diff options
548 files changed, 23270 insertions, 17792 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 5267b0294c..2e0c95a5fe 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -181,6 +181,8 @@ on late-init chmod 0666 /sys/kernel/tracing/events/clk/clk_enable/enable chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_set_rate/enable chmod 0666 /sys/kernel/tracing/events/clk/clk_set_rate/enable + chmod 0666 /sys/kernel/debug/tracing/events/printk/console/enable + chmod 0666 /sys/kernel/tracing/events/printk/console/enable # disk chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable @@ -298,6 +300,12 @@ on late-init chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger +on late-init && property:ro.boot.fastboot.boottrace=enabled + setprop debug.atrace.tags.enableflags 802922 + setprop persist.traced.enable 0 + write /sys/kernel/debug/tracing/tracing_on 1 + write /sys/kernel/tracing/tracing_on 1 + # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created # will likely fail with EBUSY as it would be in use by traced_probes. @@ -393,3 +401,10 @@ on property:persist.debug.atrace.boottrace=1 service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categories disabled oneshot + +on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled + setprop debug.atrace.tags.enableflags 0 + setprop persist.traced.enable 1 + write /sys/kernel/debug/tracing/tracing_on 0 + write /sys/kernel/tracing/tracing_on 0 + diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 6e9747f4dd..fe913411fa 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -234,6 +234,7 @@ static const char* WAKE_LOCK_NAME = "dumpstate_wakelock"; // task and the log title of the duration report. static const std::string DUMP_TRACES_TASK = "DUMP TRACES"; static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT"; +static const std::string DUMP_NETSTATS_PROTO_TASK = "DUMP NETSTATS PROTO"; static const std::string DUMP_HALS_TASK = "DUMP HALS"; static const std::string DUMP_BOARD_TASK = "dumpstate_board()"; static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS"; @@ -1041,6 +1042,26 @@ static void DumpIncidentReport() { } } +static void DumpNetstatsProto() { + const std::string path = ds.bugreport_internal_dir_ + "/tmp_netstats_proto"; + auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))); + if (fd < 0) { + MYLOGE("Could not open %s to dump netstats proto.\n", path.c_str()); + return; + } + RunCommandToFd(fd, "", {"dumpsys", "netstats", "--proto"}, + CommandOptions::WithTimeout(120).Build()); + bool empty = 0 == lseek(fd, 0, SEEK_END); + if (!empty) { + ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "netstats" + kProtoExt, + path); + } else { + unlink(path.c_str()); + } +} + static void MaybeAddSystemTraceToZip() { // This function copies into the .zip the system trace that was snapshotted // by the early call to MaybeSnapshotSystemTrace(), if any background @@ -1576,7 +1597,8 @@ static Dumpstate::RunStatus dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); // Enqueue slow functions into the thread pool, if the parallel run is enabled. - std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins; + std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins, + dump_netstats_report; if (ds.dump_pool_) { // Pool was shutdown in DumpstateDefaultAfterCritical method in order to // drop root user. Restarts it with two threads for the parallel run. @@ -1585,6 +1607,8 @@ static Dumpstate::RunStatus dumpstate() { dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1); dump_incident_report = ds.dump_pool_->enqueueTask( DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport); + dump_netstats_report = ds.dump_pool_->enqueueTask( + DUMP_NETSTATS_PROTO_TASK, &DumpNetstatsProto); dump_board = ds.dump_pool_->enqueueTaskWithFd( DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1); dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1); @@ -1783,6 +1807,13 @@ static Dumpstate::RunStatus dumpstate() { dump_frozen_cgroupfs(); if (ds.dump_pool_) { + WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_netstats_report)); + } else { + RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_NETSTATS_PROTO_TASK, + DumpNetstatsProto); + } + + if (ds.dump_pool_) { WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_incident_report)); } else { RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK, diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index faf67fd92f..b1283eb4a7 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -99,6 +99,8 @@ static constexpr const char* kXattrDefault = "user.default"; static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce"; static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de"; +static constexpr const char* kMiscMirrorCePath = "/data_mirror/misc_ce"; +static constexpr const char* kMiscMirrorDePath = "/data_mirror/misc_de"; static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M @@ -3558,16 +3560,28 @@ binder::Status InstalldNativeService::tryMountDataMirror( std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_)); if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { - return error("Failed to create CE mirror"); + return error("Failed to create CE data mirror"); } std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_)); if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { - return error("Failed to create DE mirror"); + return error("Failed to create DE data mirror"); + } + + std::string mirrorVolMiscCePath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_)); + if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + return error("Failed to create CE misc mirror"); + } + + std::string mirrorVolMiscDePath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_)); + if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + return error("Failed to create DE misc mirror"); } auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str()); auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str()); + auto miscCePath = StringPrintf("%s/misc_ce", create_data_path(uuid_).c_str()); + auto miscDePath = StringPrintf("%s/misc_de", create_data_path(uuid_).c_str()); if (access(cePath.c_str(), F_OK) != 0) { return error("Cannot access CE path: " + cePath); @@ -3575,6 +3589,12 @@ binder::Status InstalldNativeService::tryMountDataMirror( if (access(dePath.c_str(), F_OK) != 0) { return error("Cannot access DE path: " + dePath); } + if (access(miscCePath.c_str(), F_OK) != 0) { + return error("Cannot access misc CE path: " + cePath); + } + if (access(miscDePath.c_str(), F_OK) != 0) { + return error("Cannot access misc DE path: " + dePath); + } struct stat ceStat, mirrorCeStat; if (stat(cePath.c_str(), &ceStat) != 0) { @@ -3602,6 +3622,21 @@ binder::Status InstalldNativeService::tryMountDataMirror( MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) { return error("Failed to mount " + mirrorVolDePath); } + + // Mount misc CE mirror + if (TEMP_FAILURE_RETRY(mount(miscCePath.c_str(), mirrorVolMiscCePath.c_str(), NULL, + MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, + nullptr)) == -1) { + return error("Failed to mount " + mirrorVolMiscCePath); + } + + // Mount misc DE mirror + if (TEMP_FAILURE_RETRY(mount(miscDePath.c_str(), mirrorVolMiscDePath.c_str(), NULL, + MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, + nullptr)) == -1) { + return error("Failed to mount " + mirrorVolMiscDePath); + } + return ok(); } @@ -3624,6 +3659,8 @@ binder::Status InstalldNativeService::onPrivateVolumeRemoved( std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_)); std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_)); + std::string mirrorMiscCeVolPath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_)); + std::string mirrorMiscDeVolPath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_)); std::lock_guard<std::recursive_mutex> lock(mMountsLock); @@ -3648,6 +3685,29 @@ binder::Status InstalldNativeService::onPrivateVolumeRemoved( if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) { res = error("Failed to delete " + mirrorDeVolPath); } + + // Unmount misc CE storage + if (TEMP_FAILURE_RETRY(umount(mirrorMiscCeVolPath.c_str())) != 0) { + if (errno != ENOENT) { + res = error(StringPrintf("Failed to umount %s %s", mirrorMiscCeVolPath.c_str(), + strerror(errno))); + } + } + if (delete_dir_contents_and_dir(mirrorMiscCeVolPath, true) != 0) { + res = error("Failed to delete " + mirrorMiscCeVolPath); + } + + // Unmount misc DE storage + if (TEMP_FAILURE_RETRY(umount(mirrorMiscDeVolPath.c_str())) != 0) { + if (errno != ENOENT) { + res = error(StringPrintf("Failed to umount %s %s", mirrorMiscDeVolPath.c_str(), + strerror(errno))); + } + } + if (delete_dir_contents_and_dir(mirrorMiscDeVolPath, true) != 0) { + res = error("Failed to delete " + mirrorMiscDeVolPath); + } + return res; } diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 3f7c7d6a7b..44235ccdef 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -464,7 +464,6 @@ void Replayer::setPosition(SurfaceComposerClient::Transaction& t, void Replayer::setSize(SurfaceComposerClient::Transaction& t, layer_id id, const SizeChange& sc) { ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h()); - t.setSize(mLayers[id], sc.w(), sc.h()); } void Replayer::setLayer(SurfaceComposerClient::Transaction& t, diff --git a/data/etc/android.hardware.type.automotive.xml b/data/etc/android.hardware.type.automotive.xml index 113945b0c5..a9b4b0526a 100644 --- a/data/etc/android.hardware.type.automotive.xml +++ b/data/etc/android.hardware.type.automotive.xml @@ -17,6 +17,4 @@ <!-- These features determine that the device running android is a car. --> <permissions> <feature name="android.hardware.type.automotive" /> - <!-- TODO: Revert this after enabling work profiles refer b/170332519 --> - <unavailable-feature name="android.software.managed_users"/> </permissions> diff --git a/data/etc/android.software.credentials.xml b/data/etc/android.software.credentials.xml new file mode 100644 index 0000000000..234d14411c --- /dev/null +++ b/data/etc/android.software.credentials.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<permissions> + <feature name="android.software.credentials" /> +</permissions> diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml index 8fdd8d06d5..08330126c7 100644 --- a/data/etc/handheld_core_hardware.xml +++ b/data/etc/handheld_core_hardware.xml @@ -52,6 +52,7 @@ <feature name="android.software.print" /> <feature name="android.software.companion_device_setup" /> <feature name="android.software.autofill" /> + <feature name="android.software.credentials" /> <feature name="android.software.cant_save_state" /> <feature name="android.software.secure_lock_screen" /> <feature name="android.software.window_magnification" /> diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml index 59d5b10947..6af4d91418 100644 --- a/data/etc/tablet_core_hardware.xml +++ b/data/etc/tablet_core_hardware.xml @@ -52,6 +52,7 @@ <feature name="android.software.print" /> <feature name="android.software.companion_device_setup" /> <feature name="android.software.autofill" /> + <feature name="android.software.credentials" /> <feature name="android.software.cant_save_state" /> <feature name="android.software.secure_lock_screen" /> <feature name="android.software.window_magnification" /> diff --git a/include/android/input.h b/include/android/input.h index 38b27bc587..7080386df7 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -54,7 +54,14 @@ #include <stdint.h> #include <sys/types.h> #include <android/keycodes.h> + +// This file is included by modules that have host support but android/looper.h is not supported +// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled. +#ifndef __BIONIC__ +#define __REMOVED_IN(x) __attribute__((deprecated)) +#endif #include <android/looper.h> + #include <jni.h> #if !defined(__INTRODUCED_IN) @@ -833,6 +840,12 @@ enum AMotionClassification : uint32_t { * This classification type should be used to accelerate the long press behaviour. */ AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS = 2, + /** + * Classification constant: touchpad two-finger swipe. + * + * The current event stream represents the user swiping with two fingers on a touchpad. + */ + AMOTION_EVENT_CLASSIFICATION_TWO_FINGER_SWIPE = 3, }; /** diff --git a/include/android/keycodes.h b/include/android/keycodes.h index 214559d683..e5b5db2964 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -776,7 +776,59 @@ enum { AKEYCODE_THUMBS_DOWN = 287, /** Used to switch current account that is consuming content. * May be consumed by system to switch current viewer profile. */ - AKEYCODE_PROFILE_SWITCH = 288 + AKEYCODE_PROFILE_SWITCH = 288, + /** Video Application key #1. */ + AKEYCODE_VIDEO_APP_1 = 289, + /** Video Application key #2. */ + AKEYCODE_VIDEO_APP_2 = 290, + /** Video Application key #3. */ + AKEYCODE_VIDEO_APP_3 = 291, + /** Video Application key #4. */ + AKEYCODE_VIDEO_APP_4 = 292, + /** Video Application key #5. */ + AKEYCODE_VIDEO_APP_5 = 293, + /** Video Application key #6. */ + AKEYCODE_VIDEO_APP_6 = 294, + /** Video Application key #7. */ + AKEYCODE_VIDEO_APP_7 = 295, + /** Video Application key #8. */ + AKEYCODE_VIDEO_APP_8 = 296, + /** Featured Application key #1. */ + AKEYCODE_FEATURED_APP_1 = 297, + /** Featured Application key #2. */ + AKEYCODE_FEATURED_APP_2 = 298, + /** Featured Application key #3. */ + AKEYCODE_FEATURED_APP_3 = 299, + /** Featured Application key #4. */ + AKEYCODE_FEATURED_APP_4 = 300, + /** Demo Application key #1. */ + AKEYCODE_DEMO_APP_1 = 301, + /** Demo Application key #2. */ + AKEYCODE_DEMO_APP_2 = 302, + /** Demo Application key #3. */ + AKEYCODE_DEMO_APP_3 = 303, + /** Demo Application key #4. */ + AKEYCODE_DEMO_APP_4 = 304, + /** Keyboard backlight Down key. + * Adjusts the keyboard backlight brightness down. */ + AKEYCODE_KEYBOARD_BACKLIGHT_DOWN = 305, + /** Keyboard backlight Up key. + * Adjusts the keyboard backlight brightness up. */ + AKEYCODE_KEYBOARD_BACKLIGHT_UP = 306, + /** Keyboard backlight Toggle key. + * Toggles the keyboard backlight on/off. */ + AKEYCODE_KEYBOARD_BACKLIGHT_TOGGLE = 307, + /** The primary button on the barrel of a stylus. + * This is usually the button closest to the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_PRIMARY = 308, + /** The secondary button on the barrel of a stylus. + * This is usually the second button from the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_SECONDARY = 309, + /** The tertiary button on the barrel of a stylus. + * This is usually the third button from the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_TERTIARY = 310, + /** A button on the tail end of a stylus. */ + AKEYCODE_STYLUS_BUTTON_TAIL = 311, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/include/android/looper.h b/include/android/looper.h index 718f703048..4fe142a8e2 100644 --- a/include/android/looper.h +++ b/include/android/looper.h @@ -201,8 +201,11 @@ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa * Like ALooper_pollOnce(), but performs all pending callbacks until all * data has been consumed or a file descriptor is available with no callback. * This function will never return ALOOPER_POLL_CALLBACK. + * + * Removed in API 34 as ALooper_pollAll can swallow ALooper_wake calls. + * Use ALooper_pollOnce instead. */ -int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData); +int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) __REMOVED_IN(1); /** * Wakes the poll asynchronously. diff --git a/include/android/sensor.h b/include/android/sensor.h index eef69f4b32..105f9524c7 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -45,6 +45,11 @@ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ +// This file is included by modules that have host support but android/looper.h is not supported +// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled. +#ifndef __BIONIC__ +#define __REMOVED_IN(x) __attribute__((deprecated)) +#endif #include <android/looper.h> #include <stdbool.h> diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 6223ef7f82..f76e73d3cf 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -545,6 +545,8 @@ void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, * You can register for changes in the refresh rate using * \a AChoreographer_registerRefreshRateCallback. * + * See ASurfaceTransaction_clearFrameRate(). + * * \param frameRate is the intended frame rate of this surface, in frames per second. 0 is a special * value that indicates the app will accept the system's choice for the display frame rate, which is * the default behavior if this function isn't called. The frameRate param does <em>not</em> need to @@ -568,6 +570,31 @@ void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* tra __INTRODUCED_IN(31); /** + * Clears the frame rate which is set for \a surface_control. + * + * This is equivalent to calling + * ASurfaceTransaction_setFrameRateWithChangeStrategy( + * transaction, 0, compatibility, changeFrameRateStrategy). + * + * Usage of this API won't directly affect the application's frame production pipeline. However, + * because the system may change the display refresh rate, calls to this function may result in + * changes to Choreographer callback timings, and changes to the time interval at which the system + * releases buffers back to the application. + * + * See ASurfaceTransaction_setFrameRateWithChangeStrategy() + * + * You can register for changes in the refresh rate using + * \a AChoreographer_registerRefreshRateCallback. + * + * See ASurfaceTransaction_setFrameRateWithChangeStrategy(). + * + * Available since API level 34. + */ +void ASurfaceTransaction_clearFrameRate(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control) + __INTRODUCED_IN(__ANDROID_API_U__); + +/** * Indicate whether to enable backpressure for buffer submission to a given SurfaceControl. * * By default backpressure is disabled, which means submitting a buffer prior to receiving diff --git a/include/android/surface_control_jni.h b/include/android/surface_control_jni.h new file mode 100644 index 0000000000..67e3a9ff42 --- /dev/null +++ b/include/android/surface_control_jni.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +/** + * @addtogroup NativeActivity Native Activity + * @{ + */ + +/** + * @file surface_control_jni.h + */ + +#ifndef ANDROID_SURFACE_CONTROL_JNI_H +#define ANDROID_SURFACE_CONTROL_JNI_H + +#include <jni.h> +#include <sys/cdefs.h> + +#include <android/surface_control.h> + +__BEGIN_DECLS + +/** + * Return the ASurfaceControl wrapped by a Java SurfaceControl object. + * + * This method does not acquire any additional reference to the ASurfaceControl + * that is returned. To keep the ASurfaceControl alive after the Java + * SurfaceControl object is closed, explicitly or by the garbage collector, be + * sure to use ASurfaceControl_acquire() to acquire an additional reference. + * + * Available since API level 34. + */ +ASurfaceControl* _Nullable ASurfaceControl_fromSurfaceControl(JNIEnv* _Nonnull env, + jobject _Nonnull surfaceControlObj) __INTRODUCED_IN(__ANDROID_API_U__); + +/** + * Return the ASurfaceTransaction wrapped by a Java Transaction object. + * + * The returned ASurfaceTransaction is still owned by the Java Transaction object is only + * valid while the Java Transaction object is alive. In particular, the returned transaction + * must NOT be deleted with ASurfaceTransaction_delete. + * May return nullptr on error. + * + * Available since API level 34. + */ +ASurfaceTransaction* _Nullable ASurfaceTransaction_fromTransaction(JNIEnv* _Nonnull env, + jobject _Nonnull transactionObj) __INTRODUCED_IN(__ANDROID_API_U__); + +__END_DECLS + +#endif // ANDROID_SURFACE_CONTROL_JNI_H +/** @} */ diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h index 4aa2f60d45..6794fbfc34 100644 --- a/include/audiomanager/AudioManager.h +++ b/include/audiomanager/AudioManager.h @@ -38,8 +38,52 @@ typedef enum { PLAYER_STATE_PAUSED = 3, PLAYER_STATE_STOPPED = 4, PLAYER_UPDATE_DEVICE_ID = 5, + PLAYER_UPDATE_PORT_ID = 6, + PLAYER_UPDATE_MUTED = 7, } player_state_t; +static constexpr char + kExtraPlayerEventMuteKey[] = "android.media.extra.PLAYER_EVENT_MUTE"; +enum { + PLAYER_MUTE_MASTER = (1 << 0), + PLAYER_MUTE_STREAM_VOLUME = (1 << 1), + PLAYER_MUTE_STREAM_MUTED = (1 << 2), + PLAYER_MUTE_PLAYBACK_RESTRICTED = (1 << 3), + PLAYER_MUTE_CLIENT_VOLUME = (1 << 4), + PLAYER_MUTE_VOLUME_SHAPER = (1 << 5), +}; + +struct mute_state_t { + /** Flag used when the master volume is causing the mute state. */ + bool muteFromMasterMute = false; + /** Flag used when the stream volume is causing the mute state. */ + bool muteFromStreamVolume = false; + /** Flag used when the stream muted is causing the mute state. */ + bool muteFromStreamMuted = false; + /** Flag used when playback is restricted by AppOps manager with OP_PLAY_AUDIO. */ + bool muteFromPlaybackRestricted = false; + /** Flag used when audio track was muted by client volume. */ + bool muteFromClientVolume = false; + /** Flag used when volume is muted by volume shaper. */ + bool muteFromVolumeShaper = false; + + explicit operator int() const + { + int result = muteFromMasterMute * PLAYER_MUTE_MASTER; + result |= muteFromStreamVolume * PLAYER_MUTE_STREAM_VOLUME; + result |= muteFromStreamMuted * PLAYER_MUTE_STREAM_MUTED; + result |= muteFromPlaybackRestricted * PLAYER_MUTE_PLAYBACK_RESTRICTED; + result |= muteFromClientVolume * PLAYER_MUTE_CLIENT_VOLUME; + result |= muteFromVolumeShaper * PLAYER_MUTE_VOLUME_SHAPER; + return result; + } + + bool operator==(const mute_state_t& other) const + { + return static_cast<int>(*this) == static_cast<int>(other); + } +}; + // must be kept in sync with definitions in AudioManager.java #define RECORD_RIID_INVALID -1 diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h index 426e10c9bc..769670ea99 100644 --- a/include/audiomanager/IAudioManager.h +++ b/include/audiomanager/IAudioManager.h @@ -17,8 +17,10 @@ #ifndef ANDROID_IAUDIOMANAGER_H #define ANDROID_IAUDIOMANAGER_H +#include <audiomanager/AudioManager.h> #include <utils/Errors.h> #include <binder/IInterface.h> +#include <binder/PersistableBundle.h> #include <hardware/power.h> #include <system/audio.h> @@ -40,6 +42,7 @@ public: RECORDER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 5, RELEASE_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 6, PLAYER_SESSION_ID = IBinder::FIRST_CALL_TRANSACTION + 7, + PORT_EVENT = IBinder::FIRST_CALL_TRANSACTION + 8, }; DECLARE_META_INTERFACE(AudioManager) @@ -52,12 +55,14 @@ public: /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage, audio_content_type_t content)= 0; /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event, - audio_port_handle_t deviceId) = 0; + audio_port_handle_t eventId) = 0; /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0; virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0; /*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0; /*oneway*/ virtual status_t releaseRecorder(audio_unique_id_t riid) = 0; /*oneway*/ virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) = 0; + /*oneway*/ virtual status_t portEvent(audio_port_handle_t portId, player_state_t event, + const std::unique_ptr<os::PersistableBundle>& extras) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/ftl/algorithm.h b/include/ftl/algorithm.h new file mode 100644 index 0000000000..c5ff03b80d --- /dev/null +++ b/include/ftl/algorithm.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#pragma once + +#include <algorithm> +#include <functional> +#include <utility> + +#include <ftl/optional.h> + +namespace android::ftl { + +// Adapter for std::find_if that converts the return value from iterator to optional. +// +// const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv}; +// assert(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }) == "cake"sv); +// +template <typename Container, typename Predicate, typename V = typename Container::value_type> +constexpr auto find_if(const Container& container, Predicate&& predicate) + -> Optional<std::reference_wrapper<const V>> { + const auto it = std::find_if(std::cbegin(container), std::cend(container), + std::forward<Predicate>(predicate)); + if (it == std::cend(container)) return {}; + return std::cref(*it); +} + +// Transformers for ftl::find_if on a map-like `Container` that contains key-value pairs. +// +// const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>( +// 12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv); +// +// using Map = decltype(map); +// +// assert(14 == ftl::find_if(map, [](const auto& pair) { +// return pair.second.size() == 3; +// }).transform(ftl::to_key<Map>)); +// +// const auto opt = ftl::find_if(map, [](const auto& pair) { +// return pair.second.size() == 1; +// }).transform(ftl::to_mapped_ref<Map>); +// +// assert(opt); +// assert(opt->get() == ftl::StaticVector("tiramisu"sv)); +// +template <typename Map, typename Pair = typename Map::value_type, + typename Key = typename Map::key_type> +constexpr auto to_key(const Pair& pair) -> Key { + return pair.first; +} + +template <typename Map, typename Pair = typename Map::value_type, + typename Mapped = typename Map::mapped_type> +constexpr auto to_mapped_ref(const Pair& pair) -> std::reference_wrapper<const Mapped> { + return std::cref(pair.second); +} + +} // namespace android::ftl diff --git a/include/ftl/details/optional.h b/include/ftl/details/optional.h new file mode 100644 index 0000000000..bff7c1e000 --- /dev/null +++ b/include/ftl/details/optional.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#pragma once + +#include <functional> +#include <optional> + +#include <ftl/details/type_traits.h> + +namespace android::ftl { + +template <typename> +struct Optional; + +namespace details { + +template <typename> +struct is_optional : std::false_type {}; + +template <typename T> +struct is_optional<std::optional<T>> : std::true_type {}; + +template <typename T> +struct is_optional<Optional<T>> : std::true_type {}; + +template <typename F, typename T> +struct transform_result { + using type = Optional<std::remove_cv_t<std::invoke_result_t<F, T>>>; +}; + +template <typename F, typename T> +using transform_result_t = typename transform_result<F, T>::type; + +template <typename F, typename T> +struct and_then_result { + using type = remove_cvref_t<std::invoke_result_t<F, T>>; + static_assert(is_optional<type>{}, "and_then function must return an optional"); +}; + +template <typename F, typename T> +using and_then_result_t = typename and_then_result<F, T>::type; + +} // namespace details +} // namespace android::ftl diff --git a/include/ftl/details/type_traits.h b/include/ftl/details/type_traits.h new file mode 100644 index 0000000000..7092ec50fb --- /dev/null +++ b/include/ftl/details/type_traits.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#pragma once + +#include <type_traits> + +namespace android::ftl::details { + +// TODO: Replace with std::remove_cvref_t in C++20. +template <typename U> +using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>; + +} // namespace android::ftl::details diff --git a/include/ftl/optional.h b/include/ftl/optional.h new file mode 100644 index 0000000000..626507fd8f --- /dev/null +++ b/include/ftl/optional.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#pragma once + +#include <functional> +#include <optional> +#include <utility> + +#include <ftl/details/optional.h> + +namespace android::ftl { + +// Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8. +// +// TODO: Remove in C++23. +// +template <typename T> +struct Optional final : std::optional<T> { + using std::optional<T>::optional; + + // Implicit downcast. + Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {} + + using std::optional<T>::has_value; + using std::optional<T>::value; + + // Returns Optional<U> where F is a function that maps T to U. + template <typename F> + constexpr auto transform(F&& f) const& { + using R = details::transform_result_t<F, decltype(value())>; + if (has_value()) return R(std::invoke(std::forward<F>(f), value())); + return R(); + } + + template <typename F> + constexpr auto transform(F&& f) & { + using R = details::transform_result_t<F, decltype(value())>; + if (has_value()) return R(std::invoke(std::forward<F>(f), value())); + return R(); + } + + template <typename F> + constexpr auto transform(F&& f) const&& { + using R = details::transform_result_t<F, decltype(std::move(value()))>; + if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value()))); + return R(); + } + + template <typename F> + constexpr auto transform(F&& f) && { + using R = details::transform_result_t<F, decltype(std::move(value()))>; + if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value()))); + return R(); + } + + // Returns Optional<U> where F is a function that maps T to Optional<U>. + template <typename F> + constexpr auto and_then(F&& f) const& { + using R = details::and_then_result_t<F, decltype(value())>; + if (has_value()) return std::invoke(std::forward<F>(f), value()); + return R(); + } + + template <typename F> + constexpr auto and_then(F&& f) & { + using R = details::and_then_result_t<F, decltype(value())>; + if (has_value()) return std::invoke(std::forward<F>(f), value()); + return R(); + } + + template <typename F> + constexpr auto and_then(F&& f) const&& { + using R = details::and_then_result_t<F, decltype(std::move(value()))>; + if (has_value()) return std::invoke(std::forward<F>(f), std::move(value())); + return R(); + } + + template <typename F> + constexpr auto and_then(F&& f) && { + using R = details::and_then_result_t<F, decltype(std::move(value()))>; + if (has_value()) return std::invoke(std::forward<F>(f), std::move(value())); + return R(); + } +}; + +// Deduction guides. +template <typename T> +Optional(T) -> Optional<T>; + +template <typename T> +Optional(std::optional<T>) -> Optional<T>; + +} // namespace android::ftl diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h index 5217e76064..49cde7fedc 100644 --- a/include/ftl/small_map.h +++ b/include/ftl/small_map.h @@ -17,11 +17,11 @@ #pragma once #include <ftl/initializer_list.h> +#include <ftl/optional.h> #include <ftl/small_vector.h> #include <algorithm> #include <functional> -#include <optional> #include <type_traits> #include <utility> @@ -47,7 +47,7 @@ namespace android::ftl { // assert(!map.dynamic()); // // assert(map.contains(123)); -// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u); +// assert(map.get(42).transform([](const std::string& s) { return s.size(); }) == 3u); // // const auto opt = map.get(-1); // assert(opt); @@ -59,7 +59,7 @@ namespace android::ftl { // map.emplace_or_replace(0, "vanilla", 2u, 3u); // assert(map.dynamic()); // -// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); +// assert(map == SmallMap(ftl::init::map(-1, "xyz"sv)(0, "nil"sv)(42, "???"sv)(123, "abc"sv))); // template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>> class SmallMap final { @@ -123,9 +123,7 @@ class SmallMap final { const_iterator cend() const { return map_.cend(); } // Returns whether a mapping exists for the given key. - bool contains(const key_type& key) const { - return get(key, [](const mapped_type&) {}); - } + bool contains(const key_type& key) const { return get(key).has_value(); } // Returns a reference to the value for the given key, or std::nullopt if the key was not found. // @@ -139,46 +137,24 @@ class SmallMap final { // ref.get() = 'D'; // assert(d == 'D'); // - auto get(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> { - return get(key, [](const mapped_type& v) { return std::cref(v); }); - } - - auto get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> { - return get(key, [](mapped_type& v) { return std::ref(v); }); + auto get(const key_type& key) const -> Optional<std::reference_wrapper<const mapped_type>> { + for (const auto& [k, v] : *this) { + if (KeyEqual{}(k, key)) { + return std::cref(v); + } + } + return {}; } - // Returns the result R of a unary operation F on (a constant or mutable reference to) the value - // for the given key, or std::nullopt if the key was not found. If F has a return type of void, - // then the Boolean result indicates whether the key was found. - // - // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); - // - // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z'); - // assert(map.get('c', [](char& c) { c = std::toupper(c); })); - // - template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>> - auto get(const key_type& key, F f) const - -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> { + auto get(const key_type& key) -> Optional<std::reference_wrapper<mapped_type>> { for (auto& [k, v] : *this) { if (KeyEqual{}(k, key)) { - if constexpr (std::is_void_v<R>) { - f(v); - return true; - } else { - return f(v); - } + return std::ref(v); } } - return {}; } - template <typename F> - auto get(const key_type& key, F f) { - return std::as_const(*this).get( - key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); }); - } - // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise. const_iterator find(const key_type& key) const { return const_cast<SmallMap&>(*this).find(key); } iterator find(const key_type& key) { return find(key, begin()); } @@ -286,7 +262,7 @@ bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs for (const auto& [k, v] : lhs) { const auto& lv = v; - if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { + if (!rhs.get(k).transform([&lv](const W& rv) { return lv == rv; }).value_or(false)) { return false; } } diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index 339726e4ea..11294c3ac8 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -21,11 +21,12 @@ #include <algorithm> #include <iterator> -#include <type_traits> #include <utility> #include <variant> #include <vector> +#include <ftl/details/type_traits.h> + namespace android::ftl { template <typename> @@ -80,10 +81,6 @@ class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<Sma using Static = StaticVector<T, N>; using Dynamic = SmallVector<T, 0>; - // TODO: Replace with std::remove_cvref_t in C++20. - template <typename U> - using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>; - public: FTL_ARRAY_TRAIT(T, value_type); FTL_ARRAY_TRAIT(T, size_type); @@ -104,7 +101,7 @@ class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<Sma // Constructs at most N elements. See StaticVector for underlying constructors. template <typename Arg, typename... Args, - typename = std::enable_if_t<!is_small_vector<remove_cvref_t<Arg>>{}>> + typename = std::enable_if_t<!is_small_vector<details::remove_cvref_t<Arg>>{}>> SmallVector(Arg&& arg, Args&&... args) : vector_(std::in_place_type<Static>, std::forward<Arg>(arg), std::forward<Args>(args)...) {} diff --git a/include/ftl/unit.h b/include/ftl/unit.h new file mode 100644 index 0000000000..e38230b976 --- /dev/null +++ b/include/ftl/unit.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#pragma once + +#include <type_traits> +#include <utility> + +namespace android::ftl { + +// The unit type, and its only value. +constexpr struct Unit { +} unit; + +constexpr bool operator==(Unit, Unit) { + return true; +} + +constexpr bool operator!=(Unit, Unit) { + return false; +} + +// Adapts a function object F to return Unit. The return value of F is ignored. +// +// As a practical use, the function passed to ftl::Optional<T>::transform is not allowed to return +// void (cf. https://wg21.link/P0798R8#mapping-functions-returning-void), but may return Unit if +// only its side effects are meaningful: +// +// ftl::Optional opt = "food"s; +// opt.transform(ftl::unit_fn([](std::string& str) { str.pop_back(); })); +// assert(opt == "foo"s); +// +template <typename F> +struct UnitFn { + F f; + + template <typename... Args> + Unit operator()(Args&&... args) { + return f(std::forward<Args>(args)...), unit; + } +}; + +template <typename F> +constexpr auto unit_fn(F&& f) -> UnitFn<std::decay_t<F>> { + return {std::forward<F>(f)}; +} + +} // namespace android::ftl diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index 9148fee532..98a18c9560 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_DISPLAY_VIEWPORT_H -#define _LIBINPUT_DISPLAY_VIEWPORT_H +#pragma once #include <android-base/stringprintf.h> #include <ftl/enum.h> @@ -144,5 +143,3 @@ struct DisplayViewport { }; } // namespace android - -#endif // _LIBINPUT_DISPLAY_VIEWPORT_H diff --git a/include/input/Input.h b/include/input/Input.h index 7ea297049b..172e5b46d8 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_INPUT_H -#define _LIBINPUT_INPUT_H +#pragma once #pragma GCC system_header @@ -290,6 +289,10 @@ enum class MotionClassification : uint8_t { * The current gesture likely represents a user intentionally exerting force on the touchscreen. */ DEEP_PRESS = AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS, + /** + * The current gesture represents the user swiping with two fingers on a touchpad. + */ + TWO_FINGER_SWIPE = AMOTION_EVENT_CLASSIFICATION_TWO_FINGER_SWIPE, }; /** @@ -1061,6 +1064,46 @@ public: uint32_t seq; }; -} // namespace android +/* Pointer icon styles. + * Must match the definition in android.view.PointerIcon. + * + * Due to backwards compatibility and public api constraints, this is a duplicate (but type safe) + * definition of PointerIcon.java. + * + * TODO(b/235023317) move this definition to an aidl and statically assign to the below java public + * api values. + * + * WARNING: Keep these definitions in sync with + * frameworks/base/core/java/android/view/PointerIcon.java + */ +enum class PointerIconStyle : int32_t { + TYPE_CUSTOM = -1, + TYPE_NULL = 0, + TYPE_ARROW = 1000, + TYPE_CONTEXT_MENU = 1001, + TYPE_HAND = 1002, + TYPE_HELP = 1003, + TYPE_WAIT = 1004, + TYPE_CELL = 1006, + TYPE_CROSSHAIR = 1007, + TYPE_TEXT = 1008, + TYPE_VERTICAL_TEXT = 1009, + TYPE_ALIAS = 1010, + TYPE_COPY = 1011, + TYPE_NO_DROP = 1012, + TYPE_ALL_SCROLL = 1013, + TYPE_HORIZONTAL_DOUBLE_ARROW = 1014, + TYPE_VERTICAL_DOUBLE_ARROW = 1015, + TYPE_TOP_RIGHT_DOUBLE_ARROW = 1016, + TYPE_TOP_LEFT_DOUBLE_ARROW = 1017, + TYPE_ZOOM_IN = 1018, + TYPE_ZOOM_OUT = 1019, + TYPE_GRAB = 1020, + TYPE_GRABBING = 1021, + + TYPE_SPOT_HOVER = 2000, + TYPE_SPOT_TOUCH = 2001, + TYPE_SPOT_ANCHOR = 2002, +}; -#endif // _LIBINPUT_INPUT_H +} // namespace android diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 3585392c2b..0026e82caa 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -14,15 +14,17 @@ * limitations under the License. */ -#ifndef _LIBINPUT_INPUT_DEVICE_H -#define _LIBINPUT_INPUT_DEVICE_H +#pragma once #include <android/sensor.h> +#include <ftl/flags.h> #include <input/Input.h> #include <input/KeyCharacterMap.h> #include <unordered_map> #include <vector> +#include "android/hardware/input/InputDeviceCountryCode.h" + namespace android { /* @@ -104,12 +106,18 @@ enum class InputDeviceSensorReportingMode : int32_t { }; enum class InputDeviceLightType : int32_t { - MONO = 0, + INPUT = 0, PLAYER_ID = 1, - RGB = 2, - MULTI_COLOR = 3, + KEYBOARD_BACKLIGHT = 2, + + ftl_last = KEYBOARD_BACKLIGHT +}; - ftl_last = MULTI_COLOR +enum class InputDeviceLightCapability : uint32_t { + /** Capability to change brightness of the light */ + BRIGHTNESS = 0x00000001, + /** Capability to change color of the light */ + RGB = 0x00000002, }; struct InputDeviceSensorInfo { @@ -170,14 +178,17 @@ struct InputDeviceSensorInfo { struct InputDeviceLightInfo { explicit InputDeviceLightInfo(std::string name, int32_t id, InputDeviceLightType type, + ftl::Flags<InputDeviceLightCapability> capabilityFlags, int32_t ordinal) - : name(name), id(id), type(type), ordinal(ordinal) {} + : name(name), id(id), type(type), capabilityFlags(capabilityFlags), ordinal(ordinal) {} // Name string of the light. std::string name; // Light id int32_t id; // Type of the light. InputDeviceLightType type; + // Light capabilities. + ftl::Flags<InputDeviceLightCapability> capabilityFlags; // Ordinal of the light int32_t ordinal; }; @@ -210,8 +221,10 @@ public: }; void initialize(int32_t id, int32_t generation, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal, - bool hasMic); + const InputDeviceIdentifier& identifier, const std::string& alias, + bool isExternal, bool hasMic, + hardware::input::InputDeviceCountryCode countryCode = + hardware::input::InputDeviceCountryCode::INVALID); inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } @@ -223,6 +236,7 @@ public: } inline bool isExternal() const { return mIsExternal; } inline bool hasMic() const { return mHasMic; } + inline hardware::input::InputDeviceCountryCode getCountryCode() const { return mCountryCode; } inline uint32_t getSources() const { return mSources; } const MotionRange* getMotionRange(int32_t axis, uint32_t source) const; @@ -274,9 +288,11 @@ private: std::string mAlias; bool mIsExternal; bool mHasMic; + hardware::input::InputDeviceCountryCode mCountryCode; uint32_t mSources; int32_t mKeyboardType; std::shared_ptr<KeyCharacterMap> mKeyCharacterMap; + bool mHasVibrator; bool mHasBattery; bool mHasButtonUnderPad; @@ -334,5 +350,3 @@ enum ReservedInputDeviceId : int32_t { }; } // namespace android - -#endif // _LIBINPUT_INPUT_DEVICE_H diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index 2a742f9cf4..b4374acdcc 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_INPUT_EVENT_LABELS_H -#define _LIBINPUT_INPUT_EVENT_LABELS_H +#pragma once #include <input/Input.h> #include <android/keycodes.h> @@ -68,4 +67,3 @@ private: }; } // namespace android -#endif // _LIBINPUT_INPUT_EVENT_LABELS_H diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 5f9a37d69c..1c52792cf6 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_INPUT_TRANSPORT_H -#define _LIBINPUT_INPUT_TRANSPORT_H +#pragma once #pragma GCC system_header @@ -452,8 +451,11 @@ private: */ class InputConsumer { public: - /* Creates a consumer associated with an input channel. */ + /* Create a consumer associated with an input channel. */ explicit InputConsumer(const std::shared_ptr<InputChannel>& channel); + /* Create a consumer associated with an input channel, override resampling system property */ + explicit InputConsumer(const std::shared_ptr<InputChannel>& channel, + bool enableTouchResampling); /* Destroys the consumer and releases its input channel. */ ~InputConsumer(); @@ -671,5 +673,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_INPUT_TRANSPORT_H diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index f6f8939b7a..dc928b806f 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef _LIBINPUT_KEY_CHARACTER_MAP_H -#define _LIBINPUT_KEY_CHARACTER_MAP_H +#pragma once #include <stdint.h> +#include <list> #ifdef __linux__ #include <binder/IBinder.h> @@ -152,29 +152,22 @@ public: private: struct Behavior { - Behavior(); - Behavior(const Behavior& other); - - /* The next behavior in the list, or NULL if none. */ - Behavior* next; - /* The meta key modifiers for this behavior. */ - int32_t metaState; + int32_t metaState = 0; /* The character to insert. */ - char16_t character; + char16_t character = 0; /* The fallback keycode if the key is not handled. */ - int32_t fallbackKeyCode; + int32_t fallbackKeyCode = 0; /* The replacement keycode if the key has to be replaced outright. */ - int32_t replacementKeyCode; + int32_t replacementKeyCode = 0; }; struct Key { Key(); Key(const Key& other); - ~Key(); /* The single character label printed on the key, or 0 if none. */ char16_t label; @@ -184,7 +177,7 @@ private: /* The list of key behaviors sorted from most specific to least specific * meta key binding. */ - Behavior* firstBehavior; + std::list<Behavior> behaviors; }; class Parser { @@ -240,8 +233,7 @@ private: KeyCharacterMap(const std::string& filename); bool getKey(int32_t keyCode, const Key** outKey) const; - bool getKeyBehavior(int32_t keyCode, int32_t metaState, - const Key** outKey, const Behavior** outBehavior) const; + const Behavior* getKeyBehavior(int32_t keyCode, int32_t metaState) const; static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState); bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; @@ -277,5 +269,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_KEY_CHARACTER_MAP_H diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h index 1da78aa0c1..e203d190a6 100644 --- a/include/input/KeyLayoutMap.h +++ b/include/input/KeyLayoutMap.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_KEY_LAYOUT_MAP_H -#define _LIBINPUT_KEY_LAYOUT_MAP_H +#pragma once #include <android-base/result.h> #include <stdint.h> @@ -78,7 +77,7 @@ public: std::optional<AxisInfo> mapAxis(int32_t scanCode) const; const std::string getLoadFileName() const; // Return pair of sensor type and sensor data index, for the input device abs code - base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode); + base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode) const; virtual ~KeyLayoutMap(); @@ -131,5 +130,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_KEY_LAYOUT_MAP_H diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h index 9a3e15f1cd..f7f960f8e6 100644 --- a/include/input/Keyboard.h +++ b/include/input/Keyboard.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_KEYBOARD_H -#define _LIBINPUT_KEYBOARD_H +#pragma once #include <input/Input.h> #include <input/InputDevice.h> @@ -88,5 +87,3 @@ extern int32_t normalizeMetaState(int32_t oldMetaState); extern bool isMetaKey(int32_t keyCode); } // namespace android - -#endif // _LIBINPUT_KEYBOARD_H diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h index 451918bb46..28e4816afe 100644 --- a/include/input/PropertyMap.h +++ b/include/input/PropertyMap.h @@ -14,14 +14,11 @@ * limitations under the License. */ -#ifndef _UTILS_PROPERTY_MAP_H -#define _UTILS_PROPERTY_MAP_H +#pragma once #include <android-base/result.h> -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include <utils/String8.h> #include <utils/Tokenizer.h> +#include <unordered_map> namespace android { @@ -58,30 +55,27 @@ public: /* Adds a property. * Replaces the property with the same key if it is already present. */ - void addProperty(const String8& key, const String8& value); - - /* Returns true if the property map contains the specified key. */ - bool hasProperty(const String8& key) const; + void addProperty(const std::string& key, const std::string& value); /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. (Also logs a warning.) */ - bool tryGetProperty(const String8& key, String8& outValue) const; - bool tryGetProperty(const String8& key, bool& outValue) const; - bool tryGetProperty(const String8& key, int32_t& outValue) const; - bool tryGetProperty(const String8& key, float& outValue) const; + bool tryGetProperty(const std::string& key, std::string& outValue) const; + bool tryGetProperty(const std::string& key, bool& outValue) const; + bool tryGetProperty(const std::string& key, int32_t& outValue) const; + bool tryGetProperty(const std::string& key, float& outValue) const; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); - /* Gets the underlying property map. */ - inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; } - /* Loads a property map from a file. */ static android::base::Result<std::unique_ptr<PropertyMap>> load(const char* filename); private: + /* Returns true if the property map contains the specified key. */ + bool hasProperty(const std::string& key) const; + class Parser { PropertyMap* mMap; Tokenizer* mTokenizer; @@ -95,13 +89,11 @@ private: status_t parseType(); status_t parseKey(); status_t parseKeyProperty(); - status_t parseModifier(const String8& token, int32_t* outMetaState); + status_t parseModifier(const std::string& token, int32_t* outMetaState); status_t parseCharacterLiteral(char16_t* outCharacter); }; - KeyedVector<String8, String8> mProperties; + std::unordered_map<std::string, std::string> mProperties; }; } // namespace android - -#endif // _UTILS_PROPERTY_MAP_H diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h index eda628e233..a616a95ab1 100644 --- a/include/input/TouchVideoFrame.h +++ b/include/input/TouchVideoFrame.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_TOUCHVIDEOFRAME_H -#define _LIBINPUT_TOUCHVIDEOFRAME_H +#pragma once #include <stdint.h> #include <sys/time.h> @@ -75,5 +74,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_TOUCHVIDEOFRAME_H diff --git a/include/input/VelocityControl.h b/include/input/VelocityControl.h index 1acc2aef70..f72a1bdded 100644 --- a/include/input/VelocityControl.h +++ b/include/input/VelocityControl.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_VELOCITY_CONTROL_H -#define _LIBINPUT_VELOCITY_CONTROL_H +#pragma once #include <input/Input.h> #include <input/VelocityTracker.h> @@ -98,10 +97,8 @@ private: VelocityControlParameters mParameters; nsecs_t mLastMovementTime; - VelocityTracker::Position mRawPosition; + float mRawPositionX, mRawPositionY; VelocityTracker mVelocityTracker; }; } // namespace android - -#endif // _LIBINPUT_VELOCITY_CONTROL_H diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 886f1f7753..294879ed21 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef _LIBINPUT_VELOCITY_TRACKER_H -#define _LIBINPUT_VELOCITY_TRACKER_H +#pragma once #include <input/Input.h> #include <utils/BitSet.h> #include <utils/Timers.h> +#include <map> +#include <set> namespace android { @@ -46,18 +47,14 @@ public: MAX = LEGACY, }; - struct Position { - float x, y; - }; - struct Estimator { static const size_t MAX_DEGREE = 4; // Estimator time base. nsecs_t time; - // Polynomial coefficients describing motion in X and Y. - float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; + // Polynomial coefficients describing motion. + float coeff[MAX_DEGREE + 1]; // Polynomial degree (number of coefficients), or zero if no information is // available. @@ -71,14 +68,40 @@ public: degree = 0; confidence = 0; for (size_t i = 0; i <= MAX_DEGREE; i++) { - xCoeff[i] = 0; - yCoeff[i] = 0; + coeff[i] = 0; + } + } + }; + + /* + * Contains all available velocity data from a VelocityTracker. + */ + struct ComputedVelocity { + inline std::optional<float> getVelocity(int32_t axis, uint32_t id) const { + const auto& axisVelocities = mVelocities.find(axis); + if (axisVelocities == mVelocities.end()) { + return {}; } + + const auto& axisIdVelocity = axisVelocities->second.find(id); + if (axisIdVelocity == axisVelocities->second.end()) { + return {}; + } + + return axisIdVelocity->second; + } + + inline void addVelocity(int32_t axis, uint32_t id, float velocity) { + mVelocities[axis][id] = velocity; } + + private: + std::map<int32_t /*axis*/, std::map<int32_t /*pointerId*/, float /*velocity*/>> mVelocities; }; - // Creates a velocity tracker using the specified strategy. + // Creates a velocity tracker using the specified strategy for each supported axis. // If strategy is not provided, uses the default strategy for the platform. + // TODO(b/32830165): support axis-specific strategies. VelocityTracker(const Strategy strategy = Strategy::DEFAULT); ~VelocityTracker(); @@ -92,47 +115,57 @@ public: void clearPointers(BitSet32 idBits); // Adds movement information for a set of pointers. - // The idBits bitfield specifies the pointer ids of the pointers whose positions + // The idBits bitfield specifies the pointer ids of the pointers whose data points // are included in the movement. - // The positions array contains position information for each pointer in order by - // increasing id. Its size should be equal to the number of one bits in idBits. - void addMovement(nsecs_t eventTime, BitSet32 idBits, const std::vector<Position>& positions); + // The positions map contains a mapping of an axis to positions array. + // The positions arrays contain information for each pointer in order by increasing id. + // Each array's size should be equal to the number of one bits in idBits. + void addMovement(nsecs_t eventTime, BitSet32 idBits, + const std::map<int32_t, std::vector<float>>& positions); // Adds movement information for all pointers in a MotionEvent, including historical samples. void addMovement(const MotionEvent* event); - // Gets the velocity of the specified pointer id in position units per second. - // Returns false and sets the velocity components to zero if there is - // insufficient movement information for the pointer. - bool getVelocity(uint32_t id, float* outVx, float* outVy) const; + // Returns the velocity of the specified pointer id and axis in position units per second. + // Returns empty optional if there is insufficient movement information for the pointer, or if + // the given axis is not supported for velocity tracking. + std::optional<float> getVelocity(int32_t axis, uint32_t id) const; + + // Returns a ComputedVelocity instance with all available velocity data, using the given units + // (reference: units == 1 means "per millisecond"), and clamping each velocity between + // [-maxVelocity, maxVelocity], inclusive. + ComputedVelocity getComputedVelocity(int32_t units, float maxVelocity); - // Gets an estimator for the recent movements of the specified pointer id. + // Gets an estimator for the recent movements of the specified pointer id for the given axis. // Returns false and clears the estimator if there is no information available // about the pointer. - bool getEstimator(uint32_t id, Estimator* outEstimator) const; + bool getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const; // Gets the active pointer id, or -1 if none. inline int32_t getActivePointerId() const { return mActivePointerId; } - // Gets a bitset containing all pointer ids from the most recent movement. - inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; } - private: - // The default velocity tracker strategy. - // Although other strategies are available for testing and comparison purposes, - // this is the strategy that applications will actually use. Be very careful - // when adjusting the default strategy because it can dramatically affect - // (often in a bad way) the user experience. - static const Strategy DEFAULT_STRATEGY = Strategy::LSQ2; - nsecs_t mLastEventTime; BitSet32 mCurrentPointerIdBits; int32_t mActivePointerId; - std::unique_ptr<VelocityTrackerStrategy> mStrategy; - - bool configureStrategy(const Strategy strategy); - static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy); + // An override strategy passed in the constructor to be used for all axes. + // This strategy will apply to all axes, unless the default strategy is specified here. + // When default strategy is specified, then each axis will use a potentially different strategy + // based on a hardcoded mapping. + const Strategy mOverrideStrategy; + // Maps axes to their respective VelocityTrackerStrategy instances. + // Note that, only axes that have had MotionEvents (and not all supported axes) will be here. + std::map<int32_t /*axis*/, std::unique_ptr<VelocityTrackerStrategy>> mConfiguredStrategies; + + void configureStrategy(int32_t axis); + + // Generates a VelocityTrackerStrategy instance for the given Strategy type. + // The `deltaValues` parameter indicates whether or not the created strategy should treat motion + // values as deltas (and not as absolute values). This the parameter is applicable only for + // strategies that support differential axes. + static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy, + bool deltaValues); }; @@ -146,10 +179,9 @@ protected: public: virtual ~VelocityTrackerStrategy() { } - virtual void clear() = 0; virtual void clearPointers(BitSet32 idBits) = 0; virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) = 0; + const std::vector<float>& positions) = 0; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; }; @@ -178,10 +210,9 @@ public: LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); virtual ~LeastSquaresVelocityTrackerStrategy(); - virtual void clear(); virtual void clearPointers(BitSet32 idBits); void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; + const std::vector<float>& positions) override; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: @@ -196,11 +227,9 @@ private: struct Movement { nsecs_t eventTime; BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; + float positions[MAX_POINTERS]; - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; } }; float chooseWeight(uint32_t index) const; @@ -221,10 +250,9 @@ public: IntegratingVelocityTrackerStrategy(uint32_t degree); ~IntegratingVelocityTrackerStrategy(); - virtual void clear(); virtual void clearPointers(BitSet32 idBits); void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; + const std::vector<float>& positions) override; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: @@ -233,16 +261,15 @@ private: nsecs_t updateTime; uint32_t degree; - float xpos, xvel, xaccel; - float ypos, yvel, yaccel; + float pos, vel, accel; }; const uint32_t mDegree; BitSet32 mPointerIdBits; State mPointerState[MAX_POINTER_ID + 1]; - void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; - void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; + void initState(State& state, nsecs_t eventTime, float pos) const; + void updateState(State& state, nsecs_t eventTime, float pos) const; void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; }; @@ -255,10 +282,9 @@ public: LegacyVelocityTrackerStrategy(); virtual ~LegacyVelocityTrackerStrategy(); - virtual void clear(); virtual void clearPointers(BitSet32 idBits); void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; + const std::vector<float>& positions) override; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: @@ -274,11 +300,9 @@ private: struct Movement { nsecs_t eventTime; BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; + float positions[MAX_POINTERS]; - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; } }; uint32_t mIndex; @@ -287,13 +311,12 @@ private: class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { public: - ImpulseVelocityTrackerStrategy(); + ImpulseVelocityTrackerStrategy(bool deltaValues); virtual ~ImpulseVelocityTrackerStrategy(); - virtual void clear(); virtual void clearPointers(BitSet32 idBits); void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; + const std::vector<float>& positions) override; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: @@ -308,17 +331,18 @@ private: struct Movement { nsecs_t eventTime; BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; + float positions[MAX_POINTERS]; - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; } }; + // Whether or not the input movement values for the strategy come in the form of delta values. + // If the input values are not deltas, the strategy needs to calculate deltas as part of its + // velocity calculation. + const bool mDeltaValues; + size_t mIndex; Movement mMovements[HISTORY_SIZE]; }; } // namespace android - -#endif // _LIBINPUT_VELOCITY_TRACKER_H diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h index 6e8e2c9cf4..a4381eaab9 100644 --- a/include/input/VirtualKeyMap.h +++ b/include/input/VirtualKeyMap.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_VIRTUAL_KEY_MAP_H -#define _LIBINPUT_VIRTUAL_KEY_MAP_H +#pragma once #include <stdint.h> @@ -77,5 +76,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_KEY_CHARACTER_MAP_H diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h index b36728e934..d52861add0 100644 --- a/libs/arect/include/android/rect.h +++ b/libs/arect/include/android/rect.h @@ -57,7 +57,7 @@ typedef struct ARect { } ARect; #ifdef __cplusplus -}; +} #endif #endif // ANDROID_RECT_H diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index df965ab65f..c4bb6d0bf3 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -321,10 +321,6 @@ cc_library { }, afdo: true, - - header_abi_checker: { - diff_flags: ["-allow-adding-removing-weak-symbols"], - }, } cc_library_static { @@ -463,9 +459,7 @@ aidl_interface { local_include_dir: "aidl", host_supported: true, srcs: [ - "aidl/android/content/pm/IPackageChangeObserver.aidl", "aidl/android/content/pm/IPackageManagerNative.aidl", - "aidl/android/content/pm/PackageChangeEvent.aidl", "aidl/android/content/pm/IStagedApexObserver.aidl", "aidl/android/content/pm/ApexStagedEvent.aidl", "aidl/android/content/pm/StagedApexInfo.aidl", diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 7c99f76ec6..f8a8843309 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -17,7 +17,6 @@ package android.content.pm; -import android.content.pm.IPackageChangeObserver; import android.content.pm.IStagedApexObserver; import android.content.pm.StagedApexInfo; @@ -92,18 +91,6 @@ interface IPackageManagerNative { */ @utf8InCpp String getModuleMetadataPackageName(); - /* Returns the names of all packages. */ - @utf8InCpp String[] getAllPackages(); - - /** Register an extra package change observer to receive the multi-cast. */ - void registerPackageChangeObserver(in IPackageChangeObserver observer); - - /** - * Unregister an existing package change observer. - * This does nothing if this observer was not already registered. - */ - void unregisterPackageChangeObserver(in IPackageChangeObserver observer); - /** * Returns true if the package has the SHA 256 version of the signing certificate. * @see PackageManager#hasSigningCertificate(String, byte[], int), where type diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 9f7e2c87b8..dc572ac953 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -219,80 +219,79 @@ inline IBinder* BpInterface<INTERFACE>::onAsBinder() namespace internal { constexpr const char* const kManualInterfaces[] = { - "android.app.IActivityManager", - "android.app.IUidObserver", - "android.drm.IDrm", - "android.dvr.IVsyncCallback", - "android.dvr.IVsyncService", - "android.gfx.tests.ICallback", - "android.gfx.tests.IIPCTest", - "android.gfx.tests.ISafeInterfaceTest", - "android.graphicsenv.IGpuService", - "android.gui.IConsumerListener", - "android.gui.IGraphicBufferConsumer", - "android.gui.ITransactionComposerListener", - "android.gui.SensorEventConnection", - "android.gui.SensorServer", - "android.hardware.ICamera", - "android.hardware.ICameraClient", - "android.hardware.ICameraRecordingProxy", - "android.hardware.ICameraRecordingProxyListener", - "android.hardware.ICrypto", - "android.hardware.IOMXObserver", - "android.hardware.IStreamListener", - "android.hardware.IStreamSource", - "android.media.IAudioService", - "android.media.IDataSource", - "android.media.IDrmClient", - "android.media.IMediaCodecList", - "android.media.IMediaDrmService", - "android.media.IMediaExtractor", - "android.media.IMediaExtractorService", - "android.media.IMediaHTTPConnection", - "android.media.IMediaHTTPService", - "android.media.IMediaLogService", - "android.media.IMediaMetadataRetriever", - "android.media.IMediaMetricsService", - "android.media.IMediaPlayer", - "android.media.IMediaPlayerClient", - "android.media.IMediaPlayerService", - "android.media.IMediaRecorder", - "android.media.IMediaRecorderClient", - "android.media.IMediaResourceMonitor", - "android.media.IMediaSource", - "android.media.IRemoteDisplay", - "android.media.IRemoteDisplayClient", - "android.media.IResourceManagerClient", - "android.media.IResourceManagerService", - "android.os.IComplexTypeInterface", - "android.os.IPermissionController", - "android.os.IPingResponder", - "android.os.IProcessInfoService", - "android.os.ISchedulingPolicyService", - "android.os.IStringConstants", - "android.os.storage.IObbActionListener", - "android.os.storage.IStorageEventListener", - "android.os.storage.IStorageManager", - "android.os.storage.IStorageShutdownObserver", - "android.service.vr.IPersistentVrStateCallbacks", - "android.service.vr.IVrManager", - "android.service.vr.IVrStateCallbacks", - "android.ui.ISurfaceComposer", - "android.ui.ISurfaceComposerClient", - "android.utils.IMemory", - "android.utils.IMemoryHeap", - "com.android.car.procfsinspector.IProcfsInspector", - "com.android.internal.app.IAppOpsCallback", - "com.android.internal.app.IAppOpsService", - "com.android.internal.app.IBatteryStats", - "com.android.internal.os.IResultReceiver", - "com.android.internal.os.IShellCallback", - "drm.IDrmManagerService", - "drm.IDrmServiceListener", - "IAAudioClient", - "IAAudioService", - "VtsFuzzer", - nullptr, + "android.app.IActivityManager", + "android.app.IUidObserver", + "android.drm.IDrm", + "android.dvr.IVsyncCallback", + "android.dvr.IVsyncService", + "android.gfx.tests.ICallback", + "android.gfx.tests.IIPCTest", + "android.gfx.tests.ISafeInterfaceTest", + "android.graphicsenv.IGpuService", + "android.gui.IConsumerListener", + "android.gui.IGraphicBufferConsumer", + "android.gui.ITransactionComposerListener", + "android.gui.SensorEventConnection", + "android.gui.SensorServer", + "android.hardware.ICamera", + "android.hardware.ICameraClient", + "android.hardware.ICameraRecordingProxy", + "android.hardware.ICameraRecordingProxyListener", + "android.hardware.ICrypto", + "android.hardware.IOMXObserver", + "android.hardware.IStreamListener", + "android.hardware.IStreamSource", + "android.media.IAudioService", + "android.media.IDataSource", + "android.media.IDrmClient", + "android.media.IMediaCodecList", + "android.media.IMediaDrmService", + "android.media.IMediaExtractor", + "android.media.IMediaExtractorService", + "android.media.IMediaHTTPConnection", + "android.media.IMediaHTTPService", + "android.media.IMediaLogService", + "android.media.IMediaMetadataRetriever", + "android.media.IMediaMetricsService", + "android.media.IMediaPlayer", + "android.media.IMediaPlayerClient", + "android.media.IMediaPlayerService", + "android.media.IMediaRecorder", + "android.media.IMediaRecorderClient", + "android.media.IMediaResourceMonitor", + "android.media.IMediaSource", + "android.media.IRemoteDisplay", + "android.media.IRemoteDisplayClient", + "android.media.IResourceManagerClient", + "android.media.IResourceManagerService", + "android.os.IComplexTypeInterface", + "android.os.IPermissionController", + "android.os.IPingResponder", + "android.os.IProcessInfoService", + "android.os.ISchedulingPolicyService", + "android.os.IStringConstants", + "android.os.storage.IObbActionListener", + "android.os.storage.IStorageEventListener", + "android.os.storage.IStorageManager", + "android.os.storage.IStorageShutdownObserver", + "android.service.vr.IPersistentVrStateCallbacks", + "android.service.vr.IVrManager", + "android.service.vr.IVrStateCallbacks", + "android.ui.ISurfaceComposer", + "android.utils.IMemory", + "android.utils.IMemoryHeap", + "com.android.car.procfsinspector.IProcfsInspector", + "com.android.internal.app.IAppOpsCallback", + "com.android.internal.app.IAppOpsService", + "com.android.internal.app.IBatteryStats", + "com.android.internal.os.IResultReceiver", + "com.android.internal.os.IShellCallback", + "drm.IDrmManagerService", + "drm.IDrmServiceListener", + "IAAudioClient", + "IAAudioService", + "VtsFuzzer", + nullptr, }; constexpr const char* const kDownstreamManualInterfaces[] = { diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp index c5d3a3207c..5f145a149d 100644 --- a/libs/bufferqueueconverter/Android.bp +++ b/libs/bufferqueueconverter/Android.bp @@ -22,6 +22,7 @@ cc_library_shared { double_loadable: true, srcs: [ + ":libgui_frame_event_aidl", "BufferQueueConverter.cpp", ], diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index c010a2e58a..a25a49397e 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,12 +14,14 @@ cc_test { address: true, }, srcs: [ + "algorithm_test.cpp", "cast_test.cpp", "concat_test.cpp", "enum_test.cpp", "fake_guard_test.cpp", "flags_test.cpp", "future_test.cpp", + "optional_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", diff --git a/libs/ftl/algorithm_test.cpp b/libs/ftl/algorithm_test.cpp new file mode 100644 index 0000000000..8052caf642 --- /dev/null +++ b/libs/ftl/algorithm_test.cpp @@ -0,0 +1,50 @@ +/* + * 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 <ftl/algorithm.h> +#include <ftl/small_map.h> +#include <ftl/static_vector.h> +#include <gtest/gtest.h> + +#include <string_view> + +namespace android::test { + +// Keep in sync with example usage in header file. +TEST(Algorithm, FindIf) { + using namespace std::string_view_literals; + + const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv}; + EXPECT_EQ(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }), "cake"sv); + + const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>( + 12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv); + + using Map = decltype(map); + + EXPECT_EQ(14, ftl::find_if(map, [](const auto& pair) { + return pair.second.size() == 3; + }).transform(ftl::to_key<Map>)); + + const auto opt = ftl::find_if(map, [](const auto& pair) { + return pair.second.size() == 1; + }).transform(ftl::to_mapped_ref<Map>); + + ASSERT_TRUE(opt); + EXPECT_EQ(opt->get(), ftl::StaticVector("tiramisu"sv)); +} + +} // namespace android::test diff --git a/libs/ftl/optional_test.cpp b/libs/ftl/optional_test.cpp new file mode 100644 index 0000000000..f7410c2aa9 --- /dev/null +++ b/libs/ftl/optional_test.cpp @@ -0,0 +1,167 @@ +/* + * 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 <ftl/optional.h> +#include <ftl/static_vector.h> +#include <ftl/string.h> +#include <ftl/unit.h> +#include <gtest/gtest.h> + +#include <cstdlib> +#include <functional> +#include <numeric> +#include <utility> + +using namespace std::placeholders; +using namespace std::string_literals; + +namespace android::test { + +using ftl::Optional; +using ftl::StaticVector; + +TEST(Optional, Construct) { + // Empty. + EXPECT_EQ(std::nullopt, Optional<int>()); + EXPECT_EQ(std::nullopt, Optional<std::string>(std::nullopt)); + + // Value. + EXPECT_EQ('?', Optional('?')); + EXPECT_EQ(""s, Optional(std::string())); + + // In place. + EXPECT_EQ("???"s, Optional<std::string>(std::in_place, 3u, '?')); + EXPECT_EQ("abc"s, Optional<std::string>(std::in_place, {'a', 'b', 'c'})); + + // Implicit downcast. + { + Optional opt = std::optional("test"s); + static_assert(std::is_same_v<decltype(opt), Optional<std::string>>); + + ASSERT_TRUE(opt); + EXPECT_EQ(opt.value(), "test"s); + } +} + +TEST(Optional, Transform) { + // Empty. + EXPECT_EQ(std::nullopt, Optional<int>().transform([](int) { return 0; })); + + // By value. + EXPECT_EQ(0, Optional(0).transform([](int x) { return x; })); + EXPECT_EQ(100, Optional(99).transform([](int x) { return x + 1; })); + EXPECT_EQ("0b100"s, Optional(4).transform(std::bind(ftl::to_string<int>, _1, ftl::Radix::kBin))); + + // By reference. + { + Optional opt = 'x'; + EXPECT_EQ('z', opt.transform([](char& c) { + c = 'y'; + return 'z'; + })); + + EXPECT_EQ('y', opt); + } + + // By rvalue reference. + { + std::string out; + EXPECT_EQ("xyz"s, Optional("abc"s).transform([&out](std::string&& str) { + out = std::move(str); + return "xyz"s; + })); + + EXPECT_EQ(out, "abc"s); + } + + // No return value. + { + Optional opt = "food"s; + EXPECT_EQ(ftl::unit, opt.transform(ftl::unit_fn([](std::string& str) { str.pop_back(); }))); + EXPECT_EQ(opt, "foo"s); + } + + // Chaining. + EXPECT_EQ(14u, Optional(StaticVector{"upside"s, "down"s}) + .transform([](StaticVector<std::string, 3>&& v) { + v.push_back("cake"s); + return v; + }) + .transform([](const StaticVector<std::string, 3>& v) { + return std::accumulate(v.begin(), v.end(), std::string()); + }) + .transform([](const std::string& s) { return s.length(); })); +} + +namespace { + +Optional<int> parse_int(const std::string& str) { + if (const int i = std::atoi(str.c_str())) return i; + return std::nullopt; +} + +} // namespace + +TEST(Optional, AndThen) { + // Empty. + EXPECT_EQ(std::nullopt, Optional<int>().and_then([](int) -> Optional<int> { return 0; })); + EXPECT_EQ(std::nullopt, Optional<int>().and_then([](int) { return Optional<int>(); })); + + // By value. + EXPECT_EQ(0, Optional(0).and_then([](int x) { return Optional(x); })); + EXPECT_EQ(123, Optional("123").and_then(parse_int)); + EXPECT_EQ(std::nullopt, Optional("abc").and_then(parse_int)); + + // By reference. + { + Optional opt = 'x'; + EXPECT_EQ('z', opt.and_then([](char& c) { + c = 'y'; + return Optional('z'); + })); + + EXPECT_EQ('y', opt); + } + + // By rvalue reference. + { + std::string out; + EXPECT_EQ("xyz"s, Optional("abc"s).and_then([&out](std::string&& str) { + out = std::move(str); + return Optional("xyz"s); + })); + + EXPECT_EQ(out, "abc"s); + } + + // Chaining. + using StringVector = StaticVector<std::string, 3>; + EXPECT_EQ(14u, Optional(StaticVector{"-"s, "1"s}) + .and_then([](StringVector&& v) -> Optional<StringVector> { + if (v.push_back("4"s)) return v; + return {}; + }) + .and_then([](const StringVector& v) -> Optional<std::string> { + if (v.full()) return std::accumulate(v.begin(), v.end(), std::string()); + return {}; + }) + .and_then(parse_int) + .and_then([](int i) { + return i > 0 ? std::nullopt : std::make_optional(static_cast<unsigned>(-i)); + })); +} + +} // namespace android::test diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp index 1740a2b54c..634877f672 100644 --- a/libs/ftl/small_map_test.cpp +++ b/libs/ftl/small_map_test.cpp @@ -15,12 +15,15 @@ */ #include <ftl/small_map.h> +#include <ftl/unit.h> #include <gtest/gtest.h> #include <cctype> #include <string> +#include <string_view> using namespace std::string_literals; +using namespace std::string_view_literals; namespace android::test { @@ -38,7 +41,7 @@ TEST(SmallMap, Example) { EXPECT_TRUE(map.contains(123)); - EXPECT_EQ(map.get(42, [](const std::string& s) { return s.size(); }), 3u); + EXPECT_EQ(map.get(42).transform([](const std::string& s) { return s.size(); }), 3u); const auto opt = map.get(-1); ASSERT_TRUE(opt); @@ -50,7 +53,7 @@ TEST(SmallMap, Example) { map.emplace_or_replace(0, "vanilla", 2u, 3u); EXPECT_TRUE(map.dynamic()); - EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); + EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz"sv)(0, "nil"sv)(42, "???"sv)(123, "abc"sv))); } TEST(SmallMap, Construct) { @@ -70,7 +73,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 5u); EXPECT_FALSE(map.dynamic()); - EXPECT_EQ(map, SmallMap(ftl::init::map(123, "abc")(456, "def")(789, "ghi"))); + EXPECT_EQ(map, SmallMap(ftl::init::map(123, "abc"sv)(456, "def"sv)(789, "ghi"sv))); } { // In-place constructor with different types. @@ -81,7 +84,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 5u); EXPECT_FALSE(map.dynamic()); - EXPECT_EQ(map, SmallMap(ftl::init::map(42, "???")(123, "abc")(-1, "\0\0\0"))); + EXPECT_EQ(map, SmallMap(ftl::init::map(42, "???"sv)(123, "abc"sv)(-1, ""sv))); } { // In-place constructor with implicit size. @@ -92,7 +95,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 3u); EXPECT_FALSE(map.dynamic()); - EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "\0\0\0")(42, "???")(123, "abc"))); + EXPECT_EQ(map, SmallMap(ftl::init::map(-1, ""sv)(42, "???"sv)(123, "abc"sv))); } } @@ -108,7 +111,7 @@ TEST(SmallMap, Assign) { { // Convertible types; same capacity. SmallMap map1 = ftl::init::map<char, std::string>('M', "mega")('G', "giga"); - const SmallMap map2 = ftl::init::map('T', "tera")('P', "peta"); + const SmallMap map2 = ftl::init::map('T', "tera"sv)('P', "peta"sv); map1 = map2; EXPECT_EQ(map1, map2); @@ -147,7 +150,7 @@ TEST(SmallMap, UniqueKeys) { } } -TEST(SmallMap, Find) { +TEST(SmallMap, Get) { { // Constant reference. const SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); @@ -172,14 +175,15 @@ TEST(SmallMap, Find) { EXPECT_EQ(d, 'D'); } { - // Constant unary operation. + // Immutable transform operation. const SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); - EXPECT_EQ(map.get('c', [](char c) { return std::toupper(c); }), 'Z'); + EXPECT_EQ(map.get('c').transform([](char c) { return std::toupper(c); }), 'Z'); } { - // Mutable unary operation. + // Mutable transform operation. SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); - EXPECT_TRUE(map.get('c', [](char& c) { c = std::toupper(c); })); + EXPECT_EQ(map.get('c').transform(ftl::unit_fn([](char& c) { c = std::toupper(c); })), + ftl::unit); EXPECT_EQ(map, SmallMap(ftl::init::map('c', 'Z')('b', 'y')('a', 'x'))); } @@ -247,7 +251,7 @@ TEST(SmallMap, TryReplace) { } { // Replacement arguments can refer to the replaced mapping. - const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); + const auto ref = map.get(2).transform([](const String& s) { return s.str[0]; }); ASSERT_TRUE(ref); // Construct std::string from one character. @@ -292,7 +296,7 @@ TEST(SmallMap, EmplaceOrReplace) { } { // Replacement arguments can refer to the replaced mapping. - const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); + const auto ref = map.get(2).transform([](const String& s) { return s.str[0]; }); ASSERT_TRUE(ref); // Construct std::string from one character. diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp index bd21fbaf0e..3d81c3292a 100644 --- a/libs/gralloc/types/Android.bp +++ b/libs/gralloc/types/Android.bp @@ -23,6 +23,7 @@ package { cc_library { name: "libgralloctypes", + defaults: ["android.hardware.graphics.common-ndk_shared"], cflags: [ "-Wall", "-Werror", @@ -51,7 +52,6 @@ cc_library { ], shared_libs: [ - "android.hardware.graphics.common-V3-ndk", "android.hardware.graphics.mapper@4.0", "libhidlbase", "liblog", diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 7f0cac5d4f..4a0a839948 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -364,26 +364,61 @@ bool GraphicsEnv::shouldUseAngle() { return (mUseAngle == YES) ? true : false; } +bool GraphicsEnv::angleIsSystemDriver() { + // Make sure we are init'ed + if (mAngleAppName.empty()) { + ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE."); + return false; + } + + return (mAngleIsSystemDriver == YES) ? true : false; +} + +bool GraphicsEnv::shouldForceLegacyDriver() { + // Make sure we are init'ed + if (mAngleAppName.empty()) { + ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE."); + return false; + } + + return (mAngleIsSystemDriver == YES && mUseAngle == NO) ? true : false; +} + +std::string GraphicsEnv::getLegacySuffix() { + return mLegacyDriverSuffix; +} + void GraphicsEnv::updateUseAngle() { mUseAngle = NO; const char* ANGLE_PREFER_ANGLE = "angle"; + const char* ANGLE_PREFER_LEGACY = "legacy"; + // The following is a deprecated version of "legacy" const char* ANGLE_PREFER_NATIVE = "native"; mUseAngle = NO; if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) { - ALOGV("User set \"Developer Options\" to force the use of ANGLE"); + ALOGI("Using ANGLE, the %s GLES driver for package '%s'", + mAngleIsSystemDriver == YES ? "system" : "optional", mAngleAppName.c_str()); mUseAngle = YES; - } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { - ALOGV("User set \"Developer Options\" to force the use of Native"); + } else if (mAngleDeveloperOptIn == ANGLE_PREFER_LEGACY || + mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { + ALOGI("Using the (%s) Legacy GLES driver for package '%s'", + mAngleIsSystemDriver == YES ? "optional" : "system", mAngleAppName.c_str()); } else { ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str()); } } void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName, - const std::string developerOptIn, + const bool angleIsSystemDriver, const std::string developerOptIn, const std::vector<std::string> eglFeatures) { + // Set whether ANGLE is the system driver: + mAngleIsSystemDriver = angleIsSystemDriver ? YES : NO; + + // Note: Given the current logic and lack of the old rules file processing, + // there seems to be little chance that mUseAngle != UNKNOWN. Leave this + // for now, even though it seems outdated. if (mUseAngle != UNKNOWN) { // We've already figured out an answer for this app, so just return. ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(), @@ -404,6 +439,25 @@ void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName updateUseAngle(); } +void GraphicsEnv::setLegacyDriverInfo(const std::string appName, const bool angleIsSystemDriver, + const std::string legacyDriverName) { + ALOGV("setting legacy app name to '%s'", appName.c_str()); + mAngleAppName = appName; + + // Force the use of the legacy driver instead of ANGLE + const char* ANGLE_PREFER_LEGACY = "legacy"; + mAngleDeveloperOptIn = ANGLE_PREFER_LEGACY; + ALOGV("setting ANGLE application opt-in to 'legacy'"); + + // Set whether ANGLE is the system driver: + mAngleIsSystemDriver = angleIsSystemDriver ? YES : NO; + + mLegacyDriverSuffix = legacyDriverName; + + // Update the current status of whether we should use ANGLE or not + updateUseAngle(); +} + void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) { if (mLayerPaths.empty()) { mLayerPaths = layerPaths; diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 56d1139f57..82a6b6c2c0 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -91,17 +91,28 @@ public: bool shouldUseAngle(std::string appName); // Check if this app process should use ANGLE. bool shouldUseAngle(); + // If ANGLE is the system GLES driver + bool angleIsSystemDriver(); + // If should use legacy driver instead of a system ANGLE driver + bool shouldForceLegacyDriver(); // Set a search path for loading ANGLE libraries. The path is a list of // directories separated by ':'. A directory can be contained in a zip file // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, + void setAngleInfo(const std::string path, const std::string appName, + const bool angleIsSystemDriver, std::string devOptIn, const std::vector<std::string> eglFeatures); + // Set the state so that the legacy driver will be used, and in case ANGLE + // is the system driver, provide the name of the legacy driver. + void setLegacyDriverInfo(const std::string appName, const bool angleIsSystemDriver, + const std::string legacyDriverName); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); // Get the app name for ANGLE debug message. std::string& getAngleAppName(); + // Get the legacy driver's suffix name. + std::string getLegacySuffix(); const std::vector<std::string>& getAngleEglFeatures(); @@ -156,6 +167,10 @@ private: std::string mAngleDeveloperOptIn; // ANGLE EGL features; std::vector<std::string> mAngleEglFeatures; + // ANGLE is System Driver flag. + UseAngle mAngleIsSystemDriver = UNKNOWN; + // Legacy driver name to use when ANGLE is the system driver. + std::string mLegacyDriverSuffix; // Use ANGLE flag. UseAngle mUseAngle = UNKNOWN; // Vulkan debug layers libs. diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 56b17aecb2..d3144bb6c1 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -120,6 +120,12 @@ filegroup { path: "aidl/", } +filegroup { + name: "libgui_frame_event_aidl", + srcs: ["aidl/android/gui/FrameEvent.aidl"], + path: "aidl/", +} + cc_library_static { name: "libgui_aidl_static", vendor_available: true, @@ -136,16 +142,24 @@ cc_library_static { "include", ], + include_dirs: [ + "frameworks/native/include", + ], + export_shared_lib_headers: [ "libbinder", ], static_libs: [ "libui-types", + "libgui_window_info_static", ], aidl: { export_aidl_headers: true, + include_dirs: [ + "frameworks/native/libs/gui", + ], }, } @@ -180,19 +194,18 @@ cc_library_shared { "BufferHubConsumer.cpp", "BufferHubProducer.cpp", "BufferItemConsumer.cpp", + "CompositorTiming.cpp", "ConsumerBase.cpp", "CpuConsumer.cpp", "DebugEGLImageTracker.cpp", "DisplayEventDispatcher.cpp", "DisplayEventReceiver.cpp", - "FrameTimelineInfo.cpp", "GLConsumer.cpp", "IConsumerListener.cpp", "IGraphicBufferConsumer.cpp", "IGraphicBufferProducer.cpp", "IProducerListener.cpp", "ISurfaceComposer.cpp", - "ISurfaceComposerClient.cpp", "ITransactionCompletedListener.cpp", "LayerDebugInfo.cpp", "LayerMetadata.cpp", @@ -283,10 +296,16 @@ cc_library_static { defaults: ["libgui_bufferqueue-defaults"], srcs: [ + ":libgui_frame_event_aidl", ":inputconstants_aidl", ":libgui_bufferqueue_sources", - ":libgui_aidl", ], + + aidl: { + include_dirs: [ + "frameworks/native/libs/gui", + ], + }, } filegroup { @@ -317,6 +336,8 @@ filegroup { cc_defaults { name: "libgui_bufferqueue-defaults", + defaults: ["android.hardware.graphics.common-ndk_shared"], + cflags: [ "-Wall", "-Werror", @@ -345,7 +366,6 @@ cc_defaults { "android.hardware.graphics.bufferqueue@2.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.common@1.2", - "android.hardware.graphics.common-V3-ndk", "android.hidl.token@1.0-utils", "libbase", "libcutils", @@ -405,6 +425,7 @@ cc_library_static { ], srcs: [ + ":libgui_frame_event_aidl", "mock/GraphicBufferConsumer.cpp", "mock/GraphicBufferProducer.cpp", ], diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index aba81f60d8..3afa339849 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -33,6 +33,7 @@ #include <utils/Trace.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <chrono> @@ -158,9 +159,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati id++; mBufferItemConsumer->setName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); - mBufferItemConsumer->setBufferFreedListener(this); - ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); + ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mNumAcquired = 0; @@ -566,7 +566,7 @@ void BLASTBufferQueue::acquireNextBufferLocked( if (dequeueTime != mDequeueTimestamps.end()) { Parcel p; p.writeInt64(dequeueTime->second); - t->setMetadata(mSurfaceControl, METADATA_DEQUEUE_TIME, p); + t->setMetadata(mSurfaceControl, gui::METADATA_DEQUEUE_TIME, p); mDequeueTimestamps.erase(dequeueTime); } } @@ -599,6 +599,7 @@ Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { } void BLASTBufferQueue::acquireAndReleaseBuffer() { + BBQ_TRACE(); BufferItem bufferItem; status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false); @@ -612,6 +613,7 @@ void BLASTBufferQueue::acquireAndReleaseBuffer() { } void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) { + BBQ_TRACE(); if (!mSyncedFrameNumbers.empty() && mNumFrameAvailable > 0) { // We are waiting on a previous sync's transaction callback so allow another sync // transaction to proceed. @@ -642,8 +644,8 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { bool waitForTransactionCallback = !mSyncedFrameNumbers.empty(); { - BBQ_TRACE(); std::unique_lock _lock{mMutex}; + BBQ_TRACE(); const bool syncTransactionSet = mTransactionReadyCallback != nullptr; BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet)); @@ -1081,51 +1083,6 @@ uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() { return mLastAcquiredFrameNumber; } -void BLASTBufferQueue::abandon() { - std::unique_lock _lock{mMutex}; - // flush out the shadow queue - while (mNumFrameAvailable > 0) { - acquireAndReleaseBuffer(); - } - - // Clear submitted buffer states - mNumAcquired = 0; - mSubmitted.clear(); - mPendingRelease.clear(); - - if (!mPendingTransactions.empty()) { - BQA_LOGD("Applying pending transactions on abandon %d", - static_cast<uint32_t>(mPendingTransactions.size())); - SurfaceComposerClient::Transaction t; - mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */); - // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction - t.setApplyToken(mApplyToken).apply(false, true); - } - - // Clear sync states - if (!mSyncedFrameNumbers.empty()) { - BQA_LOGD("mSyncedFrameNumbers cleared"); - mSyncedFrameNumbers.clear(); - } - - if (mSyncTransaction != nullptr) { - BQA_LOGD("mSyncTransaction cleared mAcquireSingleBuffer=%s", - mAcquireSingleBuffer ? "true" : "false"); - mSyncTransaction = nullptr; - mAcquireSingleBuffer = false; - } - - // abandon buffer queue - if (mBufferItemConsumer != nullptr) { - mBufferItemConsumer->abandon(); - mBufferItemConsumer->setFrameAvailableListener(nullptr); - mBufferItemConsumer->setBufferFreedListener(nullptr); - } - mBufferItemConsumer = nullptr; - mConsumer = nullptr; - mProducer = nullptr; -} - bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const { std::unique_lock _lock{mMutex}; return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl); diff --git a/libs/gui/CompositorTiming.cpp b/libs/gui/CompositorTiming.cpp new file mode 100644 index 0000000000..50f7b252b6 --- /dev/null +++ b/libs/gui/CompositorTiming.cpp @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#define LOG_TAG "CompositorTiming" + +#include <cutils/compiler.h> +#include <gui/CompositorTiming.h> +#include <log/log.h> + +namespace android::gui { + +CompositorTiming::CompositorTiming(nsecs_t vsyncDeadline, nsecs_t vsyncPeriod, nsecs_t vsyncPhase, + nsecs_t presentLatency) { + if (CC_UNLIKELY(vsyncPeriod <= 0)) { + ALOGE("Invalid VSYNC period"); + return; + } + + const nsecs_t idealLatency = [=] { + // Modulo rounds toward 0 not INT64_MIN, so treat signs separately. + if (vsyncPhase < 0) return -vsyncPhase % vsyncPeriod; + + const nsecs_t latency = (vsyncPeriod - vsyncPhase) % vsyncPeriod; + return latency > 0 ? latency : vsyncPeriod; + }(); + + // Snap the latency to a value that removes scheduling jitter from the composite and present + // times, which often have >1ms of jitter. Reducing jitter is important if an app attempts to + // extrapolate something like user input to an accurate present time. Snapping also allows an + // app to precisely calculate vsyncPhase with (presentLatency % interval). + const nsecs_t bias = vsyncPeriod / 2; + const nsecs_t extraVsyncs = (presentLatency - idealLatency + bias) / vsyncPeriod; + const nsecs_t snappedLatency = + extraVsyncs > 0 ? idealLatency + extraVsyncs * vsyncPeriod : idealLatency; + + this->deadline = vsyncDeadline - idealLatency; + this->interval = vsyncPeriod; + this->presentLatency = snappedLatency; +} + +} // namespace android::gui diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index dfdce20438..501e69ade5 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -35,11 +35,14 @@ static const size_t EVENT_BUFFER_SIZE = 100; static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300); -DisplayEventDispatcher::DisplayEventDispatcher( - const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource, - ISurfaceComposer::EventRegistrationFlags eventRegistration) - : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false), - mLastVsyncCount(0), mLastScheduleVsyncTime(0) { +DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper, + gui::ISurfaceComposer::VsyncSource vsyncSource, + EventRegistrationFlags eventRegistration) + : mLooper(looper), + mReceiver(vsyncSource, eventRegistration), + mWaitingForVsync(false), + mLastVsyncCount(0), + mLastScheduleVsyncTime(0) { ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this); } diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index bfb77699c0..c52fb6b7c3 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -19,10 +19,9 @@ #include <utils/Errors.h> #include <gui/DisplayEventReceiver.h> -#include <gui/ISurfaceComposer.h> #include <gui/VsyncEventData.h> -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <private/gui/BitTube.h> @@ -32,15 +31,20 @@ namespace android { // --------------------------------------------------------------------------- -DisplayEventReceiver::DisplayEventReceiver( - ISurfaceComposer::VsyncSource vsyncSource, - ISurfaceComposer::EventRegistrationFlags eventRegistration) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); +DisplayEventReceiver::DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource, + EventRegistrationFlags eventRegistration) { + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); if (sf != nullptr) { - mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration); + mEventConnection = nullptr; + binder::Status status = + sf->createDisplayEventConnection(vsyncSource, + static_cast< + gui::ISurfaceComposer::EventRegistration>( + eventRegistration.get()), + &mEventConnection); if (mEventConnection != nullptr) { mDataChannel = std::make_unique<gui::BitTube>(); - const auto status = mEventConnection->stealReceiveChannel(mDataChannel.get()); + status = mEventConnection->stealReceiveChannel(mDataChannel.get()); if (!status.isOk()) { ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str()); mInitError = std::make_optional<status_t>(status.transactionError()); diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp deleted file mode 100644 index 3800b88ab0..0000000000 --- a/libs/gui/FrameTimelineInfo.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2021 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. - */ - -#define LOG_TAG "FrameTimelineInfo" - -#include <inttypes.h> - -#include <android/os/IInputConstants.h> -#include <gui/FrameTimelineInfo.h> -#include <gui/LayerState.h> -#include <private/gui/ParcelUtils.h> -#include <utils/Errors.h> - -#include <cmath> - -using android::os::IInputConstants; - -namespace android { - -status_t FrameTimelineInfo::write(Parcel& output) const { - SAFE_PARCEL(output.writeInt64, vsyncId); - SAFE_PARCEL(output.writeInt32, inputEventId); - SAFE_PARCEL(output.writeInt64, startTimeNanos); - return NO_ERROR; -} - -status_t FrameTimelineInfo::read(const Parcel& input) { - SAFE_PARCEL(input.readInt64, &vsyncId); - SAFE_PARCEL(input.readInt32, &inputEventId); - SAFE_PARCEL(input.readInt64, &startTimeNanos); - return NO_ERROR; -} - -void FrameTimelineInfo::merge(const FrameTimelineInfo& other) { - // When merging vsync Ids we take the oldest valid one - if (vsyncId != INVALID_VSYNC_ID && other.vsyncId != INVALID_VSYNC_ID) { - if (other.vsyncId > vsyncId) { - vsyncId = other.vsyncId; - inputEventId = other.inputEventId; - startTimeNanos = other.startTimeNanos; - } - } else if (vsyncId == INVALID_VSYNC_ID) { - vsyncId = other.vsyncId; - inputEventId = other.inputEventId; - startTimeNanos = other.startTimeNanos; - } -} - -void FrameTimelineInfo::clear() { - vsyncId = INVALID_VSYNC_ID; - inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID; - startTimeNanos = 0; -} - -}; // namespace android diff --git a/libs/gui/GLConsumerUtils.cpp b/libs/gui/GLConsumerUtils.cpp index 7a06c3d801..a1c69e7d6d 100644 --- a/libs/gui/GLConsumerUtils.cpp +++ b/libs/gui/GLConsumerUtils.cpp @@ -27,6 +27,13 @@ namespace android { void GLConsumer::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering) { + computeTransformMatrix(outTransform, buf->getWidth(), buf->getHeight(), buf->getPixelFormat(), + cropRect, transform, filtering); +} + +void GLConsumer::computeTransformMatrix(float outTransform[16], float bufferWidth, + float bufferHeight, PixelFormat pixelFormat, + const Rect& cropRect, uint32_t transform, bool filtering) { // Transform matrices static const mat4 mtxFlipH( -1, 0, 0, 0, @@ -60,8 +67,6 @@ void GLConsumer::computeTransformMatrix(float outTransform[16], if (!cropRect.isEmpty()) { float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; - float bufferWidth = buf->getWidth(); - float bufferHeight = buf->getHeight(); float shrinkAmount = 0.0f; if (filtering) { // In order to prevent bilinear sampling beyond the edge of the @@ -70,7 +75,7 @@ void GLConsumer::computeTransformMatrix(float outTransform[16], // off each end, but because the chroma channels of YUV420 images // are subsampled we may need to shrink the crop region by a whole // texel on each side. - switch (buf->getPixelFormat()) { + switch (pixelFormat) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: case PIXEL_FORMAT_RGBA_FP16: diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 24d39fe86a..af64b3bd32 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -25,8 +25,6 @@ #include <binder/Parcel.h> #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> -#include <gui/ISurfaceComposerClient.h> -#include <gui/LayerDebugInfo.h> #include <gui/LayerState.h> #include <private/gui/ParcelUtils.h> #include <stdint.h> @@ -37,7 +35,6 @@ #include <ui/DisplayState.h> #include <ui/DynamicDisplayInfo.h> #include <ui/HdrCapabilities.h> -#include <ui/StaticDisplayInfo.h> #include <utils/Log.h> // --------------------------------------------------------------------------- @@ -63,14 +60,6 @@ public: virtual ~BpSurfaceComposer(); - virtual sp<ISurfaceComposerClient> createConnection() - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); - return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder()); - } - status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state, const Vector<DisplayState>& displays, uint32_t flags, @@ -82,7 +71,7 @@ public: Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(frameTimelineInfo.write, data); + frameTimelineInfo.writeToParcel(&data); SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(state.size())); for (const auto& s : state) { @@ -119,905 +108,6 @@ public: data, &reply); } } - - void bootFinished() override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); - } - - bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const override { - Parcel data, reply; - int err = NO_ERROR; - err = data.writeInterfaceToken( - ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " - "interface descriptor: %s (%d)", strerror(-err), -err); - return false; - } - err = data.writeStrongBinder(IInterface::asBinder(bufferProducer)); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " - "strong binder to parcel: %s (%d)", strerror(-err), -err); - return false; - } - err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data, - &reply); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error " - "performing transaction: %s (%d)", strerror(-err), -err); - return false; - } - int32_t result = 0; - err = reply.readInt32(&result); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error " - "retrieving result: %s (%d)", strerror(-err), -err); - return false; - } - return result != 0; - } - - status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override { - if (!outSupported) { - return UNEXPECTED_NULL; - } - outSupported->clear(); - - Parcel data, reply; - - status_t err = data.writeInterfaceToken( - ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - return err; - } - - err = remote()->transact( - BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS, - data, &reply); - if (err != NO_ERROR) { - return err; - } - - int32_t result = 0; - err = reply.readInt32(&result); - if (err != NO_ERROR) { - return err; - } - if (result != NO_ERROR) { - return result; - } - - std::vector<int32_t> supported; - err = reply.readInt32Vector(&supported); - if (err != NO_ERROR) { - return err; - } - - outSupported->reserve(supported.size()); - for (int32_t s : supported) { - outSupported->push_back(static_cast<FrameEvent>(s)); - } - return NO_ERROR; - } - - sp<IDisplayEventConnection> createDisplayEventConnection( - VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) override { - Parcel data, reply; - sp<IDisplayEventConnection> result; - int err = data.writeInterfaceToken( - ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - return result; - } - data.writeInt32(static_cast<int32_t>(vsyncSource)); - data.writeUint32(eventRegistration.get()); - err = remote()->transact( - BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION, - data, &reply); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::createDisplayEventConnection: error performing " - "transaction: %s (%d)", strerror(-err), -err); - return result; - } - result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder()); - return result; - } - - status_t getStaticDisplayInfo(const sp<IBinder>& display, - ui::StaticDisplayInfo* info) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - remote()->transact(BnSurfaceComposer::GET_STATIC_DISPLAY_INFO, data, &reply); - const status_t result = reply.readInt32(); - if (result != NO_ERROR) return result; - return reply.read(*info); - } - - status_t getDynamicDisplayInfo(const sp<IBinder>& display, - ui::DynamicDisplayInfo* info) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - remote()->transact(BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO, data, &reply); - const status_t result = reply.readInt32(); - if (result != NO_ERROR) return result; - return reply.read(*info); - } - - status_t getDisplayNativePrimaries(const sp<IBinder>& display, - ui::DisplayPrimaries& primaries) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("getDisplayNativePrimaries failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("getDisplayNativePrimaries failed to writeStrongBinder: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES, data, &reply); - if (result != NO_ERROR) { - ALOGE("getDisplayNativePrimaries failed to transact: %d", result); - return result; - } - result = reply.readInt32(); - if (result == NO_ERROR) { - memcpy(&primaries, reply.readInplace(sizeof(ui::DisplayPrimaries)), - sizeof(ui::DisplayPrimaries)); - } - return result; - } - - status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result); - return result; - } - result = data.writeInt32(static_cast<int32_t>(colorMode)); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to writeInt32: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_COLOR_MODE, data, &reply); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to transact: %d", result); - return result; - } - return static_cast<status_t>(reply.readInt32()); - } - - status_t setBootDisplayMode(const sp<IBinder>& display, - ui::DisplayModeId displayModeId) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to writeStrongBinder: %d", result); - return result; - } - result = data.writeInt32(displayModeId); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to writeIint32: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::SET_BOOT_DISPLAY_MODE, data, &reply); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to transact: %d", result); - } - return result; - } - - status_t clearAnimationFrameStats() override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("clearAnimationFrameStats failed to writeInterfaceToken: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply); - if (result != NO_ERROR) { - ALOGE("clearAnimationFrameStats failed to transact: %d", result); - return result; - } - return reply.readInt32(); - } - - status_t getAnimationFrameStats(FrameStats* outStats) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply); - reply.read(*outStats); - return reply.readInt32(); - } - - virtual status_t overrideHdrTypes(const sp<IBinder>& display, - const std::vector<ui::Hdr>& hdrTypes) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, display); - - std::vector<int32_t> hdrTypesVector; - for (ui::Hdr i : hdrTypes) { - hdrTypesVector.push_back(static_cast<int32_t>(i)); - } - SAFE_PARCEL(data.writeInt32Vector, hdrTypesVector); - - status_t result = remote()->transact(BnSurfaceComposer::OVERRIDE_HDR_TYPES, data, &reply); - if (result != NO_ERROR) { - ALOGE("overrideHdrTypes failed to transact: %d", result); - return result; - } - return result; - } - - status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeInt32, atomId); - - status_t err = remote()->transact(BnSurfaceComposer::ON_PULL_ATOM, data, &reply); - if (err != NO_ERROR) { - ALOGE("onPullAtom failed to transact: %d", err); - return err; - } - - int32_t size = 0; - SAFE_PARCEL(reply.readInt32, &size); - const void* dataPtr = reply.readInplace(size); - if (dataPtr == nullptr) { - return UNEXPECTED_NULL; - } - pulledData->assign((const char*)dataPtr, size); - SAFE_PARCEL(reply.readBool, success); - return NO_ERROR; - } - - status_t enableVSyncInjections(bool enable) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeBool(enable); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to writeBool: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS, data, &reply, - IBinder::FLAG_ONEWAY); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to transact: %d", result); - return result; - } - return result; - } - - status_t injectVSync(nsecs_t when) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("injectVSync failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeInt64(when); - if (result != NO_ERROR) { - ALOGE("injectVSync failed to writeInt64: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply, - IBinder::FLAG_ONEWAY); - if (result != NO_ERROR) { - ALOGE("injectVSync failed to transact: %d", result); - return result; - } - return result; - } - - status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override { - if (!outLayers) { - return UNEXPECTED_NULL; - } - - Parcel data, reply; - - status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - return err; - } - - err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply); - if (err != NO_ERROR) { - return err; - } - - int32_t result = 0; - err = reply.readInt32(&result); - if (err != NO_ERROR) { - return err; - } - if (result != NO_ERROR) { - return result; - } - - outLayers->clear(); - return reply.readParcelableVector(outLayers); - } - - status_t getCompositionPreference(ui::Dataspace* defaultDataspace, - ui::PixelFormat* defaultPixelFormat, - ui::Dataspace* wideColorGamutDataspace, - ui::PixelFormat* wideColorGamutPixelFormat) const override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - return error; - } - error = remote()->transact(BnSurfaceComposer::GET_COMPOSITION_PREFERENCE, data, &reply); - if (error != NO_ERROR) { - return error; - } - error = static_cast<status_t>(reply.readInt32()); - if (error == NO_ERROR) { - *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32()); - *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32()); - *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32()); - *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32()); - } - return error; - } - - status_t getColorManagement(bool* outGetColorManagement) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply); - bool result; - status_t err = reply.readBool(&result); - if (err == NO_ERROR) { - *outGetColorManagement = result; - } - return err; - } - - status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display, - ui::PixelFormat* outFormat, - ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const override { - if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE; - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - - status_t error = - remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, - data, &reply); - if (error != NO_ERROR) { - return error; - } - - uint32_t value = 0; - error = reply.readUint32(&value); - if (error != NO_ERROR) { - return error; - } - *outFormat = static_cast<ui::PixelFormat>(value); - - error = reply.readUint32(&value); - if (error != NO_ERROR) { - return error; - } - *outDataspace = static_cast<ui::Dataspace>(value); - - error = reply.readUint32(&value); - if (error != NO_ERROR) { - return error; - } - *outComponentMask = static_cast<uint8_t>(value); - return error; - } - - status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, - uint8_t componentMask, uint64_t maxFrames) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - data.writeBool(enable); - data.writeByte(static_cast<int8_t>(componentMask)); - data.writeUint64(maxFrames); - status_t result = - remote()->transact(BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED, data, - &reply); - return result; - } - - status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const override { - if (!outStats) return BAD_VALUE; - - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - data.writeUint64(maxFrames); - data.writeUint64(timestamp); - - status_t result = - remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE, data, &reply); - - if (result != NO_ERROR) { - return result; - } - - result = reply.readUint64(&outStats->numFrames); - if (result != NO_ERROR) { - return result; - } - - result = reply.readUint64Vector(&outStats->component_0_sample); - if (result != NO_ERROR) { - return result; - } - result = reply.readUint64Vector(&outStats->component_1_sample); - if (result != NO_ERROR) { - return result; - } - result = reply.readUint64Vector(&outStats->component_2_sample); - if (result != NO_ERROR) { - return result; - } - result = reply.readUint64Vector(&outStats->component_3_sample); - return result; - } - - status_t getProtectedContentSupport(bool* outSupported) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - status_t error = - remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply); - if (error != NO_ERROR) { - return error; - } - error = reply.readBool(outSupported); - return error; - } - - status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, - const sp<IRegionSamplingListener>& listener) override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to write interface token"); - return error; - } - error = data.write(samplingArea); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to write sampling area"); - return error; - } - error = data.writeStrongBinder(stopLayerHandle); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to write stop layer handle"); - return error; - } - error = data.writeStrongBinder(IInterface::asBinder(listener)); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to write listener"); - return error; - } - error = remote()->transact(BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER, data, &reply); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to transact"); - } - return error; - } - - status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - ALOGE("removeRegionSamplingListener: Failed to write interface token"); - return error; - } - error = data.writeStrongBinder(IInterface::asBinder(listener)); - if (error != NO_ERROR) { - ALOGE("removeRegionSamplingListener: Failed to write listener"); - return error; - } - error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data, - &reply); - if (error != NO_ERROR) { - ALOGE("removeRegionSamplingListener: Failed to transact"); - } - return error; - } - - virtual status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeInt32, taskId); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - const status_t error = - remote()->transact(BnSurfaceComposer::ADD_FPS_LISTENER, data, &reply); - if (error != OK) { - ALOGE("addFpsListener: Failed to transact"); - } - return error; - } - - virtual status_t removeFpsListener(const sp<gui::IFpsListener>& listener) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - - const status_t error = - remote()->transact(BnSurfaceComposer::REMOVE_FPS_LISTENER, data, &reply); - if (error != OK) { - ALOGE("removeFpsListener: Failed to transact"); - } - return error; - } - - virtual status_t addTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - - const status_t error = - remote()->transact(BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER, data, - &reply); - if (error != NO_ERROR) { - ALOGE("addTunnelModeEnabledListener: Failed to transact"); - } - return error; - } - - virtual status_t removeTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - - const status_t error = - remote()->transact(BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER, data, - &reply); - if (error != NO_ERROR) { - ALOGE("removeTunnelModeEnabledListener: Failed to transact"); - } - return error; - } - - status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, - ui::DisplayModeId defaultMode, bool allowGroupSwitching, - float primaryRefreshRateMin, float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(displayToken); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to write display token: %d", result); - return result; - } - result = data.writeInt32(defaultMode); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write defaultMode: %d", result); - return result; - } - result = data.writeBool(allowGroupSwitching); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write allowGroupSwitching: %d", result); - return result; - } - result = data.writeFloat(primaryRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write primaryRefreshRateMin: %d", result); - return result; - } - result = data.writeFloat(primaryRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write primaryRefreshRateMax: %d", result); - return result; - } - result = data.writeFloat(appRequestRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write appRequestRefreshRateMin: %d", - result); - return result; - } - result = data.writeFloat(appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write appRequestRefreshRateMax: %d", - result); - return result; - } - - result = - remote()->transact(BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS, data, &reply); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to transact: %d", result); - return result; - } - return reply.readInt32(); - } - - status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, - ui::DisplayModeId* outDefaultMode, - bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, - float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) override { - if (!outDefaultMode || !outAllowGroupSwitching || !outPrimaryRefreshRateMin || - !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || - !outAppRequestRefreshRateMax) { - return BAD_VALUE; - } - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(displayToken); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to writeStrongBinder: %d", result); - return result; - } - result = - remote()->transact(BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS, data, &reply); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to transact: %d", result); - return result; - } - - result = reply.readInt32(outDefaultMode); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read defaultMode: %d", result); - return result; - } - if (*outDefaultMode < 0) { - ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, *outDefaultMode); - return BAD_VALUE; - } - - result = reply.readBool(outAllowGroupSwitching); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read allowGroupSwitching: %d", result); - return result; - } - result = reply.readFloat(outPrimaryRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMin: %d", result); - return result; - } - result = reply.readFloat(outPrimaryRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMax: %d", result); - return result; - } - result = reply.readFloat(outAppRequestRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMin: %d", result); - return result; - } - result = reply.readFloat(outAppRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMax: %d", result); - return result; - } - return reply.readInt32(); - } - - status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, float lightRadius) override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - ALOGE("setGlobalShadowSettings: failed to write interface token: %d", error); - return error; - } - - std::vector<float> shadowConfig = {ambientColor.r, ambientColor.g, ambientColor.b, - ambientColor.a, spotColor.r, spotColor.g, - spotColor.b, spotColor.a, lightPosY, - lightPosZ, lightRadius}; - - error = data.writeFloatVector(shadowConfig); - if (error != NO_ERROR) { - ALOGE("setGlobalShadowSettings: failed to write shadowConfig: %d", error); - return error; - } - - error = remote()->transact(BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS, data, &reply, - IBinder::FLAG_ONEWAY); - if (error != NO_ERROR) { - ALOGE("setGlobalShadowSettings: failed to transact: %d", error); - return error; - } - return NO_ERROR; - } - - status_t getDisplayDecorationSupport( - const sp<IBinder>& displayToken, - std::optional<common::DisplayDecorationSupport>* outSupport) const override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to write interface token: %d", error); - return error; - } - error = data.writeStrongBinder(displayToken); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to write display token: %d", error); - return error; - } - error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_DECORATION_SUPPORT, data, &reply); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to transact: %d", error); - return error; - } - bool support; - error = reply.readBool(&support); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to read support: %d", error); - return error; - } - - if (support) { - int32_t format, alphaInterpretation; - error = reply.readInt32(&format); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to read format: %d", error); - return error; - } - error = reply.readInt32(&alphaInterpretation); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to read alphaInterpretation: %d", error); - return error; - } - outSupport->emplace(); - outSupport->value().format = static_cast<common::PixelFormat>(format); - outSupport->value().alphaInterpretation = - static_cast<common::AlphaInterpretation>(alphaInterpretation); - } else { - outSupport->reset(); - } - return NO_ERROR; - } - - status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility, int8_t changeFrameRateStrategy) override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(surface)); - SAFE_PARCEL(data.writeFloat, frameRate); - SAFE_PARCEL(data.writeByte, compatibility); - SAFE_PARCEL(data.writeByte, changeFrameRateStrategy); - - status_t err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); - return err; - } - - return reply.readInt32(); - } - - status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, - const FrameTimelineInfo& frameTimelineInfo) override { - Parcel data, reply; - status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - ALOGE("%s: failed writing interface token: %s (%d)", __func__, strerror(-err), -err); - return err; - } - - err = data.writeStrongBinder(IInterface::asBinder(surface)); - if (err != NO_ERROR) { - ALOGE("%s: failed writing strong binder: %s (%d)", __func__, strerror(-err), -err); - return err; - } - - SAFE_PARCEL(frameTimelineInfo.write, data); - - err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_INFO, data, &reply); - if (err != NO_ERROR) { - ALOGE("%s: failed to transact: %s (%d)", __func__, strerror(-err), err); - return err; - } - - return reply.readInt32(); - } - - status_t addTransactionTraceListener( - const sp<gui::ITransactionTraceListener>& listener) override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - - return remote()->transact(BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER, data, &reply); - } - - /** - * Get priority of the RenderEngine in surface flinger. - */ - int getGPUContextPriority() override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - status_t err = - remote()->transact(BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY, data, &reply); - if (err != NO_ERROR) { - ALOGE("getGPUContextPriority failed to read data: %s (%d)", strerror(-err), err); - return 0; - } - return reply.readInt32(); - } - - status_t getMaxAcquiredBufferCount(int* buffers) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - status_t err = - remote()->transact(BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); - if (err != NO_ERROR) { - ALOGE("getMaxAcquiredBufferCount failed to read data: %s (%d)", strerror(-err), err); - return err; - } - - return reply.readInt32(buffers); - } - - status_t addWindowInfosListener( - const sp<IWindowInfosListener>& windowInfosListener) const override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); - return remote()->transact(BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER, data, &reply); - } - - status_t removeWindowInfosListener( - const sp<IWindowInfosListener>& windowInfosListener) const override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); - return remote()->transact(BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, data, &reply); - } - - status_t setOverrideFrameRate(uid_t uid, float frameRate) override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeUint32, uid); - SAFE_PARCEL(data.writeFloat, frameRate); - - status_t err = remote()->transact(BnSurfaceComposer::SET_OVERRIDE_FRAME_RATE, data, &reply); - if (err != NO_ERROR) { - ALOGE("setOverrideFrameRate: failed to transact %s (%d)", strerror(-err), err); - return err; - } - - return NO_ERROR; - } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1031,18 +121,12 @@ IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer"); status_t BnSurfaceComposer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - switch(code) { - case CREATE_CONNECTION: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> b = IInterface::asBinder(createConnection()); - reply->writeStrongBinder(b); - return NO_ERROR; - } + switch (code) { case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); FrameTimelineInfo frameTimelineInfo; - SAFE_PARCEL(frameTimelineInfo.read, data); + frameTimelineInfo.readFromParcel(&data); uint32_t count = 0; SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); @@ -1102,642 +186,6 @@ status_t BnSurfaceComposer::onTransact( uncachedBuffer, hasListenerCallbacks, listenerCallbacks, transactionId); } - case BOOT_FINISHED: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - bootFinished(); - return NO_ERROR; - } - case AUTHENTICATE_SURFACE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IGraphicBufferProducer> bufferProducer = - interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); - int32_t result = authenticateSurfaceTexture(bufferProducer) ? 1 : 0; - reply->writeInt32(result); - return NO_ERROR; - } - case GET_SUPPORTED_FRAME_TIMESTAMPS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - std::vector<FrameEvent> supportedTimestamps; - status_t result = getSupportedFrameTimestamps(&supportedTimestamps); - status_t err = reply->writeInt32(result); - if (err != NO_ERROR) { - return err; - } - if (result != NO_ERROR) { - return result; - } - - std::vector<int32_t> supported; - supported.reserve(supportedTimestamps.size()); - for (FrameEvent s : supportedTimestamps) { - supported.push_back(static_cast<int32_t>(s)); - } - return reply->writeInt32Vector(supported); - } - case CREATE_DISPLAY_EVENT_CONNECTION: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32()); - EventRegistrationFlags eventRegistration = - static_cast<EventRegistration>(data.readUint32()); - - sp<IDisplayEventConnection> connection( - createDisplayEventConnection(vsyncSource, eventRegistration)); - reply->writeStrongBinder(IInterface::asBinder(connection)); - return NO_ERROR; - } - case GET_STATIC_DISPLAY_INFO: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::StaticDisplayInfo info; - const sp<IBinder> display = data.readStrongBinder(); - const status_t result = getStaticDisplayInfo(display, &info); - SAFE_PARCEL(reply->writeInt32, result); - if (result != NO_ERROR) return result; - SAFE_PARCEL(reply->write, info); - return NO_ERROR; - } - case GET_DYNAMIC_DISPLAY_INFO: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::DynamicDisplayInfo info; - const sp<IBinder> display = data.readStrongBinder(); - const status_t result = getDynamicDisplayInfo(display, &info); - SAFE_PARCEL(reply->writeInt32, result); - if (result != NO_ERROR) return result; - SAFE_PARCEL(reply->write, info); - return NO_ERROR; - } - case GET_DISPLAY_NATIVE_PRIMARIES: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::DisplayPrimaries primaries; - sp<IBinder> display = nullptr; - - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getDisplayNativePrimaries failed to readStrongBinder: %d", result); - return result; - } - - result = getDisplayNativePrimaries(display, primaries); - reply->writeInt32(result); - if (result == NO_ERROR) { - memcpy(reply->writeInplace(sizeof(ui::DisplayPrimaries)), &primaries, - sizeof(ui::DisplayPrimaries)); - } - - return NO_ERROR; - } - case SET_ACTIVE_COLOR_MODE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getActiveColorMode failed to readStrongBinder: %d", result); - return result; - } - int32_t colorModeInt = 0; - result = data.readInt32(&colorModeInt); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to readInt32: %d", result); - return result; - } - result = setActiveColorMode(display, - static_cast<ColorMode>(colorModeInt)); - result = reply->writeInt32(result); - return result; - } - case SET_BOOT_DISPLAY_MODE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to readStrongBinder: %d", result); - return result; - } - ui::DisplayModeId displayModeId; - result = data.readInt32(&displayModeId); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to readInt32: %d", result); - return result; - } - return setBootDisplayMode(display, displayModeId); - } - case CLEAR_ANIMATION_FRAME_STATS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - status_t result = clearAnimationFrameStats(); - reply->writeInt32(result); - return NO_ERROR; - } - case GET_ANIMATION_FRAME_STATS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - FrameStats stats; - status_t result = getAnimationFrameStats(&stats); - reply->write(stats); - reply->writeInt32(result); - return NO_ERROR; - } - case ENABLE_VSYNC_INJECTIONS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - bool enable = false; - status_t result = data.readBool(&enable); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to readBool: %d", result); - return result; - } - return enableVSyncInjections(enable); - } - case INJECT_VSYNC: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int64_t when = 0; - status_t result = data.readInt64(&when); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to readInt64: %d", result); - return result; - } - return injectVSync(when); - } - case GET_LAYER_DEBUG_INFO: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - std::vector<LayerDebugInfo> outLayers; - status_t result = getLayerDebugInfo(&outLayers); - reply->writeInt32(result); - if (result == NO_ERROR) - { - result = reply->writeParcelableVector(outLayers); - } - return result; - } - case GET_COMPOSITION_PREFERENCE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::Dataspace defaultDataspace; - ui::PixelFormat defaultPixelFormat; - ui::Dataspace wideColorGamutDataspace; - ui::PixelFormat wideColorGamutPixelFormat; - status_t error = - getCompositionPreference(&defaultDataspace, &defaultPixelFormat, - &wideColorGamutDataspace, &wideColorGamutPixelFormat); - reply->writeInt32(error); - if (error == NO_ERROR) { - reply->writeInt32(static_cast<int32_t>(defaultDataspace)); - reply->writeInt32(static_cast<int32_t>(defaultPixelFormat)); - reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace)); - reply->writeInt32(static_cast<int32_t>(wideColorGamutPixelFormat)); - } - return error; - } - case GET_COLOR_MANAGEMENT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - bool result; - status_t error = getColorManagement(&result); - if (error == NO_ERROR) { - reply->writeBool(result); - } - return error; - } - case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - sp<IBinder> display = data.readStrongBinder(); - ui::PixelFormat format; - ui::Dataspace dataspace; - uint8_t component = 0; - auto result = - getDisplayedContentSamplingAttributes(display, &format, &dataspace, &component); - if (result == NO_ERROR) { - reply->writeUint32(static_cast<uint32_t>(format)); - reply->writeUint32(static_cast<uint32_t>(dataspace)); - reply->writeUint32(static_cast<uint32_t>(component)); - } - return result; - } - case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - sp<IBinder> display = nullptr; - bool enable = false; - int8_t componentMask = 0; - uint64_t maxFrames = 0; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("setDisplayContentSamplingEnabled failure in reading Display token: %d", - result); - return result; - } - - result = data.readBool(&enable); - if (result != NO_ERROR) { - ALOGE("setDisplayContentSamplingEnabled failure in reading enable: %d", result); - return result; - } - - result = data.readByte(static_cast<int8_t*>(&componentMask)); - if (result != NO_ERROR) { - ALOGE("setDisplayContentSamplingEnabled failure in reading component mask: %d", - result); - return result; - } - - result = data.readUint64(&maxFrames); - if (result != NO_ERROR) { - ALOGE("setDisplayContentSamplingEnabled failure in reading max frames: %d", result); - return result; - } - - return setDisplayContentSamplingEnabled(display, enable, - static_cast<uint8_t>(componentMask), maxFrames); - } - case GET_DISPLAYED_CONTENT_SAMPLE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - sp<IBinder> display = data.readStrongBinder(); - uint64_t maxFrames = 0; - uint64_t timestamp = 0; - - status_t result = data.readUint64(&maxFrames); - if (result != NO_ERROR) { - ALOGE("getDisplayedContentSample failure in reading max frames: %d", result); - return result; - } - - result = data.readUint64(×tamp); - if (result != NO_ERROR) { - ALOGE("getDisplayedContentSample failure in reading timestamp: %d", result); - return result; - } - - DisplayedFrameStats stats; - result = getDisplayedContentSample(display, maxFrames, timestamp, &stats); - if (result == NO_ERROR) { - reply->writeUint64(stats.numFrames); - reply->writeUint64Vector(stats.component_0_sample); - reply->writeUint64Vector(stats.component_1_sample); - reply->writeUint64Vector(stats.component_2_sample); - reply->writeUint64Vector(stats.component_3_sample); - } - return result; - } - case GET_PROTECTED_CONTENT_SUPPORT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - bool result; - status_t error = getProtectedContentSupport(&result); - if (error == NO_ERROR) { - reply->writeBool(result); - } - return error; - } - case ADD_REGION_SAMPLING_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - Rect samplingArea; - status_t result = data.read(samplingArea); - if (result != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to read sampling area"); - return result; - } - sp<IBinder> stopLayerHandle; - result = data.readNullableStrongBinder(&stopLayerHandle); - if (result != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to read stop layer handle"); - return result; - } - sp<IRegionSamplingListener> listener; - result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to read listener"); - return result; - } - return addRegionSamplingListener(samplingArea, stopLayerHandle, listener); - } - case REMOVE_REGION_SAMPLING_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IRegionSamplingListener> listener; - status_t result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("removeRegionSamplingListener: Failed to read listener"); - return result; - } - return removeRegionSamplingListener(listener); - } - case ADD_FPS_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int32_t taskId; - status_t result = data.readInt32(&taskId); - if (result != NO_ERROR) { - ALOGE("addFpsListener: Failed to read layer handle"); - return result; - } - sp<gui::IFpsListener> listener; - result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("addFpsListener: Failed to read listener"); - return result; - } - return addFpsListener(taskId, listener); - } - case REMOVE_FPS_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<gui::IFpsListener> listener; - status_t result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("removeFpsListener: Failed to read listener"); - return result; - } - return removeFpsListener(listener); - } - case ADD_TUNNEL_MODE_ENABLED_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<gui::ITunnelModeEnabledListener> listener; - status_t result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("addTunnelModeEnabledListener: Failed to read listener"); - return result; - } - return addTunnelModeEnabledListener(listener); - } - case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<gui::ITunnelModeEnabledListener> listener; - status_t result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("removeTunnelModeEnabledListener: Failed to read listener"); - return result; - } - return removeTunnelModeEnabledListener(listener); - } - case SET_DESIRED_DISPLAY_MODE_SPECS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> displayToken = data.readStrongBinder(); - ui::DisplayModeId defaultMode; - status_t result = data.readInt32(&defaultMode); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read defaultMode: %d", result); - return result; - } - if (defaultMode < 0) { - ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, defaultMode); - return BAD_VALUE; - } - bool allowGroupSwitching; - result = data.readBool(&allowGroupSwitching); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read allowGroupSwitching: %d", result); - return result; - } - float primaryRefreshRateMin; - result = data.readFloat(&primaryRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read primaryRefreshRateMin: %d", - result); - return result; - } - float primaryRefreshRateMax; - result = data.readFloat(&primaryRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read primaryRefreshRateMax: %d", - result); - return result; - } - float appRequestRefreshRateMin; - result = data.readFloat(&appRequestRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read appRequestRefreshRateMin: %d", - result); - return result; - } - float appRequestRefreshRateMax; - result = data.readFloat(&appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read appRequestRefreshRateMax: %d", - result); - return result; - } - result = setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, - primaryRefreshRateMin, primaryRefreshRateMax, - appRequestRefreshRateMin, appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to call setDesiredDisplayModeSpecs: " - "%d", - result); - return result; - } - reply->writeInt32(result); - return result; - } - case GET_DESIRED_DISPLAY_MODE_SPECS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> displayToken = data.readStrongBinder(); - ui::DisplayModeId defaultMode; - bool allowGroupSwitching; - float primaryRefreshRateMin; - float primaryRefreshRateMax; - float appRequestRefreshRateMin; - float appRequestRefreshRateMax; - - status_t result = - getDesiredDisplayModeSpecs(displayToken, &defaultMode, &allowGroupSwitching, - &primaryRefreshRateMin, &primaryRefreshRateMax, - &appRequestRefreshRateMin, - &appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to get getDesiredDisplayModeSpecs: " - "%d", - result); - return result; - } - - result = reply->writeInt32(defaultMode); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write defaultMode: %d", result); - return result; - } - result = reply->writeBool(allowGroupSwitching); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write allowGroupSwitching: %d", - result); - return result; - } - result = reply->writeFloat(primaryRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMin: %d", - result); - return result; - } - result = reply->writeFloat(primaryRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMax: %d", - result); - return result; - } - result = reply->writeFloat(appRequestRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMin: %d", - result); - return result; - } - result = reply->writeFloat(appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMax: %d", - result); - return result; - } - reply->writeInt32(result); - return result; - } - case SET_GLOBAL_SHADOW_SETTINGS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - std::vector<float> shadowConfig; - status_t error = data.readFloatVector(&shadowConfig); - if (error != NO_ERROR || shadowConfig.size() != 11) { - ALOGE("setGlobalShadowSettings: failed to read shadowConfig: %d", error); - return error; - } - - half4 ambientColor = {shadowConfig[0], shadowConfig[1], shadowConfig[2], - shadowConfig[3]}; - half4 spotColor = {shadowConfig[4], shadowConfig[5], shadowConfig[6], shadowConfig[7]}; - float lightPosY = shadowConfig[8]; - float lightPosZ = shadowConfig[9]; - float lightRadius = shadowConfig[10]; - return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, - lightRadius); - } - case GET_DISPLAY_DECORATION_SUPPORT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> displayToken; - SAFE_PARCEL(data.readNullableStrongBinder, &displayToken); - std::optional<common::DisplayDecorationSupport> support; - auto error = getDisplayDecorationSupport(displayToken, &support); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport failed with error %d", error); - return error; - } - reply->writeBool(support.has_value()); - if (support) { - reply->writeInt32(static_cast<int32_t>(support.value().format)); - reply->writeInt32(static_cast<int32_t>(support.value().alphaInterpretation)); - } - return error; - } - case SET_FRAME_RATE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> binder; - SAFE_PARCEL(data.readStrongBinder, &binder); - - sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder); - if (!surface) { - ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer"); - return BAD_VALUE; - } - float frameRate; - SAFE_PARCEL(data.readFloat, &frameRate); - - int8_t compatibility; - SAFE_PARCEL(data.readByte, &compatibility); - - int8_t changeFrameRateStrategy; - SAFE_PARCEL(data.readByte, &changeFrameRateStrategy); - - status_t result = - setFrameRate(surface, frameRate, compatibility, changeFrameRateStrategy); - reply->writeInt32(result); - return NO_ERROR; - } - case SET_FRAME_TIMELINE_INFO: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> binder; - status_t err = data.readStrongBinder(&binder); - if (err != NO_ERROR) { - ALOGE("setFrameTimelineInfo: failed to read strong binder: %s (%d)", strerror(-err), - -err); - return err; - } - sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder); - if (!surface) { - ALOGE("setFrameTimelineInfo: failed to cast to IGraphicBufferProducer: %s (%d)", - strerror(-err), -err); - return err; - } - - FrameTimelineInfo frameTimelineInfo; - SAFE_PARCEL(frameTimelineInfo.read, data); - - status_t result = setFrameTimelineInfo(surface, frameTimelineInfo); - reply->writeInt32(result); - return NO_ERROR; - } - case ADD_TRANSACTION_TRACE_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<gui::ITransactionTraceListener> listener; - SAFE_PARCEL(data.readStrongBinder, &listener); - - return addTransactionTraceListener(listener); - } - case GET_GPU_CONTEXT_PRIORITY: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int priority = getGPUContextPriority(); - SAFE_PARCEL(reply->writeInt32, priority); - return NO_ERROR; - } - case GET_MAX_ACQUIRED_BUFFER_COUNT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int buffers = 0; - int err = getMaxAcquiredBufferCount(&buffers); - if (err != NO_ERROR) { - return err; - } - SAFE_PARCEL(reply->writeInt32, buffers); - return NO_ERROR; - } - case OVERRIDE_HDR_TYPES: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> display = nullptr; - SAFE_PARCEL(data.readStrongBinder, &display); - - std::vector<int32_t> hdrTypes; - SAFE_PARCEL(data.readInt32Vector, &hdrTypes); - - std::vector<ui::Hdr> hdrTypesVector; - for (int i : hdrTypes) { - hdrTypesVector.push_back(static_cast<ui::Hdr>(i)); - } - return overrideHdrTypes(display, hdrTypesVector); - } - case ON_PULL_ATOM: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int32_t atomId = 0; - SAFE_PARCEL(data.readInt32, &atomId); - - std::string pulledData; - bool success; - status_t err = onPullAtom(atomId, &pulledData, &success); - SAFE_PARCEL(reply->writeByteArray, pulledData.size(), - reinterpret_cast<const uint8_t*>(pulledData.data())); - SAFE_PARCEL(reply->writeBool, success); - return err; - } - case ADD_WINDOW_INFOS_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IWindowInfosListener> listener; - SAFE_PARCEL(data.readStrongBinder, &listener); - - return addWindowInfosListener(listener); - } - case REMOVE_WINDOW_INFOS_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IWindowInfosListener> listener; - SAFE_PARCEL(data.readStrongBinder, &listener); - - return removeWindowInfosListener(listener); - } - case SET_OVERRIDE_FRAME_RATE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - uid_t uid; - SAFE_PARCEL(data.readUint32, &uid); - - float frameRate; - SAFE_PARCEL(data.readFloat, &frameRate); - - return setOverrideFrameRate(uid, frameRate); - } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp deleted file mode 100644 index 5e7a7ec67b..0000000000 --- a/libs/gui/ISurfaceComposerClient.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -// tag as surfaceflinger -#define LOG_TAG "SurfaceFlinger" - -#include <gui/ISurfaceComposerClient.h> - -#include <gui/IGraphicBufferProducer.h> - -#include <binder/SafeInterface.h> - -#include <ui/FrameStats.h> - -namespace android { - -namespace { // Anonymous - -enum class Tag : uint32_t { - CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, - CREATE_WITH_SURFACE_PARENT, - CLEAR_LAYER_FRAME_STATS, - GET_LAYER_FRAME_STATS, - MIRROR_SURFACE, - LAST = MIRROR_SURFACE, -}; - -} // Anonymous namespace - -class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> { -public: - explicit BpSurfaceComposerClient(const sp<IBinder>& impl) - : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {} - - ~BpSurfaceComposerClient() override; - - status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata, - sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, - int32_t* outLayerId, uint32_t* outTransformHint) override { - return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE, - name, width, height, - format, flags, parent, - std::move(metadata), - handle, gbp, outLayerId, - outTransformHint); - } - - status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height, - PixelFormat format, uint32_t flags, - const sp<IGraphicBufferProducer>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) override { - return callRemote<decltype( - &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT, - name, width, height, format, - flags, parent, - std::move(metadata), handle, gbp, - outLayerId, outTransformHint); - } - - status_t clearLayerFrameStats(const sp<IBinder>& handle) const override { - return callRemote<decltype( - &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::CLEAR_LAYER_FRAME_STATS, - handle); - } - - status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override { - return callRemote<decltype( - &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle, - outStats); - } - - status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle, - int32_t* outLayerId) override { - return callRemote<decltype(&ISurfaceComposerClient::mirrorSurface)>(Tag::MIRROR_SURFACE, - mirrorFromHandle, - outHandle, outLayerId); - } -}; - -// Out-of-line virtual method definition to trigger vtable emission in this -// translation unit (see clang warning -Wweak-vtables) -BpSurfaceComposerClient::~BpSurfaceComposerClient() {} - -IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); - -// ---------------------------------------------------------------------- - -status_t BnSurfaceComposerClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { - if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) { - return BBinder::onTransact(code, data, reply, flags); - } - auto tag = static_cast<Tag>(code); - 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: - return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats); - case Tag::MIRROR_SURFACE: - return callLocal(data, reply, &ISurfaceComposerClient::mirrorSurface); - } -} - -} // namespace android diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp index ea5fb293a6..15b2221464 100644 --- a/libs/gui/LayerDebugInfo.cpp +++ b/libs/gui/LayerDebugInfo.cpp @@ -27,7 +27,7 @@ using android::base::StringAppendF; #define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false) -namespace android { +namespace android::gui { status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { RETURN_ON_ERROR(parcel->writeCString(mName.c_str())); @@ -149,4 +149,4 @@ std::string to_string(const LayerDebugInfo& info) { return result; } -} // android +} // namespace android::gui diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp index 189d51a4c1..4e12fd330c 100644 --- a/libs/gui/LayerMetadata.cpp +++ b/libs/gui/LayerMetadata.cpp @@ -23,7 +23,7 @@ using android::base::StringPrintf; -namespace android { +namespace android::gui { LayerMetadata::LayerMetadata() = default; @@ -144,4 +144,4 @@ std::string LayerMetadata::itemToString(uint32_t key, const char* separator) con } } -} // namespace android +} // namespace android::gui diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 502031c8d8..4d5978ccf7 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -19,10 +19,10 @@ #include <cinttypes> #include <cmath> +#include <android/gui/ISurfaceComposerClient.h> #include <android/native_window.h> #include <binder/Parcel.h> #include <gui/IGraphicBufferProducer.h> -#include <gui/ISurfaceComposerClient.h> #include <gui/LayerState.h> #include <private/gui/ParcelUtils.h> #include <system/window.h> @@ -40,8 +40,6 @@ layer_state_t::layer_state_t() x(0), y(0), z(0), - w(0), - h(0), alpha(0), flags(0), mask(0), @@ -63,9 +61,11 @@ layer_state_t::layer_state_t() frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), + defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), isTrustedOverlay(false), + borderEnabled(false), bufferCrop(Rect::INVALID_RECT), destinationFrame(Rect::INVALID_RECT), dropInputMode(gui::DropInputMode::NONE) { @@ -82,8 +82,6 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, x); SAFE_PARCEL(output.writeFloat, y); SAFE_PARCEL(output.writeInt32, z); - SAFE_PARCEL(output.writeUint32, w); - SAFE_PARCEL(output.writeUint32, h); SAFE_PARCEL(output.writeUint32, layerStack.id); SAFE_PARCEL(output.writeFloat, alpha); SAFE_PARCEL(output.writeUint32, flags); @@ -100,7 +98,12 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, transparentRegion); SAFE_PARCEL(output.writeUint32, transform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); - + SAFE_PARCEL(output.writeBool, borderEnabled); + SAFE_PARCEL(output.writeFloat, borderWidth); + SAFE_PARCEL(output.writeFloat, borderColor.r); + SAFE_PARCEL(output.writeFloat, borderColor.g); + SAFE_PARCEL(output.writeFloat, borderColor.b); + SAFE_PARCEL(output.writeFloat, borderColor.a); SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dataspace)); SAFE_PARCEL(output.write, hdrMetadata); SAFE_PARCEL(output.write, surfaceDamageRegion); @@ -131,6 +134,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); + SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeBool, dimmingEnabled); @@ -172,8 +176,6 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readFloat, &x); SAFE_PARCEL(input.readFloat, &y); SAFE_PARCEL(input.readInt32, &z); - SAFE_PARCEL(input.readUint32, &w); - SAFE_PARCEL(input.readUint32, &h); SAFE_PARCEL(input.readUint32, &layerStack.id); SAFE_PARCEL(input.readFloat, &alpha); @@ -200,6 +202,17 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, transparentRegion); SAFE_PARCEL(input.readUint32, &transform); SAFE_PARCEL(input.readBool, &transformToDisplayInverse); + SAFE_PARCEL(input.readBool, &borderEnabled); + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderWidth = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.r = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.g = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.b = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.a = tmpFloat; uint32_t tmpUint32 = 0; SAFE_PARCEL(input.readUint32, &tmpUint32); @@ -240,6 +253,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readFloat, &frameRate); SAFE_PARCEL(input.readByte, &frameRateCompatibility); SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); + SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32); SAFE_PARCEL(input.readBool, &autoRefresh); @@ -437,11 +451,6 @@ void layer_state_t::merge(const layer_state_t& other) { what &= ~eRelativeLayerChanged; z = other.z; } - if (other.what & eSizeChanged) { - what |= eSizeChanged; - w = other.w; - h = other.h; - } if (other.what & eAlphaChanged) { what |= eAlphaChanged; alpha = other.alpha; @@ -550,6 +559,16 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eShadowRadiusChanged; shadowRadius = other.shadowRadius; } + if (other.what & eRenderBorderChanged) { + what |= eRenderBorderChanged; + borderEnabled = other.borderEnabled; + borderWidth = other.borderWidth; + borderColor = other.borderColor; + } + if (other.what & eDefaultFrameRateCompatibilityChanged) { + what |= eDefaultFrameRateCompatibilityChanged; + defaultFrameRateCompatibility = other.defaultFrameRateCompatibility; + } if (other.what & eFrameRateSelectionPriority) { what |= eFrameRateSelectionPriority; frameRateSelectionPriority = other.frameRateSelectionPriority; @@ -641,29 +660,44 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { changes |= !other.focusRequests.empty(); focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()), std::make_move_iterator(other.focusRequests.end())); - changes |= other.syncInputWindows && !syncInputWindows; - syncInputWindows |= other.syncInputWindows; + changes |= !other.windowInfosReportedListeners.empty(); + windowInfosReportedListeners.insert(other.windowInfosReportedListeners.begin(), + other.windowInfosReportedListeners.end()); return changes; } bool InputWindowCommands::empty() const { - return focusRequests.empty() && !syncInputWindows; + return focusRequests.empty() && windowInfosReportedListeners.empty(); } void InputWindowCommands::clear() { focusRequests.clear(); - syncInputWindows = false; + windowInfosReportedListeners.clear(); } status_t InputWindowCommands::write(Parcel& output) const { SAFE_PARCEL(output.writeParcelableVector, focusRequests); - SAFE_PARCEL(output.writeBool, syncInputWindows); + + SAFE_PARCEL(output.writeInt32, windowInfosReportedListeners.size()); + for (const auto& listener : windowInfosReportedListeners) { + SAFE_PARCEL(output.writeStrongBinder, listener); + } + return NO_ERROR; } status_t InputWindowCommands::read(const Parcel& input) { SAFE_PARCEL(input.readParcelableVector, &focusRequests); - SAFE_PARCEL(input.readBool, &syncInputWindows); + + int listenerSize = 0; + SAFE_PARCEL_READ_SIZE(input.readInt32, &listenerSize, input.dataSize()); + windowInfosReportedListeners.reserve(listenerSize); + for (int i = 0; i < listenerSize; i++) { + sp<gui::IWindowInfosReportedListener> listener; + SAFE_PARCEL(input.readStrongBinder, &listener); + windowInfosReportedListeners.insert(listener); + } + return NO_ERROR; } diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp index fe387064bc..601a5f9b33 100644 --- a/libs/gui/ScreenCaptureResults.cpp +++ b/libs/gui/ScreenCaptureResults.cpp @@ -17,6 +17,7 @@ #include <gui/ScreenCaptureResults.h> #include <private/gui/ParcelUtils.h> +#include <ui/FenceResult.h> namespace android::gui { @@ -28,17 +29,17 @@ status_t ScreenCaptureResults::writeToParcel(android::Parcel* parcel) const { SAFE_PARCEL(parcel->writeBool, false); } - if (fence != Fence::NO_FENCE) { + if (fenceResult.ok() && fenceResult.value() != Fence::NO_FENCE) { SAFE_PARCEL(parcel->writeBool, true); - SAFE_PARCEL(parcel->write, *fence); + SAFE_PARCEL(parcel->write, *fenceResult.value()); } else { SAFE_PARCEL(parcel->writeBool, false); + SAFE_PARCEL(parcel->writeInt32, fenceStatus(fenceResult)); } SAFE_PARCEL(parcel->writeBool, capturedSecureLayers); SAFE_PARCEL(parcel->writeBool, capturedHdrLayers); SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(capturedDataspace)); - SAFE_PARCEL(parcel->writeInt32, result); return NO_ERROR; } @@ -53,8 +54,13 @@ status_t ScreenCaptureResults::readFromParcel(const android::Parcel* parcel) { bool hasFence; SAFE_PARCEL(parcel->readBool, &hasFence); if (hasFence) { - fence = new Fence(); - SAFE_PARCEL(parcel->read, *fence); + fenceResult = sp<Fence>::make(); + SAFE_PARCEL(parcel->read, *fenceResult.value()); + } else { + status_t status; + SAFE_PARCEL(parcel->readInt32, &status); + fenceResult = status == NO_ERROR ? FenceResult(Fence::NO_FENCE) + : FenceResult(base::unexpected(status)); } SAFE_PARCEL(parcel->readBool, &capturedSecureLayers); @@ -62,7 +68,6 @@ status_t ScreenCaptureResults::readFromParcel(const android::Parcel* parcel) { uint32_t dataspace = 0; SAFE_PARCEL(parcel->readUint32, &dataspace); capturedDataspace = static_cast<ui::Dataspace>(dataspace); - SAFE_PARCEL(parcel->readInt32, &result); return NO_ERROR; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 6b544b2b96..4b4d46a92e 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -30,15 +30,17 @@ #include <android/gui/DisplayStatInfo.h> #include <android/native_window.h> +#include <gui/TraceUtils.h> #include <utils/Log.h> -#include <utils/Trace.h> #include <utils/NativeHandle.h> +#include <utils/Trace.h> #include <ui/DynamicDisplayInfo.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <ui/Region.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferItem.h> #include <gui/IProducerListener.h> @@ -49,6 +51,7 @@ namespace android { +using gui::aidl_utils::statusTFromBinderStatus; using ui::Dataspace; namespace { @@ -182,7 +185,7 @@ status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) { gui::DisplayStatInfo stats; binder::Status status = composerServiceAIDL()->getDisplayStats(nullptr, &stats); if (!status.isOk()) { - return status.transactionError(); + return statusTFromBinderStatus(status); } *outRefreshDuration = stats.vsyncPeriod; @@ -355,7 +358,7 @@ status_t Surface::getWideColorSupport(bool* supported) { *supported = false; binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t Surface::getHdrSupport(bool* supported) { @@ -366,12 +369,13 @@ status_t Surface::getHdrSupport(bool* supported) { return NAME_NOT_FOUND; } - ui::DynamicDisplayInfo info; - if (status_t err = composerService()->getDynamicDisplayInfo(display, &info); err != NO_ERROR) { - return err; + gui::DynamicDisplayInfo info; + if (binder::Status status = composerServiceAIDL()->getDynamicDisplayInfo(display, &info); + !status.isOk()) { + return statusTFromBinderStatus(status); } - *supported = !info.hdrCapabilities.getSupportedHdrTypes().empty(); + *supported = !info.hdrCapabilities.supportedHdrTypes.empty(); return NO_ERROR; } @@ -634,7 +638,7 @@ void Surface::getDequeueBufferInputLocked( } int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { - ATRACE_CALL(); + ATRACE_FORMAT("dequeueBuffer - %s", getDebugName()); ALOGV("Surface::dequeueBuffer"); IGraphicBufferProducer::DequeueBufferInput dqInput; @@ -1256,10 +1260,10 @@ void Surface::querySupportedTimestampsLocked() const { mQueriedSupportedTimestamps = true; std::vector<FrameEvent> supportedFrameTimestamps; - status_t err = composerService()->getSupportedFrameTimestamps( - &supportedFrameTimestamps); + binder::Status status = + composerServiceAIDL()->getSupportedFrameTimestamps(&supportedFrameTimestamps); - if (err != NO_ERROR) { + if (!status.isOk()) { return; } @@ -1287,15 +1291,12 @@ int Surface::query(int what, int* value) const { if (err == NO_ERROR) { return NO_ERROR; } - sp<ISurfaceComposer> surfaceComposer = composerService(); + sp<gui::ISurfaceComposer> surfaceComposer = composerServiceAIDL(); if (surfaceComposer == nullptr) { return -EPERM; // likely permissions error } - if (surfaceComposer->authenticateSurfaceTexture(mGraphicBufferProducer)) { - *value = 1; - } else { - *value = 0; - } + // ISurfaceComposer no longer supports authenticateSurfaceTexture + *value = 0; return NO_ERROR; } case NATIVE_WINDOW_CONCRETE_TYPE: @@ -1867,7 +1868,11 @@ int Surface::dispatchSetFrameTimelineInfo(va_list args) { auto startTimeNanos = static_cast<int64_t>(va_arg(args, int64_t)); ALOGV("Surface::%s", __func__); - return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId, startTimeNanos}); + FrameTimelineInfo ftlInfo; + ftlInfo.vsyncId = frameTimelineVsyncId; + ftlInfo.inputEventId = inputEventId; + ftlInfo.startTimeNanos = startTimeNanos; + return setFrameTimelineInfo(ftlInfo); } bool Surface::transformToDisplayInverse() const { @@ -2624,22 +2629,18 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_ mSurfaceListener->onBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate, int8_t compatibility, - int8_t changeFrameRateStrategy) { - ATRACE_CALL(); - ALOGV("Surface::setFrameRate"); - - if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, - "Surface::setFrameRate")) { - return BAD_VALUE; - } - - return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility, - changeFrameRateStrategy); +[[deprecated]] status_t Surface::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/, + int8_t /*changeFrameRateStrategy*/) { + ALOGI("Surface::setFrameRate is deprecated, setFrameRate hint is dropped as destination is not " + "SurfaceFlinger"); + // ISurfaceComposer no longer supports setFrameRate, we will return NO_ERROR when the api is + // called to avoid apps crashing, as BAD_VALUE can generate fatal exception in apps. + return NO_ERROR; } -status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { - return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); +status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& /*frameTimelineInfo*/) { + // ISurfaceComposer no longer supports setFrameTimelineInfo + return BAD_VALUE; } sp<IBinder> Surface::getSurfaceControlHandle() const { @@ -2652,4 +2653,12 @@ void Surface::destroy() { mSurfaceControlHandle = nullptr; } +const char* Surface::getDebugName() { + std::unique_lock lock{mNameMutex}; + if (mName.empty()) { + mName = getConsumerName(); + } + return mName.c_str(); +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 9358e29030..72bd1fb675 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -19,8 +19,11 @@ #include <stdint.h> #include <sys/types.h> +#include <android/gui/BnWindowInfosReportedListener.h> #include <android/gui/DisplayState.h> +#include <android/gui/ISurfaceComposerClient.h> #include <android/gui/IWindowInfosListener.h> +#include <android/os/IInputConstants.h> #include <utils/Errors.h> #include <utils/Log.h> #include <utils/SortedVector.h> @@ -33,11 +36,11 @@ #include <system/graphics.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferItemConsumer.h> #include <gui/CpuConsumer.h> #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> -#include <gui/ISurfaceComposerClient.h> #include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> @@ -61,6 +64,7 @@ using gui::IRegionSamplingListener; using gui::WindowInfo; using gui::WindowInfoHandle; using gui::WindowInfosListener; +using gui::aidl_utils::statusTFromBinderStatus; using ui::ColorMode; // --------------------------------------------------------------------------- @@ -111,7 +115,6 @@ bool ComposerService::connectLocked() { if (instance.mComposerService == nullptr) { if (ComposerService::getInstance().connectLocked()) { ALOGD("ComposerService reconnected"); - WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService); } } return instance.mComposerService; @@ -159,6 +162,7 @@ bool ComposerServiceAIDL::connectLocked() { if (instance.mComposerService == nullptr) { if (ComposerServiceAIDL::getInstance().connectLocked()) { ALOGD("ComposerServiceAIDL reconnected"); + WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService); } } return instance.mComposerService; @@ -623,12 +627,11 @@ SurfaceComposerClient::Transaction::Transaction() { SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : mId(other.mId), - mForceSynchronous(other.mForceSynchronous), mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mEarlyWakeupStart(other.mEarlyWakeupStart), mEarlyWakeupEnd(other.mEarlyWakeupEnd), - mContainsBuffer(other.mContainsBuffer), + mMayContainBuffer(other.mMayContainBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), mFrameTimelineInfo(other.mFrameTimelineInfo), @@ -657,16 +660,15 @@ SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { - const uint32_t forceSynchronous = parcel->readUint32(); + const uint64_t transactionId = parcel->readUint64(); const uint32_t transactionNestCount = parcel->readUint32(); const bool animation = parcel->readBool(); const bool earlyWakeupStart = parcel->readBool(); const bool earlyWakeupEnd = parcel->readBool(); - const bool containsBuffer = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); FrameTimelineInfo frameTimelineInfo; - SAFE_PARCEL(frameTimelineInfo.read, *parcel); + frameTimelineInfo.readFromParcel(parcel); sp<IBinder> applyToken; parcel->readNullableStrongBinder(&applyToken); @@ -734,12 +736,11 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel inputWindowCommands.read(*parcel); // Parsing was successful. Update the object. - mForceSynchronous = forceSynchronous; + mId = transactionId; mTransactionNestCount = transactionNestCount; mAnimation = animation; mEarlyWakeupStart = earlyWakeupStart; mEarlyWakeupEnd = earlyWakeupEnd; - mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; mIsAutoTimestamp = isAutoTimestamp; mFrameTimelineInfo = frameTimelineInfo; @@ -765,15 +766,14 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers(); - parcel->writeUint32(mForceSynchronous); + parcel->writeUint64(mId); parcel->writeUint32(mTransactionNestCount); parcel->writeBool(mAnimation); parcel->writeBool(mEarlyWakeupStart); parcel->writeBool(mEarlyWakeupEnd); - parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); - SAFE_PARCEL(mFrameTimelineInfo.write, *parcel); + mFrameTimelineInfo.writeToParcel(parcel); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { @@ -869,12 +869,12 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mInputWindowCommands.merge(other.mInputWindowCommands); - mContainsBuffer |= other.mContainsBuffer; + mMayContainBuffer |= other.mMayContainBuffer; mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart; mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd; mApplyToken = other.mApplyToken; - mFrameTimelineInfo.merge(other.mFrameTimelineInfo); + mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo); other.clear(); return *this; @@ -885,15 +885,14 @@ void SurfaceComposerClient::Transaction::clear() { mDisplayStates.clear(); mListenerCallbacks.clear(); mInputWindowCommands.clear(); - mContainsBuffer = false; - mForceSynchronous = 0; + mMayContainBuffer = false; mTransactionNestCount = 0; mAnimation = false; mEarlyWakeupStart = false; mEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; - mFrameTimelineInfo.clear(); + clearFrameTimelineInfo(mFrameTimelineInfo); mApplyToken = nullptr; } @@ -908,13 +907,13 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { uncacheBuffer.token = BufferCache::getInstance().getToken(); uncacheBuffer.id = cacheId; - sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(FrameTimelineInfo{}, {}, {}, 0, applyToken, {}, systemTime(), true, + sf->setTransactionState(FrameTimelineInfo{}, {}, {}, ISurfaceComposer::eOneWay, + Transaction::getDefaultApplyToken(), {}, systemTime(), true, uncacheBuffer, false, {}, generateId()); } void SurfaceComposerClient::Transaction::cacheBuffers() { - if (!mContainsBuffer) { + if (!mMayContainBuffer) { return; } @@ -999,27 +998,25 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay Vector<DisplayState> displayStates; uint32_t flags = 0; - mForceSynchronous |= synchronous; - for (auto const& kv : mComposerStates){ composerStates.add(kv.second); } displayStates = std::move(mDisplayStates); - if (mForceSynchronous) { + if (synchronous) { flags |= ISurfaceComposer::eSynchronous; } if (mAnimation) { flags |= ISurfaceComposer::eAnimation; } if (oneWay) { - if (mForceSynchronous) { - ALOGE("Transaction attempted to set synchronous and one way at the same time" - " this is an invalid request. Synchronous will win for safety"); - } else { - flags |= ISurfaceComposer::eOneWay; - } + if (synchronous) { + ALOGE("Transaction attempted to set synchronous and one way at the same time" + " this is an invalid request. Synchronous will win for safety"); + } else { + flags |= ISurfaceComposer::eOneWay; + } } // If both mEarlyWakeupStart and mEarlyWakeupEnd are set @@ -1031,9 +1028,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay flags |= ISurfaceComposer::eEarlyWakeupEnd; } - sp<IBinder> applyToken = mApplyToken - ? mApplyToken - : IInterface::asBinder(TransactionCompletedListener::getIInstance()); + sp<IBinder> applyToken = mApplyToken ? mApplyToken : sApplyToken; sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, @@ -1048,6 +1043,15 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay return NO_ERROR; } +sp<IBinder> SurfaceComposerClient::Transaction::sApplyToken = new BBinder(); + +sp<IBinder> SurfaceComposerClient::Transaction::getDefaultApplyToken() { + return sApplyToken; +} + +void SurfaceComposerClient::Transaction::setDefaultApplyToken(sp<IBinder> applyToken) { + sApplyToken = applyToken; +} // --------------------------------------------------------------------------- sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) { @@ -1078,16 +1082,6 @@ std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() { return physicalDisplayIds; } -status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) { - int64_t displayId; - binder::Status status = - ComposerServiceAIDL::getComposerService()->getPrimaryPhysicalDisplayId(&displayId); - if (status.isOk()) { - *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId)); - } - return status.transactionError(); -} - std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() { ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance(); return instance.getInternalDisplayId(); @@ -1168,21 +1162,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide( return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize( - const sp<SurfaceControl>& sc, uint32_t w, uint32_t h) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eSizeChanged; - s->w = w; - s->h = h; - - registerSurfaceControlForCallback(sc); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer( const sp<SurfaceControl>& sc, int32_t z) { layer_state_t* s = getLayerState(sc); @@ -1272,8 +1251,11 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha mStatus = BAD_INDEX; return *this; } + if (alpha < 0.0f || alpha > 1.0f) { + ALOGE("SurfaceComposerClient::Transaction::setAlpha: invalid alpha %f, clamping", alpha); + } s->what |= layer_state_t::eAlphaChanged; - s->alpha = alpha; + s->alpha = std::clamp(alpha, 0.f, 1.f); registerSurfaceControlForCallback(sc); return *this; @@ -1473,7 +1455,6 @@ std::shared_ptr<BufferData> SurfaceComposerClient::Transaction::getAndClearBuffe s->what &= ~layer_state_t::eBufferChanged; s->bufferData = nullptr; - mContainsBuffer = false; return bufferData; } @@ -1504,7 +1485,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe if (buffer == nullptr) { s->what &= ~layer_state_t::eBufferChanged; s->bufferData = nullptr; - mContainsBuffer = false; return *this; } @@ -1539,7 +1519,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe const std::vector<SurfaceControlStats>&) {}, nullptr); - mContainsBuffer = true; + mMayContainBuffer = true; return *this; } @@ -1727,8 +1707,10 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocus return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() { - mInputWindowCommands.syncInputWindows = true; +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::addWindowInfosReportedListener( + sp<gui::IWindowInfosReportedListener> windowInfosReportedListener) { + mInputWindowCommands.windowInfosReportedListeners.insert(windowInfosReportedListener); return *this; } @@ -1835,6 +1817,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp<SurfaceControl>& sc, + int8_t compatibility) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eDefaultFrameRateCompatibilityChanged; + s->defaultFrameRateCompatibility = compatibility; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( const sp<SurfaceControl>& sc, int32_t fixedTransformHint) { layer_state_t* s = getLayerState(sc); @@ -1853,7 +1848,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( const FrameTimelineInfo& frameTimelineInfo) { - mFrameTimelineInfo.merge(frameTimelineInfo); + mergeFrameTimelineInfo(mFrameTimelineInfo, frameTimelineInfo); return *this; } @@ -1947,6 +1942,23 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropI return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::enableBorder( + const sp<SurfaceControl>& sc, bool shouldEnable, float width, const half4& color) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eRenderBorderChanged; + s->borderEnabled = shouldEnable; + s->borderWidth = width; + s->borderColor = color; + + registerSurfaceControlForCallback(sc); + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) { @@ -2002,7 +2014,6 @@ void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& s.layerStackSpaceRect = layerStackRect; s.orientedDisplaySpaceRect = displayRect; s.what |= DisplayState::eDisplayProjectionChanged; - mForceSynchronous = true; // TODO: do we actually still need this? } void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) { @@ -2012,6 +2023,31 @@ void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token s.what |= DisplayState::eDisplaySizeChanged; } +// copied from FrameTimelineInfo::merge() +void SurfaceComposerClient::Transaction::mergeFrameTimelineInfo(FrameTimelineInfo& t, + const FrameTimelineInfo& other) { + // When merging vsync Ids we take the oldest valid one + if (t.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID && + other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + if (other.vsyncId > t.vsyncId) { + t.vsyncId = other.vsyncId; + t.inputEventId = other.inputEventId; + t.startTimeNanos = other.startTimeNanos; + } + } else if (t.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { + t.vsyncId = other.vsyncId; + t.inputEventId = other.inputEventId; + t.startTimeNanos = other.startTimeNanos; + } +} + +// copied from FrameTimelineInfo::clear() +void SurfaceComposerClient::Transaction::clearFrameTimelineInfo(FrameTimelineInfo& t) { + t.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID; + t.inputEventId = os::IInputConstants::INVALID_INPUT_EVENT_ID; + t.startTimeNanos = 0; +} + // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {} @@ -2020,11 +2056,11 @@ SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& c : mStatus(NO_ERROR), mClient(client) {} void SurfaceComposerClient::onFirstRef() { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); if (sf != nullptr && mStatus == NO_INIT) { sp<ISurfaceComposerClient> conn; - conn = sf->createConnection(); - if (conn != nullptr) { + binder::Status status = sf->createConnection(&conn); + if (status.isOk() && conn != nullptr) { mClient = conn; mStatus = NO_ERROR; } @@ -2062,7 +2098,7 @@ void SurfaceComposerClient::dispose() { } sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, + PixelFormat format, int32_t flags, const sp<IBinder>& parentHandle, LayerMetadata metadata, uint32_t* outTransformHint) { @@ -2072,38 +2108,9 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uin return s; } -sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w, - uint32_t h, PixelFormat format, - uint32_t flags, Surface* parent, - LayerMetadata metadata, - uint32_t* outTransformHint) { - sp<SurfaceControl> sur; - status_t err = mStatus; - - if (mStatus == NO_ERROR) { - sp<IBinder> handle; - sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer(); - sp<IGraphicBufferProducer> gbp; - - uint32_t transformHint = 0; - int32_t id = -1; - err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp, - std::move(metadata), &handle, &gbp, &id, - &transformHint); - if (outTransformHint) { - *outTransformHint = transformHint; - } - ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err)); - if (err == NO_ERROR) { - return new SurfaceControl(this, handle, gbp, id, transformHint); - } - } - return nullptr; -} - status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - sp<SurfaceControl>* outSurface, uint32_t flags, + sp<SurfaceControl>* outSurface, int32_t flags, const sp<IBinder>& parentHandle, LayerMetadata metadata, uint32_t* outTransformHint) { @@ -2111,21 +2118,17 @@ status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32 status_t err = mStatus; if (mStatus == NO_ERROR) { - sp<IBinder> handle; - sp<IGraphicBufferProducer> gbp; - - uint32_t transformHint = 0; - int32_t id = -1; - err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata), - &handle, &gbp, &id, &transformHint); - + gui::CreateSurfaceResult result; + binder::Status status = mClient->createSurface(std::string(name.string()), flags, + parentHandle, std::move(metadata), &result); + err = statusTFromBinderStatus(status); if (outTransformHint) { - *outTransformHint = transformHint; + *outTransformHint = result.transformHint; } ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - *outSurface = - new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint, flags); + *outSurface = new SurfaceControl(this, result.handle, result.layerId, w, h, format, + result.transformHint, flags); } } return err; @@ -2136,12 +2139,22 @@ sp<SurfaceControl> SurfaceComposerClient::mirrorSurface(SurfaceControl* mirrorFr return nullptr; } - sp<IBinder> handle; sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle(); - int32_t layer_id = -1; - status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle, &layer_id); + gui::MirrorSurfaceResult result; + const binder::Status status = mClient->mirrorSurface(mirrorFromHandle, &result); + const status_t err = statusTFromBinderStatus(status); if (err == NO_ERROR) { - return new SurfaceControl(this, handle, nullptr, layer_id, true /* owned */); + return new SurfaceControl(this, result.handle, result.layerId); + } + return nullptr; +} + +sp<SurfaceControl> SurfaceComposerClient::mirrorDisplay(DisplayId displayId) { + gui::MirrorSurfaceResult result; + const binder::Status status = mClient->mirrorDisplay(displayId.value, &result); + const status_t err = statusTFromBinderStatus(status); + if (err == NO_ERROR) { + return new SurfaceControl(this, result.handle, result.layerId); } return nullptr; } @@ -2150,7 +2163,8 @@ status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) c if (mStatus != NO_ERROR) { return mStatus; } - return mClient->clearLayerFrameStats(token); + const binder::Status status = mClient->clearLayerFrameStats(token); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token, @@ -2158,19 +2172,38 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token, if (mStatus != NO_ERROR) { return mStatus; } - return mClient->getLayerFrameStats(token, outStats); + gui::FrameStats stats; + const binder::Status status = mClient->getLayerFrameStats(token, &stats); + if (status.isOk()) { + outStats->refreshPeriodNano = stats.refreshPeriodNano; + outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size()); + for (const auto& t : stats.desiredPresentTimesNano) { + outStats->desiredPresentTimesNano.add(t); + } + outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size()); + for (const auto& t : stats.actualPresentTimesNano) { + outStats->actualPresentTimesNano.add(t); + } + outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size()); + for (const auto& t : stats.frameReadyTimesNano) { + outStats->frameReadyTimesNano.add(t); + } + } + return statusTFromBinderStatus(status); } // ---------------------------------------------------------------------------- status_t SurfaceComposerClient::enableVSyncInjections(bool enable) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - return sf->enableVSyncInjections(enable); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); + binder::Status status = sf->enableVSyncInjections(enable); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::injectVSync(nsecs_t when) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - return sf->injectVSync(when); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); + binder::Status status = sf->injectVSync(when); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display, @@ -2184,17 +2217,106 @@ status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display, state->layerStackSpaceRect = ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height); } - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display, - ui::StaticDisplayInfo* info) { - return ComposerService::getComposerService()->getStaticDisplayInfo(display, info); + ui::StaticDisplayInfo* outInfo) { + using Tag = android::gui::DeviceProductInfo::ManufactureOrModelDate::Tag; + gui::StaticDisplayInfo ginfo; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getStaticDisplayInfo(display, &ginfo); + if (status.isOk()) { + // convert gui::StaticDisplayInfo to ui::StaticDisplayInfo + outInfo->connectionType = static_cast<ui::DisplayConnectionType>(ginfo.connectionType); + outInfo->density = ginfo.density; + outInfo->secure = ginfo.secure; + outInfo->installOrientation = static_cast<ui::Rotation>(ginfo.installOrientation); + + DeviceProductInfo info; + std::optional<gui::DeviceProductInfo> dpi = ginfo.deviceProductInfo; + gui::DeviceProductInfo::ManufactureOrModelDate& date = dpi->manufactureOrModelDate; + info.name = dpi->name; + if (dpi->manufacturerPnpId.size() > 0) { + // copid from PnpId = std::array<char, 4> in ui/DeviceProductInfo.h + constexpr int kMaxPnpIdSize = 4; + size_t count = std::max<size_t>(kMaxPnpIdSize, dpi->manufacturerPnpId.size()); + std::copy_n(dpi->manufacturerPnpId.begin(), count, info.manufacturerPnpId.begin()); + } + if (dpi->relativeAddress.size() > 0) { + std::copy(dpi->relativeAddress.begin(), dpi->relativeAddress.end(), + std::back_inserter(info.relativeAddress)); + } + info.productId = dpi->productId; + if (date.getTag() == Tag::modelYear) { + DeviceProductInfo::ModelYear modelYear; + modelYear.year = static_cast<uint32_t>(date.get<Tag::modelYear>().year); + info.manufactureOrModelDate = modelYear; + } else if (date.getTag() == Tag::manufactureYear) { + DeviceProductInfo::ManufactureYear manufactureYear; + manufactureYear.year = date.get<Tag::manufactureYear>().modelYear.year; + info.manufactureOrModelDate = manufactureYear; + } else if (date.getTag() == Tag::manufactureWeekAndYear) { + DeviceProductInfo::ManufactureWeekAndYear weekAndYear; + weekAndYear.year = + date.get<Tag::manufactureWeekAndYear>().manufactureYear.modelYear.year; + weekAndYear.week = date.get<Tag::manufactureWeekAndYear>().week; + info.manufactureOrModelDate = weekAndYear; + } + + outInfo->deviceProductInfo = info; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp<IBinder>& display, - ui::DynamicDisplayInfo* info) { - return ComposerService::getComposerService()->getDynamicDisplayInfo(display, info); + ui::DynamicDisplayInfo* outInfo) { + gui::DynamicDisplayInfo ginfo; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfo(display, &ginfo); + if (status.isOk()) { + // convert gui::DynamicDisplayInfo to ui::DynamicDisplayInfo + outInfo->supportedDisplayModes.clear(); + outInfo->supportedDisplayModes.reserve(ginfo.supportedDisplayModes.size()); + for (const auto& mode : ginfo.supportedDisplayModes) { + ui::DisplayMode outMode; + outMode.id = mode.id; + outMode.resolution.width = mode.resolution.width; + outMode.resolution.height = mode.resolution.height; + outMode.xDpi = mode.xDpi; + outMode.yDpi = mode.yDpi; + outMode.refreshRate = mode.refreshRate; + outMode.appVsyncOffset = mode.appVsyncOffset; + outMode.sfVsyncOffset = mode.sfVsyncOffset; + outMode.presentationDeadline = mode.presentationDeadline; + outMode.group = mode.group; + outInfo->supportedDisplayModes.push_back(outMode); + } + + outInfo->activeDisplayModeId = ginfo.activeDisplayModeId; + + outInfo->supportedColorModes.clear(); + outInfo->supportedColorModes.reserve(ginfo.supportedColorModes.size()); + for (const auto& cmode : ginfo.supportedColorModes) { + outInfo->supportedColorModes.push_back(static_cast<ui::ColorMode>(cmode)); + } + + outInfo->activeColorMode = static_cast<ui::ColorMode>(ginfo.activeColorMode); + + std::vector<ui::Hdr> types; + types.reserve(ginfo.hdrCapabilities.supportedHdrTypes.size()); + for (const auto& hdr : ginfo.hdrCapabilities.supportedHdrTypes) { + types.push_back(static_cast<ui::Hdr>(hdr)); + } + outInfo->hdrCapabilities = HdrCapabilities(types, ginfo.hdrCapabilities.maxLuminance, + ginfo.hdrCapabilities.maxAverageLuminance, + ginfo.hdrCapabilities.minLuminance); + + outInfo->autoLowLatencyModeSupported = ginfo.autoLowLatencyModeSupported; + outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported; + outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getActiveDisplayMode(const sp<IBinder>& display, @@ -2218,10 +2340,13 @@ status_t SurfaceComposerClient::setDesiredDisplayModeSpecs( const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, float appRequestRefreshRateMax) { - return ComposerService::getComposerService() - ->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, - primaryRefreshRateMin, primaryRefreshRateMax, - appRequestRefreshRateMin, appRequestRefreshRateMax); + binder::Status status = + ComposerServiceAIDL::getComposerService() + ->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, + primaryRefreshRateMin, primaryRefreshRateMax, + appRequestRefreshRateMin, + appRequestRefreshRateMax); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, @@ -2231,41 +2356,81 @@ status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp<IBinder>& di float* outPrimaryRefreshRateMax, float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) { - return ComposerService::getComposerService() - ->getDesiredDisplayModeSpecs(displayToken, outDefaultMode, outAllowGroupSwitching, - outPrimaryRefreshRateMin, outPrimaryRefreshRateMax, - outAppRequestRefreshRateMin, outAppRequestRefreshRateMax); + if (!outDefaultMode || !outAllowGroupSwitching || !outPrimaryRefreshRateMin || + !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { + return BAD_VALUE; + } + gui::DisplayModeSpecs specs; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDesiredDisplayModeSpecs(displayToken, + &specs); + if (status.isOk()) { + *outDefaultMode = specs.defaultMode; + *outAllowGroupSwitching = specs.allowGroupSwitching; + *outPrimaryRefreshRateMin = specs.primaryRefreshRateMin; + *outPrimaryRefreshRateMax = specs.primaryRefreshRateMax; + *outAppRequestRefreshRateMin = specs.appRequestRefreshRateMin; + *outAppRequestRefreshRateMax = specs.appRequestRefreshRateMax; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp<IBinder>& display, ui::DisplayPrimaries& outPrimaries) { - return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries); + gui::DisplayPrimaries primaries; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDisplayNativePrimaries(display, + &primaries); + if (status.isOk()) { + outPrimaries.red.X = primaries.red.X; + outPrimaries.red.Y = primaries.red.Y; + outPrimaries.red.Z = primaries.red.Z; + + outPrimaries.green.X = primaries.green.X; + outPrimaries.green.Y = primaries.green.Y; + outPrimaries.green.Z = primaries.green.Z; + + outPrimaries.blue.X = primaries.blue.X; + outPrimaries.blue.Y = primaries.blue.Y; + outPrimaries.blue.Z = primaries.blue.Z; + + outPrimaries.white.X = primaries.white.X; + outPrimaries.white.Y = primaries.white.Y; + outPrimaries.white.Z = primaries.white.Z; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) { - return ComposerService::getComposerService()->setActiveColorMode(display, colorMode); + binder::Status status = ComposerServiceAIDL::getComposerService() + ->setActiveColorMode(display, static_cast<int>(colorMode)); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) { binder::Status status = ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId displayModeId) { - return ComposerService::getComposerService()->setBootDisplayMode(display, displayModeId); + binder::Status status = ComposerServiceAIDL::getComposerService() + ->setBootDisplayMode(display, static_cast<int>(displayModeId)); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) { binder::Status status = ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) { - return ComposerService::getComposerService()->setOverrideFrameRate(uid, frameRate); + binder::Status status = + ComposerServiceAIDL::getComposerService()->setOverrideFrameRate(uid, frameRate); + return statusTFromBinderStatus(status); } void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) { @@ -2284,57 +2449,137 @@ void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token, status_t SurfaceComposerClient::getCompositionPreference( ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat, ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) { - return ComposerService::getComposerService() - ->getCompositionPreference(defaultDataspace, defaultPixelFormat, - wideColorGamutDataspace, wideColorGamutPixelFormat); + gui::CompositionPreference pref; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getCompositionPreference(&pref); + if (status.isOk()) { + *defaultDataspace = static_cast<ui::Dataspace>(pref.defaultDataspace); + *defaultPixelFormat = static_cast<ui::PixelFormat>(pref.defaultPixelFormat); + *wideColorGamutDataspace = static_cast<ui::Dataspace>(pref.wideColorGamutDataspace); + *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(pref.wideColorGamutPixelFormat); + } + return statusTFromBinderStatus(status); } bool SurfaceComposerClient::getProtectedContentSupport() { bool supported = false; - ComposerService::getComposerService()->getProtectedContentSupport(&supported); + ComposerServiceAIDL::getComposerService()->getProtectedContentSupport(&supported); return supported; } status_t SurfaceComposerClient::clearAnimationFrameStats() { - return ComposerService::getComposerService()->clearAnimationFrameStats(); + binder::Status status = ComposerServiceAIDL::getComposerService()->clearAnimationFrameStats(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) { - return ComposerService::getComposerService()->getAnimationFrameStats(outStats); + gui::FrameStats stats; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getAnimationFrameStats(&stats); + if (status.isOk()) { + outStats->refreshPeriodNano = stats.refreshPeriodNano; + outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size()); + for (const auto& t : stats.desiredPresentTimesNano) { + outStats->desiredPresentTimesNano.add(t); + } + outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size()); + for (const auto& t : stats.actualPresentTimesNano) { + outStats->actualPresentTimesNano.add(t); + } + outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size()); + for (const auto& t : stats.frameReadyTimesNano) { + outStats->frameReadyTimesNano.add(t); + } + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::overrideHdrTypes(const sp<IBinder>& display, const std::vector<ui::Hdr>& hdrTypes) { - return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes); + std::vector<int32_t> hdrTypesVector; + hdrTypesVector.reserve(hdrTypes.size()); + for (auto t : hdrTypes) { + hdrTypesVector.push_back(static_cast<int32_t>(t)); + } + + binder::Status status = + ComposerServiceAIDL::getComposerService()->overrideHdrTypes(display, hdrTypesVector); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::onPullAtom(const int32_t atomId, std::string* outData, bool* success) { - return ComposerService::getComposerService()->onPullAtom(atomId, outData, success); + gui::PullAtomData pad; + binder::Status status = ComposerServiceAIDL::getComposerService()->onPullAtom(atomId, &pad); + if (status.isOk()) { + outData->assign((const char*)pad.data.data(), pad.data.size()); + *success = pad.success; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) { - return ComposerService::getComposerService() - ->getDisplayedContentSamplingAttributes(display, outFormat, outDataspace, - outComponentMask); + if (!outFormat || !outDataspace || !outComponentMask) { + return BAD_VALUE; + } + + gui::ContentSamplingAttributes attrs; + binder::Status status = ComposerServiceAIDL::getComposerService() + ->getDisplayedContentSamplingAttributes(display, &attrs); + if (status.isOk()) { + *outFormat = static_cast<ui::PixelFormat>(attrs.format); + *outDataspace = static_cast<ui::Dataspace>(attrs.dataspace); + *outComponentMask = static_cast<uint8_t>(attrs.componentMask); + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, uint8_t componentMask, uint64_t maxFrames) { - return ComposerService::getComposerService()->setDisplayContentSamplingEnabled(display, enable, - componentMask, - maxFrames); + binder::Status status = + ComposerServiceAIDL::getComposerService() + ->setDisplayContentSamplingEnabled(display, enable, + static_cast<int8_t>(componentMask), + static_cast<int64_t>(maxFrames)); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) { - return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames, - timestamp, outStats); + if (!outStats) { + return BAD_VALUE; + } + + gui::DisplayedFrameStats stats; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDisplayedContentSample(display, maxFrames, + timestamp, &stats); + if (status.isOk()) { + // convert gui::DisplayedFrameStats to ui::DisplayedFrameStats + outStats->numFrames = static_cast<uint64_t>(stats.numFrames); + outStats->component_0_sample.reserve(stats.component_0_sample.size()); + for (const auto& s : stats.component_0_sample) { + outStats->component_0_sample.push_back(static_cast<uint64_t>(s)); + } + outStats->component_1_sample.reserve(stats.component_1_sample.size()); + for (const auto& s : stats.component_1_sample) { + outStats->component_1_sample.push_back(static_cast<uint64_t>(s)); + } + outStats->component_2_sample.reserve(stats.component_2_sample.size()); + for (const auto& s : stats.component_2_sample) { + outStats->component_2_sample.push_back(static_cast<uint64_t>(s)); + } + outStats->component_3_sample.reserve(stats.component_3_sample.size()); + for (const auto& s : stats.component_3_sample) { + outStats->component_3_sample.push_back(static_cast<uint64_t>(s)); + } + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display, @@ -2342,39 +2587,55 @@ status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display, binder::Status status = ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display, outIsWideColorDisplay); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addRegionSamplingListener( const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, const sp<IRegionSamplingListener>& listener) { - return ComposerService::getComposerService()->addRegionSamplingListener(samplingArea, - stopLayerHandle, - listener); + gui::ARect rect; + rect.left = samplingArea.left; + rect.top = samplingArea.top; + rect.right = samplingArea.right; + rect.bottom = samplingArea.bottom; + binder::Status status = + ComposerServiceAIDL::getComposerService()->addRegionSamplingListener(rect, + stopLayerHandle, + listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeRegionSamplingListener( const sp<IRegionSamplingListener>& listener) { - return ComposerService::getComposerService()->removeRegionSamplingListener(listener); + binder::Status status = + ComposerServiceAIDL::getComposerService()->removeRegionSamplingListener(listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) { - return ComposerService::getComposerService()->addFpsListener(taskId, listener); + binder::Status status = + ComposerServiceAIDL::getComposerService()->addFpsListener(taskId, listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeFpsListener(const sp<gui::IFpsListener>& listener) { - return ComposerService::getComposerService()->removeFpsListener(listener); + binder::Status status = ComposerServiceAIDL::getComposerService()->removeFpsListener(listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addTunnelModeEnabledListener( const sp<gui::ITunnelModeEnabledListener>& listener) { - return ComposerService::getComposerService()->addTunnelModeEnabledListener(listener); + binder::Status status = + ComposerServiceAIDL::getComposerService()->addTunnelModeEnabledListener(listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeTunnelModeEnabledListener( const sp<gui::ITunnelModeEnabledListener>& listener) { - return ComposerService::getComposerService()->removeTunnelModeEnabledListener(listener); + binder::Status status = + ComposerServiceAIDL::getComposerService()->removeTunnelModeEnabledListener(listener); + return statusTFromBinderStatus(status); } bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) { @@ -2390,7 +2651,7 @@ status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayT binder::Status status = ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken, brightness); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addHdrLayerInfoListener( @@ -2398,7 +2659,7 @@ status_t SurfaceComposerClient::addHdrLayerInfoListener( binder::Status status = ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken, listener); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeHdrLayerInfoListener( @@ -2406,45 +2667,80 @@ status_t SurfaceComposerClient::removeHdrLayerInfoListener( binder::Status status = ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken, listener); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) { binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { - return ComposerService::getComposerService()->setGlobalShadowSettings(ambientColor, spotColor, - lightPosY, lightPosZ, - lightRadius); + gui::Color ambientColorG, spotColorG; + ambientColorG.r = ambientColor.r; + ambientColorG.g = ambientColor.g; + ambientColorG.b = ambientColor.b; + ambientColorG.a = ambientColor.a; + spotColorG.r = spotColor.r; + spotColorG.g = spotColor.g; + spotColorG.b = spotColor.b; + spotColorG.a = spotColor.a; + binder::Status status = + ComposerServiceAIDL::getComposerService()->setGlobalShadowSettings(ambientColorG, + spotColorG, + lightPosY, lightPosZ, + lightRadius); + return statusTFromBinderStatus(status); } std::optional<DisplayDecorationSupport> SurfaceComposerClient::getDisplayDecorationSupport( const sp<IBinder>& displayToken) { + std::optional<gui::DisplayDecorationSupport> gsupport; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDisplayDecorationSupport(displayToken, + &gsupport); std::optional<DisplayDecorationSupport> support; - ComposerService::getComposerService()->getDisplayDecorationSupport(displayToken, &support); + // TODO (b/241277093): Remove `false && ` once b/241278870 is fixed. + if (false && status.isOk() && gsupport.has_value()) { + support.emplace(DisplayDecorationSupport{ + .format = + static_cast<aidl::android::hardware::graphics::common::PixelFormat>( + gsupport->format), + .alphaInterpretation = + static_cast<aidl::android::hardware::graphics::common::AlphaInterpretation>( + gsupport->alphaInterpretation) + }); + } return support; } -int SurfaceComposerClient::getGPUContextPriority() { - return ComposerService::getComposerService()->getGPUContextPriority(); +int SurfaceComposerClient::getGpuContextPriority() { + int priority; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getGpuContextPriority(&priority); + if (!status.isOk()) { + status_t err = statusTFromBinderStatus(status); + ALOGE("getGpuContextPriority failed to read data: %s (%d)", strerror(-err), err); + return 0; + } + return priority; } status_t SurfaceComposerClient::addWindowInfosListener( const sp<WindowInfosListener>& windowInfosListener, std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) { return WindowInfosListenerReporter::getInstance() - ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService(), + ->addWindowInfosListener(windowInfosListener, ComposerServiceAIDL::getComposerService(), outInitialInfo); } status_t SurfaceComposerClient::removeWindowInfosListener( const sp<WindowInfosListener>& windowInfosListener) { return WindowInfosListenerReporter::getInstance() - ->removeWindowInfosListener(windowInfosListener, ComposerService::getComposerService()); + ->removeWindowInfosListener(windowInfosListener, + ComposerServiceAIDL::getComposerService()); } // ---------------------------------------------------------------------------- @@ -2455,7 +2751,7 @@ status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, if (s == nullptr) return NO_INIT; binder::Status status = s->captureDisplay(captureArgs, captureListener); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t ScreenshotClient::captureDisplay(DisplayId displayId, @@ -2464,7 +2760,7 @@ status_t ScreenshotClient::captureDisplay(DisplayId displayId, if (s == nullptr) return NO_INIT; binder::Status status = s->captureDisplayById(displayId.value, captureListener); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, @@ -2473,7 +2769,7 @@ status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, if (s == nullptr) return NO_INIT; binder::Status status = s->captureLayers(captureArgs, captureListener); - return status.transactionError(); + return statusTFromBinderStatus(status); } // --------------------------------------------------------------------------------- diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 654fb336fe..84257dee9b 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -49,12 +49,10 @@ namespace android { // ============================================================================ SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp, int32_t layerId, - uint32_t w, uint32_t h, PixelFormat format, uint32_t transform, - uint32_t flags) + int32_t layerId, uint32_t w, uint32_t h, PixelFormat format, + uint32_t transform, uint32_t flags) : mClient(client), mHandle(handle), - mGraphicBufferProducer(gbp), mLayerId(layerId), mTransformHint(transform), mWidth(w), @@ -65,7 +63,6 @@ SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) { mClient = other->mClient; mHandle = other->mHandle; - mGraphicBufferProducer = other->mGraphicBufferProducer; mTransformHint = other->mTransformHint; mLayerId = other->mLayerId; mWidth = other->mWidth; @@ -165,11 +162,11 @@ sp<Surface> SurfaceControl::createSurface() void SurfaceControl::updateDefaultBufferSize(uint32_t width, uint32_t height) { Mutex::Autolock _l(mLock); - mWidth = width; mHeight = height; + mWidth = width; + mHeight = height; if (mBbq) { mBbq->update(mBbqChild, width, height, mFormat); } - } sp<IBinder> SurfaceControl::getLayerStateHandle() const @@ -245,9 +242,7 @@ status_t SurfaceControl::readFromParcel(const Parcel& parcel, *outSurfaceControl = new SurfaceControl(new SurfaceComposerClient( interface_cast<ISurfaceComposerClient>(client)), - handle.get(), nullptr, layerId, - width, height, format, - transformHint); + handle.get(), layerId, width, height, format, transformHint); return NO_ERROR; } diff --git a/libs/gui/TransactionTracing.cpp b/libs/gui/TransactionTracing.cpp index eedc3df009..59450fb411 100644 --- a/libs/gui/TransactionTracing.cpp +++ b/libs/gui/TransactionTracing.cpp @@ -15,9 +15,9 @@ */ #include "gui/TransactionTracing.h" -#include "gui/ISurfaceComposer.h" +#include "android/gui/ISurfaceComposer.h" -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> namespace android { @@ -32,7 +32,7 @@ sp<TransactionTraceListener> TransactionTraceListener::getInstance() { if (sInstance == nullptr) { sInstance = new TransactionTraceListener; - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); sf->addTransactionTraceListener(sInstance); } @@ -50,4 +50,4 @@ bool TransactionTraceListener::isTracingEnabled() { return mTracingEnabled; } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 4e966d1393..804ce4fac0 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.isClone == isClone; + info.layoutParamsFlags == layoutParamsFlags; } status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { @@ -124,8 +124,7 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->write(touchableRegion) ?: parcel->writeBool(replaceTouchableRegionWithCrop) ?: parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?: - parcel->writeStrongBinder(windowToken) ?: - parcel->writeBool(isClone); + parcel->writeStrongBinder(windowToken); // clang-format on return status; } @@ -176,8 +175,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->read(touchableRegion) ?: parcel->readBool(&replaceTouchableRegionWithCrop) ?: parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?: - parcel->readNullableStrongBinder(&windowToken) ?: - parcel->readBool(&isClone); + parcel->readNullableStrongBinder(&windowToken); // clang-format on if (status != OK) { diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index cfc7dbc463..01e865da6a 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include <gui/ISurfaceComposer.h> +#include <android/gui/ISurfaceComposer.h> +#include <gui/AidlStatusUtil.h> #include <gui/WindowInfosListenerReporter.h> namespace android { @@ -23,6 +24,7 @@ using gui::DisplayInfo; using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; +using gui::aidl_utils::statusTFromBinderStatus; sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() { static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter; @@ -31,13 +33,14 @@ sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() { status_t WindowInfosListenerReporter::addWindowInfosListener( const sp<WindowInfosListener>& windowInfosListener, - const sp<ISurfaceComposer>& surfaceComposer, + const sp<gui::ISurfaceComposer>& surfaceComposer, std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) { status_t status = OK; { std::scoped_lock lock(mListenersMutex); if (mWindowInfosListeners.empty()) { - status = surfaceComposer->addWindowInfosListener(this); + binder::Status s = surfaceComposer->addWindowInfosListener(this); + status = statusTFromBinderStatus(s); } if (status == OK) { @@ -55,12 +58,13 @@ status_t WindowInfosListenerReporter::addWindowInfosListener( status_t WindowInfosListenerReporter::removeWindowInfosListener( const sp<WindowInfosListener>& windowInfosListener, - const sp<ISurfaceComposer>& surfaceComposer) { + const sp<gui::ISurfaceComposer>& surfaceComposer) { status_t status = OK; { std::scoped_lock lock(mListenersMutex); if (mWindowInfosListeners.size() == 1) { - status = surfaceComposer->removeWindowInfosListener(this); + binder::Status s = surfaceComposer->removeWindowInfosListener(this); + status = statusTFromBinderStatus(s); // Clear the last stored state since we're disabling updates and don't want to hold // stale values mLastWindowInfos.clear(); @@ -78,7 +82,8 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( binder::Status WindowInfosListenerReporter::onWindowInfosChanged( const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos, const sp<IWindowInfosReportedListener>& windowInfosReportedListener) { - std::unordered_set<sp<WindowInfosListener>, SpHash<WindowInfosListener>> windowInfosListeners; + std::unordered_set<sp<WindowInfosListener>, gui::SpHash<WindowInfosListener>> + windowInfosListeners; { std::scoped_lock lock(mListenersMutex); @@ -101,7 +106,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( return binder::Status::ok(); } -void WindowInfosListenerReporter::reconnect(const sp<ISurfaceComposer>& composerService) { +void WindowInfosListenerReporter::reconnect(const sp<gui::ISurfaceComposer>& composerService) { std::scoped_lock lock(mListenersMutex); if (!mWindowInfosListeners.empty()) { composerService->addWindowInfosListener(this); diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/ARect.aidl index 1b13761392..5785907a9c 100644 --- a/libs/gui/aidl/android/gui/Rect.aidl +++ b/libs/gui/aidl/android/gui/ARect.aidl @@ -20,7 +20,7 @@ package android.gui; // TODO(b/221473398): // use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl /** @hide */ -parcelable Rect { +parcelable ARect { /// Minimum X coordinate of the rectangle. int left; diff --git a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl b/libs/gui/aidl/android/gui/Color.aidl index e30e9072fc..12af066562 100644 --- a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl +++ b/libs/gui/aidl/android/gui/Color.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * 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. @@ -14,19 +14,12 @@ * limitations under the License. */ -package android.content.pm; +package android.gui; -/** - * This event is designed for notification to native code listener about - * any changes on a package including update, deletion and etc. - * - * @hide - */ -parcelable PackageChangeEvent { - @utf8InCpp String packageName; - long version; - long lastUpdateTimeMillis; - boolean newInstalled; - boolean dataRemoved; - boolean isDeleted; +/** @hide */ +parcelable Color { + float r; + float g; + float b; + float a; } diff --git a/libs/gui/aidl/android/gui/CompositionPreference.aidl b/libs/gui/aidl/android/gui/CompositionPreference.aidl new file mode 100644 index 0000000000..b615824a7d --- /dev/null +++ b/libs/gui/aidl/android/gui/CompositionPreference.aidl @@ -0,0 +1,25 @@ +/* + * 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 android.gui; + +/** @hide */ +parcelable CompositionPreference { + int /*ui::Dataspace*/ defaultDataspace; + int /*ui::PixelFormat*/ defaultPixelFormat; + int /*ui::Dataspace*/ wideColorGamutDataspace; + int /*ui::PixelFormat*/ wideColorGamutPixelFormat; +} diff --git a/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl b/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl new file mode 100644 index 0000000000..5d913b1da6 --- /dev/null +++ b/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl @@ -0,0 +1,24 @@ +/* + * 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 android.gui; + +/** @hide */ +parcelable ContentSamplingAttributes { + int /*ui::PixelFormat*/ format; + int /*ui::Dataspace*/ dataspace; + byte componentMask; +} diff --git a/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl b/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl new file mode 100644 index 0000000000..39e49167aa --- /dev/null +++ b/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl @@ -0,0 +1,24 @@ +/* + * 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 android.gui; + +/** @hide */ +parcelable CreateSurfaceResult { + IBinder handle; + int layerId; + int transformHint; +} diff --git a/libs/gui/aidl/android/gui/DeviceProductInfo.aidl b/libs/gui/aidl/android/gui/DeviceProductInfo.aidl new file mode 100644 index 0000000000..98404cf0fd --- /dev/null +++ b/libs/gui/aidl/android/gui/DeviceProductInfo.aidl @@ -0,0 +1,58 @@ +/* + * 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 android.gui; + +// Product-specific information about the display or the directly connected device on the +// display chain. For example, if the display is transitively connected, this field may contain +// product information about the intermediate device. + +/** @hide */ +parcelable DeviceProductInfo { + parcelable ModelYear { + int year; + } + + parcelable ManufactureYear { + ModelYear modelYear; + } + + parcelable ManufactureWeekAndYear { + ManufactureYear manufactureYear; + + // 1-base week number. Week numbering may not be consistent between manufacturers. + int week; + } + + union ManufactureOrModelDate { + ModelYear modelYear; + ManufactureYear manufactureYear; + ManufactureWeekAndYear manufactureWeekAndYear; + } + + // Display name. + @utf8InCpp String name; + + // NULL-terminated Manufacturer plug and play ID. + byte[] manufacturerPnpId; + + // Manufacturer product ID. + @utf8InCpp String productId; + + ManufactureOrModelDate manufactureOrModelDate; + + byte[] relativeAddress; +} diff --git a/libs/gui/aidl/android/gui/DisplayConnectionType.aidl b/libs/gui/aidl/android/gui/DisplayConnectionType.aidl new file mode 100644 index 0000000000..72c4ede7ac --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayConnectionType.aidl @@ -0,0 +1,24 @@ +/* + * 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 android.gui; + +/** @hide */ +@Backing(type="int") +enum DisplayConnectionType { + Internal = 0, + External = 1 +} diff --git a/libs/input/android/os/BlockUntrustedTouchesMode.aidl b/libs/gui/aidl/android/gui/DisplayDecorationSupport.aidl index 9504e993f8..023049657b 100644 --- a/libs/input/android/os/BlockUntrustedTouchesMode.aidl +++ b/libs/gui/aidl/android/gui/DisplayDecorationSupport.aidl @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020, The Android Open Source Project + * 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. @@ -14,22 +14,12 @@ * limitations under the License. */ -package android.os; +package android.gui; - -/** - * Block untrusted touches feature mode. - * - * @hide - */ -@Backing(type="int") -enum BlockUntrustedTouchesMode { - /** Feature is off. */ - DISABLED, - - /** Untrusted touches are flagged but not blocked. */ - PERMISSIVE, - - /** Untrusted touches are blocked. */ - BLOCK +// TODO(b/222607970): +// remove this aidl and use android.hardware.graphics.common.DisplayDecorationSupport +/** @hide */ +parcelable DisplayDecorationSupport { + int format; + int alphaInterpretation; } diff --git a/libs/gui/aidl/android/gui/DisplayMode.aidl b/libs/gui/aidl/android/gui/DisplayMode.aidl new file mode 100644 index 0000000000..3cd77f82d7 --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayMode.aidl @@ -0,0 +1,36 @@ +/* + * 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 android.gui; + +import android.gui.Size; + +// Mode supported by physical display. +// Make sure to sync with libui DisplayMode.h + +/** @hide */ +parcelable DisplayMode { + int id; + Size resolution; + float xDpi = 0.0f; + float yDpi = 0.0f; + + float refreshRate = 0.0f; + long appVsyncOffset = 0; + long sfVsyncOffset = 0; + long presentationDeadline = 0; + int group = -1; +} diff --git a/libs/gui/aidl/android/gui/DisplayModeSpecs.aidl b/libs/gui/aidl/android/gui/DisplayModeSpecs.aidl new file mode 100644 index 0000000000..fb4fcdf8e8 --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayModeSpecs.aidl @@ -0,0 +1,27 @@ +/* + * 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 android.gui; + +/** @hide */ +parcelable DisplayModeSpecs { + int defaultMode; + boolean allowGroupSwitching; + float primaryRefreshRateMin; + float primaryRefreshRateMax; + float appRequestRefreshRateMin; + float appRequestRefreshRateMax; +} diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/DisplayPrimaries.aidl index 6929a6cb49..dbf668c629 100644 --- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl +++ b/libs/gui/aidl/android/gui/DisplayPrimaries.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * 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. @@ -14,15 +14,20 @@ * limitations under the License. */ -package android.content.pm; +package android.gui; -import android.content.pm.PackageChangeEvent; +// copied from libui ConfigStoreTypes.h -/** - * This is a non-blocking notification when a package has changed. - * - * @hide - */ -oneway interface IPackageChangeObserver { - void onPackageChanged(in PackageChangeEvent event); +/** @hide */ +parcelable DisplayPrimaries { + parcelable CieXyz { + float X; + float Y; + float Z; + } + + CieXyz red; + CieXyz green; + CieXyz blue; + CieXyz white; } diff --git a/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl b/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl new file mode 100644 index 0000000000..f4b6dadc49 --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl @@ -0,0 +1,40 @@ +/* + * 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 android.gui; + +/** @hide */ +parcelable DisplayedFrameStats { + /* The number of frames represented by this sample. */ + long numFrames = 0; + + /* A histogram counting how many times a pixel of a given value was displayed onscreen for + * FORMAT_COMPONENT_0. The buckets of the histogram are evenly weighted, the number of buckets + * is device specific. eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that + * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels + * were displayed onscreen in range 0x40->0x7F, etc. + */ + long[] component_0_sample; + + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_1. */ + long[] component_1_sample; + + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_2. */ + long[] component_2_sample; + + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_3. */ + long[] component_3_sample; +} diff --git a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl new file mode 100644 index 0000000000..57e6081e27 --- /dev/null +++ b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl @@ -0,0 +1,45 @@ +/* + * 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 android.gui; + +import android.gui.DisplayMode; +import android.gui.HdrCapabilities; + +// Information about a physical display which may change on hotplug reconnect. +// Make sure to sync with libui DynamicDisplayInfo.h + +/** @hide */ +parcelable DynamicDisplayInfo { + List<DisplayMode> supportedDisplayModes; + + int activeDisplayModeId; + + int[] supportedColorModes; + int activeColorMode; + HdrCapabilities hdrCapabilities; + + // True if the display reports support for HDMI 2.1 Auto Low Latency Mode. + // For more information, see the HDMI 2.1 specification. + boolean autoLowLatencyModeSupported; + + // True if the display reports support for Game Content Type. + // For more information, see the HDMI 1.4 specification. + boolean gameContentTypeSupported; + + // The boot display mode preferred by the implementation. + int preferredBootDisplayMode; +} diff --git a/libs/gui/aidl/android/gui/FrameEvent.aidl b/libs/gui/aidl/android/gui/FrameEvent.aidl new file mode 100644 index 0000000000..aaabdb5b54 --- /dev/null +++ b/libs/gui/aidl/android/gui/FrameEvent.aidl @@ -0,0 +1,35 @@ +/* + * 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 android.gui; + +// Identifiers for all the events that may be recorded or reported. + +/** @hide */ +@Backing(type="int") +enum FrameEvent { + POSTED = 0, + REQUESTED_PRESENT = 1, + LATCH = 2, + ACQUIRE = 3, + FIRST_REFRESH_START = 4, + LAST_REFRESH_START = 5, + GPU_COMPOSITION_DONE = 6, + DISPLAY_PRESENT = 7, + DEQUEUE_READY = 8, + RELEASE = 9, + EVENT_COUNT = 10 // Not an actual event. +} diff --git a/libs/gui/aidl/android/gui/FrameStats.aidl b/libs/gui/aidl/android/gui/FrameStats.aidl new file mode 100644 index 0000000000..a145e74b11 --- /dev/null +++ b/libs/gui/aidl/android/gui/FrameStats.aidl @@ -0,0 +1,47 @@ +/* + * 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 android.gui; + +// Make sure to sync with libui FrameStats.h + +/** @hide */ +parcelable FrameStats { + /* + * Approximate refresh time, in nanoseconds. + */ + long refreshPeriodNano; + + /* + * The times in nanoseconds for when the frame contents were posted by the producer (e.g. + * the application). They are either explicitly set or defaulted to the time when + * Surface::queueBuffer() was called. + */ + long[] desiredPresentTimesNano; + + /* + * The times in milliseconds for when the frame contents were presented on the screen. + */ + long[] actualPresentTimesNano; + + /* + * The times in nanoseconds for when the frame contents were ready to be presented. Note that + * a frame can be posted and still it contents being rendered asynchronously in GL. In such a + * case these are the times when the frame contents were completely rendered (i.e. their fences + * signaled). + */ + long[] frameReadyTimesNano; +} diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl index 255ce568d2..6ffe466f20 100644 --- a/libs/gui/include/gui/FrameTimelineInfo.h +++ b/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * 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. @@ -14,36 +14,23 @@ * limitations under the License. */ -#pragma once +package android.gui; -#include <stdint.h> - -#include <binder/Parcel.h> - -namespace android { - -struct FrameTimelineInfo { +/** @hide */ +parcelable FrameTimelineInfo { // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java - static constexpr int64_t INVALID_VSYNC_ID = -1; + const long INVALID_VSYNC_ID = -1; // The vsync id that was used to start the transaction - int64_t vsyncId = INVALID_VSYNC_ID; + long vsyncId = INVALID_VSYNC_ID; // The id of the input event that caused this buffer // Default is android::os::IInputConstants::INVALID_INPUT_EVENT_ID = 0 // We copy the value of the input event ID instead of including the header, because libgui // header libraries containing FrameTimelineInfo must be available to vendors, but libinput is // not directly vendor available. - int32_t inputEventId = 0; + int inputEventId = 0; // The current time in nanoseconds the application started to render the frame. - int64_t startTimeNanos = 0; - - status_t write(Parcel& output) const; - status_t read(const Parcel& input); - - void merge(const FrameTimelineInfo& other); - void clear(); -}; - -} // namespace android + long startTimeNanos = 0; +} diff --git a/libs/gui/aidl/android/gui/HdrCapabilities.aidl b/libs/gui/aidl/android/gui/HdrCapabilities.aidl new file mode 100644 index 0000000000..9d06da9f27 --- /dev/null +++ b/libs/gui/aidl/android/gui/HdrCapabilities.aidl @@ -0,0 +1,27 @@ +/* + * 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 android.gui; + +// Make sure to sync with libui HdrCapabilities.h + +/** @hide */ +parcelable HdrCapabilities { + int[] supportedHdrTypes; + float maxLuminance; + float maxAverageLuminance; + float minLuminance; +} diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index b31b37bada..3c220fcc66 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -16,39 +16,97 @@ package android.gui; -import android.gui.DisplayCaptureArgs; +import android.gui.Color; +import android.gui.CompositionPreference; +import android.gui.ContentSamplingAttributes; import android.gui.DisplayBrightness; +import android.gui.DisplayCaptureArgs; +import android.gui.DisplayDecorationSupport; +import android.gui.DisplayedFrameStats; +import android.gui.DisplayModeSpecs; +import android.gui.DisplayPrimaries; import android.gui.DisplayState; import android.gui.DisplayStatInfo; +import android.gui.DynamicDisplayInfo; +import android.gui.FrameEvent; +import android.gui.FrameStats; +import android.gui.IDisplayEventConnection; +import android.gui.IFpsListener; import android.gui.IHdrLayerInfoListener; -import android.gui.LayerCaptureArgs; +import android.gui.IRegionSamplingListener; import android.gui.IScreenCaptureListener; +import android.gui.ISurfaceComposerClient; +import android.gui.ITransactionTraceListener; +import android.gui.ITunnelModeEnabledListener; +import android.gui.IWindowInfosListener; +import android.gui.LayerCaptureArgs; +import android.gui.LayerDebugInfo; +import android.gui.PullAtomData; +import android.gui.ARect; +import android.gui.StaticDisplayInfo; /** @hide */ interface ISurfaceComposer { - /* create a virtual display + enum VsyncSource { + eVsyncSourceApp = 0, + eVsyncSourceSurfaceFlinger = 1 + } + + enum EventRegistration { + modeChanged = 1 << 0, + frameRateOverride = 1 << 1, + } + + /** + * Signal that we're done booting. + * Requires ACCESS_SURFACE_FLINGER permission + */ + // Note this must be the 1st method, so IBinder::FIRST_CALL_TRANSACTION + // is assigned, as it is called from Java by ActivityManagerService. + void bootFinished(); + + /** + * Create a display event connection + */ + @nullable IDisplayEventConnection createDisplayEventConnection(VsyncSource vsyncSource, + EventRegistration eventRegistration); + + /** + * Create a connection with SurfaceFlinger. + */ + @nullable ISurfaceComposerClient createConnection(); + + /** + * Create a virtual display * requires ACCESS_SURFACE_FLINGER permission. */ @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure); - /* destroy a virtual display + /** + * Destroy a virtual display * requires ACCESS_SURFACE_FLINGER permission. */ void destroyDisplay(IBinder display); - /* get stable IDs for connected physical displays. + /** + * Get stable IDs for connected physical displays. */ long[] getPhysicalDisplayIds(); - long getPrimaryPhysicalDisplayId(); - - /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a - * DisplayEventReceiver hotplug event. + /** + * Get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or + * a DisplayEventReceiver hotplug event. */ @nullable IBinder getPhysicalDisplayToken(long displayId); - /* set display power mode. depending on the mode, it can either trigger + /** + * Returns the frame timestamps supported by SurfaceFlinger. + */ + FrameEvent[] getSupportedFrameTimestamps(); + + /** + * Set display power mode. depending on the mode, it can either trigger * screen on, off or low power mode and wait for it to complete. * requires ACCESS_SURFACE_FLINGER permission. */ @@ -60,12 +118,31 @@ interface ISurfaceComposer { * video frames */ DisplayStatInfo getDisplayStats(@nullable IBinder display); - /** + /** * Get transactional state of given display. */ DisplayState getDisplayState(IBinder display); /** + * Gets immutable information about given physical display. + */ + StaticDisplayInfo getStaticDisplayInfo(IBinder display); + + /** + * Gets dynamic information about given physical display. + */ + DynamicDisplayInfo getDynamicDisplayInfo(IBinder display); + + DisplayPrimaries getDisplayNativePrimaries(IBinder display); + + void setActiveColorMode(IBinder display, int colorMode); + + /** + * Sets the user-preferred display mode that a device should boot in. + */ + void setBootDisplayMode(IBinder display, int displayModeId); + + /** * Clears the user-preferred display mode. The device should now boot in system preferred * display mode. */ @@ -110,7 +187,9 @@ interface ISurfaceComposer { * match the size of the output buffer. */ void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener); + void captureDisplayById(long displayId, IScreenCaptureListener listener); + /** * Capture a subtree of the layer hierarchy, potentially ignoring the root node. * This requires READ_FRAME_BUFFER permission. This function will fail if there @@ -118,13 +197,163 @@ interface ISurfaceComposer { */ void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener); - /* + /** + * Clears the frame statistics for animations. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + void clearAnimationFrameStats(); + + /** + * Gets the frame statistics for animations. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + FrameStats getAnimationFrameStats(); + + /** + * Overrides the supported HDR modes for the given display device. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + void overrideHdrTypes(IBinder display, in int[] hdrTypes); + + /** + * Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd. + * + * Requires the calling uid be from system server. + */ + PullAtomData onPullAtom(int atomId); + + oneway void enableVSyncInjections(boolean enable); + + oneway void injectVSync(long when); + + /** + * Gets the list of active layers in Z order for debugging purposes + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + List<LayerDebugInfo> getLayerDebugInfo(); + + boolean getColorManagement(); + + /** + * Gets the composition preference of the default data space and default pixel format, + * as well as the wide color gamut data space and wide color gamut pixel format. + * If the wide color gamut data space is V0_SRGB, then it implies that the platform + * has no wide color gamut support. + * + */ + CompositionPreference getCompositionPreference(); + + /** + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + ContentSamplingAttributes getDisplayedContentSamplingAttributes(IBinder display); + + /** + * Turns on the color sampling engine on the display. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + void setDisplayContentSamplingEnabled(IBinder display, boolean enable, byte componentMask, long maxFrames); + + /** + * Returns statistics on the color profile of the last frame displayed for a given display + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + DisplayedFrameStats getDisplayedContentSample(IBinder display, long maxFrames, long timestamp); + + /** + * Gets whether SurfaceFlinger can support protected content in GPU composition. + */ + boolean getProtectedContentSupport(); + + /** * Queries whether the given display is a wide color display. * Requires the ACCESS_SURFACE_FLINGER permission. */ boolean isWideColorDisplay(IBinder token); - /* + /** + * Registers a listener to stream median luma updates from SurfaceFlinger. + * + * The sampling area is bounded by both samplingArea and the given stopLayerHandle + * (i.e., only layers behind the stop layer will be captured and sampled). + * + * Multiple listeners may be provided so long as they have independent listeners. + * If multiple listeners are provided, the effective sampling region for each listener will + * be bounded by whichever stop layer has a lower Z value. + * + * Requires the same permissions as captureLayers and captureScreen. + */ + void addRegionSamplingListener(in ARect samplingArea, @nullable IBinder stopLayerHandle, IRegionSamplingListener listener); + + /** + * Removes a listener that was streaming median luma updates from SurfaceFlinger. + */ + void removeRegionSamplingListener(IRegionSamplingListener listener); + + /** + * Registers a listener that streams fps updates from SurfaceFlinger. + * + * The listener will stream fps updates for the layer tree rooted at the layer denoted by the + * task ID, i.e., the layer must have the task ID as part of its layer metadata with key + * METADATA_TASK_ID. If there is no such layer, then no fps is expected to be reported. + * + * Multiple listeners may be supported. + * + * Requires the READ_FRAME_BUFFER permission. + */ + void addFpsListener(int taskId, IFpsListener listener); + + /** + * Removes a listener that was streaming fps updates from SurfaceFlinger. + */ + void removeFpsListener(IFpsListener listener); + + /** + * Registers a listener to receive tunnel mode enabled updates from SurfaceFlinger. + * + * Requires ACCESS_SURFACE_FLINGER permission. + */ + void addTunnelModeEnabledListener(ITunnelModeEnabledListener listener); + + /** + * Removes a listener that was receiving tunnel mode enabled updates from SurfaceFlinger. + * + * Requires ACCESS_SURFACE_FLINGER permission. + */ + void removeTunnelModeEnabledListener(ITunnelModeEnabledListener listener); + + /** + * Sets the refresh rate boundaries for the display. + * + * The primary refresh rate range represents display manager's general guidance on the display + * modes we'll consider when switching refresh rates. Unless we get an explicit signal from an + * app, we should stay within this range. + * + * The app request refresh rate range allows us to consider more display modes when switching + * refresh rates. Although we should generally stay within the primary range, specific + * considerations, such as layer frame rate settings specified via the setFrameRate() api, may + * cause us to go outside the primary range. We never go outside the app request range. The app + * request range will be greater than or equal to the primary refresh rate range, never smaller. + * + * defaultMode is used to narrow the list of display modes SurfaceFlinger will consider + * switching between. Only modes with a mode group and resolution matching defaultMode + * will be considered for switching. The defaultMode corresponds to an ID of mode in the list + * of supported modes returned from getDynamicDisplayInfo(). + */ + void setDesiredDisplayModeSpecs( + IBinder displayToken, int defaultMode, + boolean allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, + float appRequestRefreshRateMin, float appRequestRefreshRateMax); + + DisplayModeSpecs getDesiredDisplayModeSpecs(IBinder displayToken); + + /** * Gets whether brightness operations are supported on a display. * * displayToken @@ -138,7 +367,7 @@ interface ISurfaceComposer { */ boolean getDisplayBrightnessSupport(IBinder displayToken); - /* + /** * Sets the brightness of a display. * * displayToken @@ -153,7 +382,7 @@ interface ISurfaceComposer { */ void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness); - /* + /** * Adds a listener that receives HDR layer information. This is used in combination * with setDisplayBrightness to adjust the display brightness depending on factors such * as whether or not HDR is in use. @@ -162,7 +391,7 @@ interface ISurfaceComposer { */ void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener); - /* + /** * Removes a listener that was added with addHdrLayerInfoListener. * * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if @@ -171,7 +400,7 @@ interface ISurfaceComposer { */ void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener); - /* + /** * Sends a power boost to the composer. This function is asynchronous. * * boostId @@ -179,5 +408,78 @@ interface ISurfaceComposer { * * Returns NO_ERROR upon success. */ - void notifyPowerBoost(int boostId); + oneway void notifyPowerBoost(int boostId); + + /* + * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows + * material design guidelines. + * + * ambientColor + * Color to the ambient shadow. The alpha is premultiplied. + * + * spotColor + * Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow + * depends on the light position. + * + * lightPosY/lightPosZ + * Position of the light used to cast the spot shadow. The X value is always the display + * width / 2. + * + * lightRadius + * Radius of the light casting the shadow. + */ + oneway void setGlobalShadowSettings(in Color ambientColor, in Color spotColor, float lightPosY, float lightPosZ, float lightRadius); + + /** + * Gets whether a display supports DISPLAY_DECORATION layers. + * + * displayToken + * The token of the display. + * outSupport + * An output parameter for whether/how the display supports + * DISPLAY_DECORATION layers. + * + * Returns NO_ERROR upon success. Otherwise, + * NAME_NOT_FOUND if the display is invalid, or + * BAD_VALUE if the output parameter is invalid. + */ + @nullable DisplayDecorationSupport getDisplayDecorationSupport(IBinder displayToken); + + /** + * Set the override frame rate for a specified uid by GameManagerService. + * Passing the frame rate and uid to SurfaceFlinger to update the override mapping + * in the scheduler. + */ + void setOverrideFrameRate(int uid, float frameRate); + + /** + * Adds a TransactionTraceListener to listen for transaction tracing state updates. + */ + void addTransactionTraceListener(ITransactionTraceListener listener); + + /** + * Gets priority of the RenderEngine in SurfaceFlinger. + */ + int getGpuContextPriority(); + + /** + * Gets the number of buffers SurfaceFlinger would need acquire. This number + * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the + * client could allocate enough buffers to match SF expectations of the + * pipeline depth. SurfaceFlinger will make sure that it will give the app at + * least the time configured as the 'appDuration' before trying to latch + * the buffer. + * + * The total buffers needed for a given configuration is basically the + * numbers of vsyncs a single buffer is used across the stack. For the default + * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger + * and 1 vsync by the display. The extra buffers are calculated as the + * number of additional buffers on top of the 2 buffers already present + * in MIN_UNDEQUEUED_BUFFERS. + */ + int getMaxAcquiredBufferCount(); + + void addWindowInfosListener(IWindowInfosListener windowInfosListener); + + void removeWindowInfosListener(IWindowInfosListener windowInfosListener); } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl new file mode 100644 index 0000000000..b8ee4d72d7 --- /dev/null +++ b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl @@ -0,0 +1,64 @@ +/* + * 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 android.gui; + +import android.gui.CreateSurfaceResult; +import android.gui.FrameStats; +import android.gui.LayerMetadata; +import android.gui.MirrorSurfaceResult; + +/** @hide */ +interface ISurfaceComposerClient { + + // flags for createSurface() + // (keep in sync with SurfaceControl.java) + const int eHidden = 0x00000004; + const int eDestroyBackbuffer = 0x00000020; + const int eSkipScreenshot = 0x00000040; + const int eSecure = 0x00000080; + const int eNonPremultiplied = 0x00000100; + const int eOpaque = 0x00000400; + const int eProtectedByApp = 0x00000800; + const int eProtectedByDRM = 0x00001000; + const int eCursorWindow = 0x00002000; + const int eNoColorFill = 0x00004000; + + const int eFXSurfaceBufferQueue = 0x00000000; + const int eFXSurfaceEffect = 0x00020000; + const int eFXSurfaceBufferState = 0x00040000; + const int eFXSurfaceContainer = 0x00080000; + const int eFXSurfaceMask = 0x000F0000; + + /** + * Requires ACCESS_SURFACE_FLINGER permission + */ + CreateSurfaceResult createSurface(@utf8InCpp String name, int flags, @nullable IBinder parent, in LayerMetadata metadata); + + /** + * Requires ACCESS_SURFACE_FLINGER permission + */ + void clearLayerFrameStats(IBinder handle); + + /** + * Requires ACCESS_SURFACE_FLINGER permission + */ + FrameStats getLayerFrameStats(IBinder handle); + + MirrorSurfaceResult mirrorSurface(IBinder mirrorFromHandle); + + MirrorSurfaceResult mirrorDisplay(long displayId); +} diff --git a/libs/gui/aidl/android/gui/LayerDebugInfo.aidl b/libs/gui/aidl/android/gui/LayerDebugInfo.aidl new file mode 100644 index 0000000000..faca980f3c --- /dev/null +++ b/libs/gui/aidl/android/gui/LayerDebugInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.gui; + +parcelable LayerDebugInfo cpp_header "gui/LayerDebugInfo.h"; diff --git a/libs/gui/aidl/android/gui/LayerMetadata.aidl b/libs/gui/aidl/android/gui/LayerMetadata.aidl new file mode 100644 index 0000000000..1368ac512f --- /dev/null +++ b/libs/gui/aidl/android/gui/LayerMetadata.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.gui; + +parcelable LayerMetadata cpp_header "gui/LayerMetadata.h"; diff --git a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl b/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl new file mode 100644 index 0000000000..9fac3e8644 --- /dev/null +++ b/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl @@ -0,0 +1,23 @@ +/* + * 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 android.gui; + +/** @hide */ +parcelable MirrorSurfaceResult { + IBinder handle; + int layerId; +} diff --git a/libs/gui/aidl/android/gui/PullAtomData.aidl b/libs/gui/aidl/android/gui/PullAtomData.aidl new file mode 100644 index 0000000000..14d33c6d0b --- /dev/null +++ b/libs/gui/aidl/android/gui/PullAtomData.aidl @@ -0,0 +1,23 @@ +/* + * 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 android.gui; + +/** @hide */ +parcelable PullAtomData { + @utf8InCpp String data; + boolean success; +} diff --git a/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl new file mode 100644 index 0000000000..0ccda56ef5 --- /dev/null +++ b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl @@ -0,0 +1,30 @@ +/* + * 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 android.gui; + +import android.gui.DisplayConnectionType; +import android.gui.DeviceProductInfo; +import android.gui.Rotation; + +/** @hide */ +parcelable StaticDisplayInfo { + DisplayConnectionType connectionType = DisplayConnectionType.Internal; + float density; + boolean secure; + @nullable DeviceProductInfo deviceProductInfo; + Rotation installOrientation = Rotation.Rotation0; +} diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp new file mode 100644 index 0000000000..cdc9376a44 --- /dev/null +++ b/libs/gui/fuzzer/Android.bp @@ -0,0 +1,137 @@ +/* + * Copyright 2021 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_defaults { + name: "libgui_fuzzer_defaults", + static_libs: [ + "android.hidl.token@1.0-utils", + "libbinder_random_parcel", + "libgui_aidl_static", + "libgui_window_info_static", + "libpdx", + "libgmock", + "libgui_mocks", + "libgmock_ndk", + "libgmock_main", + "libgtest_ndk_c++", + "libgmock_main_ndk", + "librenderengine_mocks", + "perfetto_trace_protos", + "libcompositionengine_mocks", + "perfetto_trace_protos", + ], + shared_libs: [ + "android.hardware.configstore@1.0", + "android.hardware.configstore-utils", + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.bufferqueue@2.0", + "android.hardware.power-V2-cpp", + "android.hidl.token@1.0", + "libSurfaceFlingerProp", + "libgui", + "libbase", + "liblog", + "libEGL", + "libGLESv2", + "libbinder", + "libcutils", + "libhidlbase", + "libinput", + "libui", + "libutils", + "libnativewindow", + "libvndksupport", + "libbufferhubqueue", + ], + header_libs: [ + "libdvr_headers", + "libui_fuzzableDataspaces_headers", + ], + fuzz_config: { + cc: [ + "android-media-fuzzing-reports@google.com", + ], + componentid: 155276, + }, +} + +cc_fuzz { + name: "libgui_surfaceComposer_fuzzer", + srcs: [ + "libgui_surfaceComposer_fuzzer.cpp", + ], + defaults: [ + "libgui_fuzzer_defaults", + ], +} + +cc_fuzz { + name: "libgui_surfaceComposerClient_fuzzer", + srcs: [ + "libgui_surfaceComposerClient_fuzzer.cpp", + ], + defaults: [ + "libgui_fuzzer_defaults", + ], +} + +cc_fuzz { + name: "libgui_parcelable_fuzzer", + srcs: [ + "libgui_parcelable_fuzzer.cpp", + ], + defaults: [ + "libgui_fuzzer_defaults", + ], +} + +cc_fuzz { + name: "libgui_bufferQueue_fuzzer", + srcs: [ + "libgui_bufferQueue_fuzzer.cpp", + ], + defaults: [ + "libgui_fuzzer_defaults", + ], +} + +cc_fuzz { + name: "libgui_consumer_fuzzer", + srcs: [ + "libgui_consumer_fuzzer.cpp", + ], + defaults: [ + "libgui_fuzzer_defaults", + ], +} + +cc_fuzz { + name: "libgui_displayEvent_fuzzer", + srcs: [ + "libgui_displayEvent_fuzzer.cpp", + ], + defaults: [ + "libgui_fuzzer_defaults", + ], +} diff --git a/libs/gui/fuzzer/README.md b/libs/gui/fuzzer/README.md new file mode 100644 index 0000000000..96e27c989f --- /dev/null +++ b/libs/gui/fuzzer/README.md @@ -0,0 +1,219 @@ +# Fuzzers for Libgui + +## Table of contents ++ [libgui_surfaceComposer_fuzzer](#SurfaceComposer) ++ [libgui_surfaceComposerClient_fuzzer](#SurfaceComposerClient) ++ [libgui_parcelable_fuzzer](#Libgui_Parcelable) ++ [libgui_bufferQueue_fuzzer](#BufferQueue) ++ [libgui_consumer_fuzzer](#Libgui_Consumer) ++ [libgui_displayEvent_fuzzer](#LibGui_DisplayEvent) + +# <a name="libgui_surfaceComposer_fuzzer"></a> Fuzzer for SurfaceComposer + +SurfaceComposer supports the following parameters: +1. SurfaceWidth (parameter name:`width`) +2. SurfaceHeight (parameter name:`height`) +3. TransactionStateFlags (parameter name:`flags`) +4. TransformHint (parameter name:`outTransformHint`) +5. SurfacePixelFormat (parameter name:`format`) +6. LayerId (parameter name:`outLayerId`) +7. SurfaceComposerTags (parameter name:`surfaceTag`) +8. PowerBoostID (parameter name:`boostId`) +9. VsyncSource (parameter name:`vsyncSource`) +10. EventRegistrationFlags (parameter name:`eventRegistration`) +11. FrameRateCompatibility (parameter name:`frameRateCompatibility`) +12. ChangeFrameRateStrategy (parameter name:`changeFrameRateStrategy`) +13. HdrTypes (parameter name:`hdrTypes`) + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`surfaceTag` | 0.`BnSurfaceComposer::BOOT_FINISHED`, 1.`BnSurfaceComposer::CREATE_CONNECTION`, 2.`BnSurfaceComposer::GET_STATIC_DISPLAY_INFO`, 3.`BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION`, 4.`BnSurfaceComposer::CREATE_DISPLAY`, 5.`BnSurfaceComposer::DESTROY_DISPLAY`, 6.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN`, 7.`BnSurfaceComposer::SET_TRANSACTION_STATE`, 8.`BnSurfaceComposer::AUTHENTICATE_SURFACE`, 9.`BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS`, 10.`BnSurfaceComposer::GET_DISPLAY_STATE`, 11.`BnSurfaceComposer::CAPTURE_DISPLAY`, 12.`BnSurfaceComposer::CAPTURE_LAYERS`, 13.`BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS`, 14.`BnSurfaceComposer::GET_ANIMATION_FRAME_STATS`, 15.`BnSurfaceComposer::SET_POWER_MODE`, 16.`BnSurfaceComposer::GET_DISPLAY_STATS`, 17.`BnSurfaceComposer::SET_ACTIVE_COLOR_MODE`, 18.`BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS`, 19.`BnSurfaceComposer::INJECT_VSYNC`, 20.`BnSurfaceComposer::GET_LAYER_DEBUG_INFO`, 21.`BnSurfaceComposer::GET_COMPOSITION_PREFERENCE`, 22.`BnSurfaceComposer::GET_COLOR_MANAGEMENT`, 23.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES`, 24.`BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED`, 25.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE`, 26.`BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT`, 27.`BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY`, 28.`BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES`, 29.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS`, 30.`BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER`, 31.`BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER`, 32.`BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS`, 33.`BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS`, 34.`BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT`, 35.`BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS`, 36.`BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID`, 37.`BnSurfaceComposer::NOTIFY_POWER_BOOST`, 38.`BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS`, 39.`BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE`, 40.`BnSurfaceComposer::SET_GAME_CONTENT_TYPE`, 41.`BnSurfaceComposer::SET_FRAME_RATE`, 42.`BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN`, 43.`BnSurfaceComposer::SET_FRAME_TIMELINE_INFO`, 44.`BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER`, 45.`BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY`, 46.`BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT`, 47.`BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO`, 48.`BnSurfaceComposer::ADD_FPS_LISTENER`, 49.`BnSurfaceComposer::REMOVE_FPS_LISTENER`, 50.`BnSurfaceComposer::OVERRIDE_HDR_TYPES`, 51.`BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER`, 52.`BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER`, 53.`BnSurfaceComposer::ON_PULL_ATOM`, 54.`BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER`, 55.`BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER` | Value obtained from FuzzedDataProvider| +|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider| +|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider| +|`eventRegistration`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride` |Value obtained from FuzzedDataProvider| +|`frameRateCompatibility`| 0.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT`, 1.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE` |Value obtained from FuzzedDataProvider| +|`changeFrameRateStrategy`| 0.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS`, 1.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS` |Value obtained from FuzzedDataProvider| +|`hdrTypes`| 0.`ui::Hdr::DOLBY_VISION`, 1.`ui::Hdr::HDR10`, 2.`ui::Hdr::HLG`, 3.`ui::Hdr::HDR10_PLUS` |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) libgui_surfaceComposer_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/libgui_surfaceComposer_fuzzer/libgui_surfaceComposer_fuzzer +``` + +# <a name="libgui_surfaceComposerClient_fuzzer"></a> Fuzzer for SurfaceComposerClient + +SurfaceComposerClient supports the following data sources: +1. SurfaceWidth (parameter name:`width`) +2. SurfaceHeight (parameter name:`height`) +3. TransactionStateFlags (parameter name:`flags`) +4. TransformHint (parameter name:`outTransformHint`) +5. SurfacePixelFormat (parameter name:`format`) +6. LayerId (parameter name:`outLayerId`) +7. SurfaceComposerClientTags (parameter name:`surfaceTag`) +8. DefaultMode (parameter name:`defaultMode`) +9. PrimaryRefreshRateMin (parameter name:`primaryRefreshRateMin`) +10. PrimaryRefreshRateMax (parameter name:`primaryRefreshRateMax`) +11. AppRefreshRateMin (parameter name:`appRefreshRateMin`) +12. AppRefreshRateMax (parameter name:`appRefreshRateMax`) +13. DisplayPowerMode (parameter name:`mode`) +14. CacheId (parameter name:`cacheId`) +15. DisplayBrightness (parameter name:`brightness`) +16. PowerBoostID (parameter name:`boostId`) +17. AtomId (parameter name:`atomId`) +18. ComponentMask (parameter name:`componentMask`) +19. MaxFrames (parameter name:`maxFrames`) +20. TaskId (parameter name:`taskId`) +21. Alpha (parameter name:`aplha`) +22. CornerRadius (parameter name:`cornerRadius`) +23. BackgroundBlurRadius (parameter name:`backgroundBlurRadius`) +24. Half3Color (parameter name:`color`) +25. LayerStack (parameter name:`layerStack`) +26. Dataspace (parameter name:`dataspace`) +27. Api (parameter name:`api`) +28. Priority (parameter name:`priority`) +29. TouchableRegionPointX (parameter name:`pointX`) +30. TouchableRegionPointY (parameter name:`pointY`) +31. ColorMode (parameter name:`colorMode`) +32. WindowInfoFlags (parameter name:`flags`) +33. WindowInfoTransformOrientation (parameter name:`transform`) + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`surfaceTag`| 0.`Tag::CREATE_SURFACE`, 1.`Tag::CREATE_WITH_SURFACE_PARENT`, 2.`Tag::CLEAR_LAYER_FRAME_STATS`, 3.`Tag::GET_LAYER_FRAME_STATS`, 4.`Tag::MIRROR_SURFACE`, 5.`Tag::LAST` |Value obtained from FuzzedDataProvider| +|`mode`| 0.`gui::TouchOcclusionMode::BLOCK_UNTRUSTED`, 1.`gui::TouchOcclusionMode::USE_OPACITY`, 2.`gui::TouchOcclusionMode::ALLOW` |Value obtained from FuzzedDataProvider| +|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider| +|`colorMode`|0.`ui::ColorMode::NATIVE`, 1.`ui::ColorMode::STANDARD_BT601_625`, 2.`ui::ColorMode::STANDARD_BT601_625_UNADJUSTED`, 3.`ui::ColorMode::STANDARD_BT601_525`, 4.`ui::ColorMode::STANDARD_BT601_525_UNADJUSTED`, 5.`ui::ColorMode::STANDARD_BT709`, 6.`ui::ColorMode::DCI_P3`, 7.`ui::ColorMode::SRGB`, 8.`ui::ColorMode::ADOBE_RGB`, 9.`ui::ColorMode::DISPLAY_P3`, 10.`ui::ColorMode::BT2020`, 11.`ui::ColorMode::BT2100_PQ`, 12.`ui::ColorMode::BT2100_HLG`, 13.`ui::ColorMode::DISPLAY_BT2020` |Value obtained from FuzzedDataProvider| +|`flags`|0 .`gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON`, 1.`gui::WindowInfo::Flag::DIM_BEHIND`, 2.`gui::WindowInfo::Flag::BLUR_BEHIND`, 3.`gui::WindowInfo::Flag::NOT_FOCUSABLE`, 4.`gui::WindowInfo::Flag::NOT_TOUCHABLE`, 5.`gui::WindowInfo::Flag::NOT_TOUCH_MODAL`, 6.`gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING`, 7.`gui::WindowInfo::Flag::KEEP_SCREEN_ON`, 8.`gui::WindowInfo::Flag::LAYOUT_IN_SCREEN`, 9.`gui::WindowInfo::Flag::LAYOUT_NO_LIMITS`, 10.`gui::WindowInfo::Flag::FULLSCREEN`, 11.`gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN`, 12.`gui::WindowInfo::Flag::DITHER`, 13.`gui::WindowInfo::Flag::SECURE`, 14.`gui::WindowInfo::Flag::SCALED`, 15.`gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES`, 16.`gui::WindowInfo::Flag::LAYOUT_INSET_DECOR`, 17.`gui::WindowInfo::Flag::ALT_FOCUSABLE_IM`, 18.`gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH`, 19.`gui::WindowInfo::Flag::SHOW_WHEN_LOCKED`, 20.`gui::WindowInfo::Flag::SHOW_WALLPAPER`, 21.`gui::WindowInfo::Flag::TURN_SCREEN_ON`, 22.`gui::WindowInfo::Flag::DISMISS_KEYGUARD`, 23.`gui::WindowInfo::Flag::SPLIT_TOUCH`, 24.`gui::WindowInfo::Flag::HARDWARE_ACCELERATED`, 25.`gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN`, 26.`gui::WindowInfo::Flag::TRANSLUCENT_STATUS`, 27.`gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION`, 28.`gui::WindowInfo::Flag::LOCAL_FOCUS_MODE`, 29.`gui::WindowInfo::Flag::SLIPPERY`, 30.`gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR`, 31.`gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS`, |Value obtained from FuzzedDataProvider| +|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider| +|`transform`| 0.`ui::Transform::ROT_0`, 1.`ui::Transform::FLIP_H`, 2.`ui::Transform::FLIP_V`, 3.`ui::Transform::ROT_90`, 4.`ui::Transform::ROT_180`, 5.`ui::Transform::ROT_270` |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) libgui_surfaceComposerClient_fuzzer +``` +2. To run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/libgui_surfaceComposerClient_fuzzer/libgui_surfaceComposerClient_fuzzer +``` + +# <a name="libgui_parcelable_fuzzer"></a> Fuzzer for Libgui_Parcelable + +Libgui_Parcelable supports the following parameters: +1. LayerMetadataKey (parameter name:`key`) +2. Dataspace (parameter name:`mDataspace`) + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`key`| 0.`view::LayerMetadataKey::METADATA_OWNER_UID`, 1.`view::LayerMetadataKey::METADATA_WINDOW_TYPE`, 2.`view::LayerMetadataKey::METADATA_TASK_ID`, 3.`view::LayerMetadataKey::METADATA_MOUSE_CURSOR`, 4.`view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID`, 5.`view::LayerMetadataKey::METADATA_OWNER_PID`, 6.`view::LayerMetadataKey::METADATA_DEQUEUE_TIME`, 7.`view::LayerMetadataKey::METADATA_GAME_MODE`, |Value obtained from FuzzedDataProvider| +|`mDataSpace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) libgui_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/libgui_fuzzer/libgui_fuzzer +``` + +# <a name="libgui_bufferQueue_fuzzer"></a> Fuzzer for BufferQueue + +BufferQueue supports the following parameters: +1. SurfaceWidth (parameter name:`width`) +2. SurfaceHeight (parameter name:`height`) +3. TransactionStateFlags (parameter name:`flags`) +4. TransformHint (parameter name:`outTransformHint`) +5. SurfacePixelFormat (parameter name:`format`) +6. LayerId (parameter name:`layerId`) +7. BufferId (parameter name:`bufferId`) +8. FrameNumber (parameter name:`frameNumber`) +9. FrameRate (parameter name:`frameRate`) +10. Compatability (parameter name:`compatability`) +11. LatchTime (parameter name:`latchTime`) +12. AcquireTime (parameter name:`acquireTime`) +13. RefreshTime (parameter name:`refreshTime`) +14. DequeueTime (parameter name:`dequeueTime`) +15. Slot (parameter name:`slot`) +16. MaxBuffers (parameter name:`maxBuffers`) +17. GenerationNumber (parameter name:`generationNumber`) +18. Api (parameter name:`api`) +19. Usage (parameter name:`usage`) +20. MaxFrameNumber (parameter name:`maxFrameNumber`) +21. BufferCount (parameter name:`bufferCount`) +22. MaxAcquredBufferCount (parameter name:`maxAcquredBufferCount`) +23. Status (parameter name:`status`) +24. ApiConnection (parameter name:`apiConnection`) +25. Dataspace (parameter name:`dataspace`) + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`status`| 0.`OK`, 1.`NO_MEMORY`, 2.`NO_INIT`, 3.`BAD_VALUE`, 4.`DEAD_OBJECT`, 5.`INVALID_OPERATION`, 6.`TIMED_OUT`, 7.`WOULD_BLOCK`, 8.`UNKNOWN_ERROR`, 9.`ALREADY_EXISTS`, |Value obtained from FuzzedDataProvider| +|`apiConnection`| 0.`BufferQueueCore::CURRENTLY_CONNECTED_API`, 1.`BufferQueueCore::NO_CONNECTED_API`, 2.`NATIVE_WINDOW_API_EGL`, 3.`NATIVE_WINDOW_API_CPU`, 4.`NATIVE_WINDOW_API_MEDIA`, 5.`NATIVE_WINDOW_API_CAMERA`, |Value obtained from FuzzedDataProvider| +|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) libgui_bufferQueue_fuzzer +``` +2. To run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/libgui_bufferQueue_fuzzer/libgui_bufferQueue_fuzzer +``` + +# <a name="libgui_consumer_fuzzer"></a> Fuzzer for Libgui_Consumer + +Libgui_Consumer supports the following parameters: +1. GraphicWidth (parameter name:`graphicWidth`) +2. GraphicHeight (parameter name:`graphicHeight`) +4. TransformHint (parameter name:`outTransformHint`) +5. GraphicPixelFormat (parameter name:`format`) +6. Usage (parameter name:`usage`) + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) libgui_consumer_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/libgui_consumer_fuzzer/libgui_consumer_fuzzer +``` + +# <a name="libgui_displayEvent_fuzzer"></a> Fuzzer for LibGui_DisplayEvent + +LibGui_DisplayEvent supports the following parameters: +1. DisplayEventType (parameter name:`type`) +2. Events (parameter name:`events`) +3. VsyncSource (parameter name:`vsyncSource`) +4. EventRegistrationFlags (parameter name:`flags`) + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider| +|`flags`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride`, |Value obtained from FuzzedDataProvider| +|`type`| 0.`DisplayEventReceiver::DISPLAY_EVENT_NULL`, 1.`DisplayEventReceiver::DISPLAY_EVENT_VSYNC`, 2.`DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG`, 3.`DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE`, 4.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE`, 5.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH`, |Value obtained from FuzzedDataProvider| +|`events`| 0.`Looper::EVENT_INPUT`, 1.`Looper::EVENT_OUTPUT`, 2.`Looper::EVENT_ERROR`, 3.`Looper::EVENT_HANGUP`, 4.`Looper::EVENT_INVALID`, |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) libgui_displayEvent_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/libgui_displayEvent_fuzzer/libgui_displayEvent_fuzzer +``` diff --git a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp new file mode 100644 index 0000000000..c97770bf0e --- /dev/null +++ b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp @@ -0,0 +1,388 @@ +/* + * 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 <gui/BufferQueueConsumer.h> +#include <gui/BufferQueueCore.h> +#include <gui/BufferQueueProducer.h> +#include <gui/bufferqueue/2.0/types.h> +#include <system/window.h> + +#include <libgui_fuzzer_utils.h> + +using namespace android; +using namespace hardware::graphics::bufferqueue; +using namespace V1_0::utils; +using namespace V2_0::utils; + +constexpr int32_t kMaxBytes = 256; + +constexpr int32_t kError[] = { + OK, NO_MEMORY, NO_INIT, BAD_VALUE, DEAD_OBJECT, INVALID_OPERATION, + TIMED_OUT, WOULD_BLOCK, UNKNOWN_ERROR, ALREADY_EXISTS, +}; + +constexpr int32_t kAPIConnection[] = { + BufferQueueCore::CURRENTLY_CONNECTED_API, + BufferQueueCore::NO_CONNECTED_API, + NATIVE_WINDOW_API_EGL, + NATIVE_WINDOW_API_CPU, + NATIVE_WINDOW_API_MEDIA, + NATIVE_WINDOW_API_CAMERA, +}; + +class BufferQueueFuzzer { +public: + BufferQueueFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + +private: + void invokeTypes(); + void invokeH2BGraphicBufferV1(); + void invokeH2BGraphicBufferV2(); + void invokeBufferQueueConsumer(); + void invokeBufferQueueProducer(); + void invokeBlastBufferQueue(); + void invokeQuery(sp<BufferQueueProducer>); + void invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer>); + void invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer>); + void invokeAcquireBuffer(sp<BufferQueueConsumer>); + void invokeOccupancyTracker(sp<BufferQueueConsumer>); + sp<SurfaceControl> makeSurfaceControl(); + sp<BLASTBufferQueue> makeBLASTBufferQueue(sp<SurfaceControl>); + + FuzzedDataProvider mFdp; +}; + +class ManageResourceHandle { +public: + ManageResourceHandle(FuzzedDataProvider* fdp) { + mNativeHandle = native_handle_create(0 /*numFds*/, 1 /*numInts*/); + mShouldOwn = fdp->ConsumeBool(); + mStream = NativeHandle::create(mNativeHandle, mShouldOwn); + } + ~ManageResourceHandle() { + if (!mShouldOwn) { + native_handle_close(mNativeHandle); + native_handle_delete(mNativeHandle); + } + } + sp<NativeHandle> getStream() { return mStream; } + +private: + bool mShouldOwn; + sp<NativeHandle> mStream; + native_handle_t* mNativeHandle; +}; + +sp<SurfaceControl> BufferQueueFuzzer::makeSurfaceControl() { + sp<IBinder> handle; + const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient()); + sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient); + sp<BnGraphicBufferProducer> producer; + return sp<SurfaceControl>::make(client, handle, mFdp.ConsumeIntegral<int32_t>(), + mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<int32_t>(), + mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint32_t>()); +} + +sp<BLASTBufferQueue> BufferQueueFuzzer::makeBLASTBufferQueue(sp<SurfaceControl> surface) { + return sp<BLASTBufferQueue>::make(mFdp.ConsumeRandomLengthString(kMaxBytes), surface, + mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<int32_t>()); +} + +void BufferQueueFuzzer::invokeBlastBufferQueue() { + sp<SurfaceControl> surface = makeSurfaceControl(); + sp<BLASTBufferQueue> queue = makeBLASTBufferQueue(surface); + + BufferItem item; + queue->onFrameAvailable(item); + queue->onFrameReplaced(item); + uint64_t bufferId = mFdp.ConsumeIntegral<uint64_t>(); + queue->onFrameDequeued(bufferId); + queue->onFrameCancelled(bufferId); + + SurfaceComposerClient::Transaction next; + uint64_t frameNumber = mFdp.ConsumeIntegral<uint64_t>(); + queue->mergeWithNextTransaction(&next, frameNumber); + queue->applyPendingTransactions(frameNumber); + + queue->update(surface, mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<int32_t>()); + queue->setFrameRate(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeIntegral<int8_t>(), + mFdp.ConsumeBool() /*shouldBeSeamless*/); + FrameTimelineInfo info; + queue->setFrameTimelineInfo(info); + + ManageResourceHandle handle(&mFdp); + queue->setSidebandStream(handle.getStream()); + + queue->getLastTransformHint(); + queue->getLastAcquiredFrameNum(); + + CompositorTiming compTiming; + sp<Fence> previousFence = new Fence(memfd_create("pfd", MFD_ALLOW_SEALING)); + sp<Fence> gpuFence = new Fence(memfd_create("gfd", MFD_ALLOW_SEALING)); + FrameEventHistoryStats frameStats(frameNumber, gpuFence, compTiming, + mFdp.ConsumeIntegral<int64_t>(), + mFdp.ConsumeIntegral<int64_t>()); + std::vector<SurfaceControlStats> stats; + sp<Fence> presentFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING)); + SurfaceControlStats controlStats(surface, mFdp.ConsumeIntegral<int64_t>(), + mFdp.ConsumeIntegral<int64_t>(), presentFence, previousFence, + mFdp.ConsumeIntegral<uint32_t>(), frameStats); + stats.push_back(controlStats); +} + +void BufferQueueFuzzer::invokeQuery(sp<BufferQueueProducer> producer) { + int32_t value; + producer->query(mFdp.ConsumeIntegral<int32_t>(), &value); +} + +void BufferQueueFuzzer::invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer> producer) { + int32_t value; + producer->query(mFdp.ConsumeIntegral<int32_t>(), &value); +} + +void BufferQueueFuzzer::invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer> producer) { + int32_t value; + producer->query(mFdp.ConsumeIntegral<int32_t>(), &value); +} + +void BufferQueueFuzzer::invokeBufferQueueProducer() { + sp<BufferQueueCore> core(new BufferQueueCore()); + sp<BufferQueueProducer> producer(new BufferQueueProducer(core)); + const sp<android::IProducerListener> listener; + android::IGraphicBufferProducer::QueueBufferOutput output; + uint32_t api = mFdp.ConsumeIntegral<uint32_t>(); + producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output); + + sp<GraphicBuffer> buffer; + int32_t slot = mFdp.ConsumeIntegral<int32_t>(); + uint32_t maxBuffers = mFdp.ConsumeIntegral<uint32_t>(); + producer->requestBuffer(slot, &buffer); + producer->setMaxDequeuedBufferCount(maxBuffers); + producer->setAsyncMode(mFdp.ConsumeBool() /*async*/); + + android::IGraphicBufferProducer::QueueBufferInput input; + producer->attachBuffer(&slot, buffer); + producer->queueBuffer(slot, input, &output); + + int32_t format = mFdp.ConsumeIntegral<int32_t>(); + uint32_t width = mFdp.ConsumeIntegral<uint32_t>(); + uint32_t height = mFdp.ConsumeIntegral<uint32_t>(); + uint64_t usage = mFdp.ConsumeIntegral<uint64_t>(); + uint64_t outBufferAge; + FrameEventHistoryDelta outTimestamps; + sp<android::Fence> fence; + producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge, + &outTimestamps); + producer->detachBuffer(slot); + producer->detachNextBuffer(&buffer, &fence); + producer->cancelBuffer(slot, fence); + + invokeQuery(producer); + + ManageResourceHandle handle(&mFdp); + producer->setSidebandStream(handle.getStream()); + + producer->allocateBuffers(width, height, format, usage); + producer->allowAllocation(mFdp.ConsumeBool() /*allow*/); + producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/); + producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/); + producer->setLegacyBufferDrop(mFdp.ConsumeBool() /*drop*/); + producer->setAutoPrerotation(mFdp.ConsumeBool() /*autoPrerotation*/); + + producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>()); + producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>()); + producer->disconnect(api); +} + +void BufferQueueFuzzer::invokeAcquireBuffer(sp<BufferQueueConsumer> consumer) { + BufferItem item; + consumer->acquireBuffer(&item, mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint64_t>()); +} + +void BufferQueueFuzzer::invokeOccupancyTracker(sp<BufferQueueConsumer> consumer) { + String8 outResult; + String8 prefix((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str()); + consumer->dumpState(prefix, &outResult); + + std::vector<OccupancyTracker::Segment> outHistory; + consumer->getOccupancyHistory(mFdp.ConsumeBool() /*forceFlush*/, &outHistory); +} + +void BufferQueueFuzzer::invokeBufferQueueConsumer() { + sp<BufferQueueCore> core(new BufferQueueCore()); + sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core)); + sp<android::IConsumerListener> listener; + consumer->consumerConnect(listener, mFdp.ConsumeBool() /*controlledByApp*/); + invokeAcquireBuffer(consumer); + + int32_t slot = mFdp.ConsumeIntegral<int32_t>(); + sp<GraphicBuffer> buffer = + new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint64_t>()); + consumer->attachBuffer(&slot, buffer); + consumer->detachBuffer(slot); + + consumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint32_t>()); + consumer->setMaxBufferCount(mFdp.ConsumeIntegral<int32_t>()); + consumer->setMaxAcquiredBufferCount(mFdp.ConsumeIntegral<int32_t>()); + + String8 name((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str()); + consumer->setConsumerName(name); + consumer->setDefaultBufferFormat(mFdp.ConsumeIntegral<int32_t>()); + android_dataspace dataspace = + static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces)); + consumer->setDefaultBufferDataSpace(dataspace); + + consumer->setTransformHint(mFdp.ConsumeIntegral<uint32_t>()); + consumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>()); + consumer->setConsumerIsProtected(mFdp.ConsumeBool() /*isProtected*/); + invokeOccupancyTracker(consumer); + + sp<Fence> releaseFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING)); + consumer->releaseBuffer(mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint64_t>(), + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); + consumer->consumerDisconnect(); +} + +void BufferQueueFuzzer::invokeTypes() { + HStatus hStatus; + int32_t status = mFdp.PickValueInArray(kError); + bool bufferNeedsReallocation = mFdp.ConsumeBool(); + bool releaseAllBuffers = mFdp.ConsumeBool(); + b2h(status, &hStatus, &bufferNeedsReallocation, &releaseAllBuffers); + h2b(hStatus, &status); + + HConnectionType type; + int32_t apiConnection = mFdp.PickValueInArray(kAPIConnection); + b2h(apiConnection, &type); + h2b(type, &apiConnection); +} + +void BufferQueueFuzzer::invokeH2BGraphicBufferV1() { + sp<V1_0::utils::H2BGraphicBufferProducer> producer( + new V1_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV1())); + const sp<android::IProducerListener> listener; + android::IGraphicBufferProducer::QueueBufferOutput output; + uint32_t api = mFdp.ConsumeIntegral<uint32_t>(); + producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output); + + sp<GraphicBuffer> buffer; + int32_t slot = mFdp.ConsumeIntegral<int32_t>(); + producer->requestBuffer(slot, &buffer); + producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<int32_t>()); + producer->setAsyncMode(mFdp.ConsumeBool()); + + android::IGraphicBufferProducer::QueueBufferInput input; + input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING)); + producer->attachBuffer(&slot, buffer); + producer->queueBuffer(slot, input, &output); + + int32_t format = mFdp.ConsumeIntegral<int32_t>(); + uint32_t width = mFdp.ConsumeIntegral<uint32_t>(); + uint32_t height = mFdp.ConsumeIntegral<uint32_t>(); + uint64_t usage = mFdp.ConsumeIntegral<uint64_t>(); + uint64_t outBufferAge; + FrameEventHistoryDelta outTimestamps; + sp<android::Fence> fence; + producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge, + &outTimestamps); + producer->detachBuffer(slot); + producer->cancelBuffer(slot, fence); + + invokeQuery(producer); + + ManageResourceHandle handle(&mFdp); + producer->setSidebandStream(handle.getStream()); + + producer->allocateBuffers(width, height, format, usage); + producer->allowAllocation(mFdp.ConsumeBool() /*allow*/); + producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/); + producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/); + + producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>()); + producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>()); + producer->disconnect(api); +} + +void BufferQueueFuzzer::invokeH2BGraphicBufferV2() { + sp<V2_0::utils::H2BGraphicBufferProducer> producer( + new V2_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV2())); + const sp<android::IProducerListener> listener; + android::IGraphicBufferProducer::QueueBufferOutput output; + uint32_t api = mFdp.ConsumeIntegral<uint32_t>(); + producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output); + + sp<GraphicBuffer> buffer; + int32_t slot = mFdp.ConsumeIntegral<int32_t>(); + producer->requestBuffer(slot, &buffer); + producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<uint32_t>()); + producer->setAsyncMode(mFdp.ConsumeBool()); + + android::IGraphicBufferProducer::QueueBufferInput input; + input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING)); + producer->attachBuffer(&slot, buffer); + producer->queueBuffer(slot, input, &output); + + int32_t format = mFdp.ConsumeIntegral<int32_t>(); + uint32_t width = mFdp.ConsumeIntegral<uint32_t>(); + uint32_t height = mFdp.ConsumeIntegral<uint32_t>(); + uint64_t usage = mFdp.ConsumeIntegral<uint64_t>(); + uint64_t outBufferAge; + FrameEventHistoryDelta outTimestamps; + sp<android::Fence> fence; + producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge, + &outTimestamps); + producer->detachBuffer(slot); + producer->cancelBuffer(slot, fence); + + invokeQuery(producer); + + ManageResourceHandle handle(&mFdp); + producer->setSidebandStream(handle.getStream()); + + producer->allocateBuffers(width, height, format, usage); + producer->allowAllocation(mFdp.ConsumeBool() /*allow*/); + producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/); + producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/); + + producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>()); + producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>()); + producer->disconnect(api); +} + +void BufferQueueFuzzer::process() { + invokeBlastBufferQueue(); + invokeH2BGraphicBufferV1(); + invokeH2BGraphicBufferV2(); + invokeTypes(); + invokeBufferQueueConsumer(); + invokeBufferQueueProducer(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + BufferQueueFuzzer bufferQueueFuzzer(data, size); + bufferQueueFuzzer.process(); + return 0; +} diff --git a/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp b/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp new file mode 100644 index 0000000000..24a046d3a9 --- /dev/null +++ b/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp @@ -0,0 +1,82 @@ +/* + * 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 <gui/BufferQueueConsumer.h> +#include <gui/BufferQueueCore.h> +#include <gui/BufferQueueProducer.h> +#include <gui/GLConsumer.h> +#include <libgui_fuzzer_utils.h> + +using namespace android; + +constexpr int32_t kMinBuffer = 0; +constexpr int32_t kMaxBuffer = 100000; + +class ConsumerFuzzer { +public: + ConsumerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + +private: + FuzzedDataProvider mFdp; +}; + +void ConsumerFuzzer::process() { + sp<BufferQueueCore> core(new BufferQueueCore()); + sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); + + uint64_t maxBuffers = mFdp.ConsumeIntegralInRange<uint64_t>(kMinBuffer, kMaxBuffer); + sp<CpuConsumer> cpu( + new CpuConsumer(consumer, maxBuffers, mFdp.ConsumeBool() /*controlledByApp*/)); + CpuConsumer::LockedBuffer lockBuffer; + cpu->lockNextBuffer(&lockBuffer); + cpu->unlockBuffer(lockBuffer); + cpu->abandon(); + + uint32_t tex = mFdp.ConsumeIntegral<uint32_t>(); + sp<GLConsumer> glComsumer(new GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, + mFdp.ConsumeBool() /*useFenceSync*/, + mFdp.ConsumeBool() /*isControlledByApp*/)); + sp<Fence> releaseFence = new Fence(memfd_create("rfd", MFD_ALLOW_SEALING)); + glComsumer->setReleaseFence(releaseFence); + glComsumer->updateTexImage(); + glComsumer->releaseTexImage(); + + sp<GraphicBuffer> buffer = + new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint64_t>()); + float mtx[16]; + glComsumer->getTransformMatrix(mtx); + glComsumer->computeTransformMatrix(mtx, buffer, getRect(&mFdp), + mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeBool() /*filtering*/); + glComsumer->scaleDownCrop(getRect(&mFdp), mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint32_t>()); + + glComsumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint32_t>()); + glComsumer->setFilteringEnabled(mFdp.ConsumeBool() /*enabled*/); + + glComsumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>()); + glComsumer->attachToContext(tex); + glComsumer->abandon(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + ConsumerFuzzer consumerFuzzer(data, size); + consumerFuzzer.process(); + return 0; +} diff --git a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp new file mode 100644 index 0000000000..6d5ae49635 --- /dev/null +++ b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp @@ -0,0 +1,104 @@ +/* + * 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 <android/gui/ISurfaceComposer.h> + +#include <libgui_fuzzer_utils.h> + +using namespace android; + +constexpr gui::ISurfaceComposer::VsyncSource kVsyncSource[] = { + gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger, +}; + +constexpr gui::ISurfaceComposer::EventRegistration kEventRegistration[] = { + gui::ISurfaceComposer::EventRegistration::modeChanged, + gui::ISurfaceComposer::EventRegistration::frameRateOverride, +}; + +constexpr uint32_t kDisplayEvent[] = { + DisplayEventReceiver::DISPLAY_EVENT_NULL, + DisplayEventReceiver::DISPLAY_EVENT_VSYNC, + DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, + DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, + DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE, + DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH, +}; + +constexpr int32_t kEvents[] = { + Looper::EVENT_INPUT, Looper::EVENT_OUTPUT, Looper::EVENT_ERROR, + Looper::EVENT_HANGUP, Looper::EVENT_INVALID, +}; + +DisplayEventReceiver::Event buildDisplayEvent(FuzzedDataProvider* fdp, uint32_t type, + DisplayEventReceiver::Event event) { + switch (type) { + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: { + event.vsync.count = fdp->ConsumeIntegral<uint32_t>(); + event.vsync.vsyncData.frameInterval = fdp->ConsumeIntegral<uint64_t>(); + event.vsync.vsyncData.preferredFrameTimelineIndex = fdp->ConsumeIntegral<uint32_t>(); + for (size_t idx = 0; idx < gui::VsyncEventData::kFrameTimelinesLength; ++idx) { + event.vsync.vsyncData.frameTimelines[idx].vsyncId = fdp->ConsumeIntegral<int64_t>(); + event.vsync.vsyncData.frameTimelines[idx].deadlineTimestamp = + fdp->ConsumeIntegral<uint64_t>(); + event.vsync.vsyncData.frameTimelines[idx].expectedPresentationTime = + fdp->ConsumeIntegral<uint64_t>(); + } + break; + + } + case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: { + event.hotplug = DisplayEventReceiver::Event::Hotplug{fdp->ConsumeBool() /*connected*/}; + break; + } + case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: { + event.modeChange = + DisplayEventReceiver::Event::ModeChange{fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int64_t>()}; + break; + } + case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE: + case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH: { + event.frameRateOverride = + DisplayEventReceiver::Event::FrameRateOverride{fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeFloatingPoint< + float>()}; + break; + } + } + return event; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider fdp(data, size); + sp<Looper> looper; + sp<FakeDisplayEventDispatcher> dispatcher( + new FakeDisplayEventDispatcher(looper, fdp.PickValueInArray(kVsyncSource), + fdp.PickValueInArray(kEventRegistration))); + + dispatcher->initialize(); + DisplayEventReceiver::Event event; + uint32_t type = fdp.PickValueInArray(kDisplayEvent); + PhysicalDisplayId displayId; + event.header = + DisplayEventReceiver::Event::Header{type, displayId, fdp.ConsumeIntegral<int64_t>()}; + event = buildDisplayEvent(&fdp, type, event); + + dispatcher->injectEvent(event); + dispatcher->handleEvent(0, fdp.PickValueInArray(kEvents), nullptr); + return 0; +} diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h new file mode 100644 index 0000000000..d51f6850c0 --- /dev/null +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -0,0 +1,313 @@ +/* + * Copyright 2021 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 <android/gui/BnRegionSamplingListener.h> +#include <android/gui/BnSurfaceComposer.h> +#include <android/gui/BnSurfaceComposerClient.h> +#include <android/gui/IDisplayEventConnection.h> +#include <android/gui/ISurfaceComposerClient.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <gmock/gmock.h> +#include <gui/BLASTBufferQueue.h> +#include <gui/DisplayEventDispatcher.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/LayerDebugInfo.h> +#include <gui/LayerState.h> +#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> +#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h> +#include <ui/fuzzer/FuzzableDataspaces.h> + +namespace android { + +constexpr uint32_t kOrientation[] = { + ui::Transform::ROT_0, ui::Transform::FLIP_H, ui::Transform::FLIP_V, + ui::Transform::ROT_90, ui::Transform::ROT_180, ui::Transform::ROT_270, +}; + +Rect getRect(FuzzedDataProvider* fdp) { + const int32_t left = fdp->ConsumeIntegral<int32_t>(); + const int32_t top = fdp->ConsumeIntegral<int32_t>(); + const int32_t right = fdp->ConsumeIntegral<int32_t>(); + const int32_t bottom = fdp->ConsumeIntegral<int32_t>(); + return Rect(left, top, right, bottom); +} + +gui::DisplayBrightness getBrightness(FuzzedDataProvider* fdp) { + static constexpr float kMinBrightness = 0; + static constexpr float kMaxBrightness = 1; + gui::DisplayBrightness brightness; + brightness.sdrWhitePoint = + fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness); + brightness.sdrWhitePointNits = + fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness); + brightness.displayBrightness = + fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness); + brightness.displayBrightnessNits = + fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness); + return brightness; +} + +class FakeBnSurfaceComposer : public gui::BnSurfaceComposer { +public: + MOCK_METHOD(binder::Status, bootFinished, (), (override)); + MOCK_METHOD(binder::Status, createDisplayEventConnection, + (gui::ISurfaceComposer::VsyncSource, gui::ISurfaceComposer::EventRegistration, + sp<gui::IDisplayEventConnection>*), + (override)); + MOCK_METHOD(binder::Status, createConnection, (sp<gui::ISurfaceComposerClient>*), (override)); + MOCK_METHOD(binder::Status, createDisplay, (const std::string&, bool, sp<IBinder>*), + (override)); + MOCK_METHOD(binder::Status, destroyDisplay, (const sp<IBinder>&), (override)); + MOCK_METHOD(binder::Status, getPhysicalDisplayIds, (std::vector<int64_t>*), (override)); + MOCK_METHOD(binder::Status, getPhysicalDisplayToken, (int64_t, sp<IBinder>*), (override)); + MOCK_METHOD(binder::Status, setPowerMode, (const sp<IBinder>&, int), (override)); + MOCK_METHOD(binder::Status, getSupportedFrameTimestamps, (std::vector<FrameEvent>*), + (override)); + MOCK_METHOD(binder::Status, getDisplayStats, (const sp<IBinder>&, gui::DisplayStatInfo*), + (override)); + MOCK_METHOD(binder::Status, getDisplayState, (const sp<IBinder>&, gui::DisplayState*), + (override)); + MOCK_METHOD(binder::Status, getStaticDisplayInfo, (const sp<IBinder>&, gui::StaticDisplayInfo*), + (override)); + MOCK_METHOD(binder::Status, getDynamicDisplayInfo, + (const sp<IBinder>&, gui::DynamicDisplayInfo*), (override)); + MOCK_METHOD(binder::Status, getDisplayNativePrimaries, + (const sp<IBinder>&, gui::DisplayPrimaries*), (override)); + MOCK_METHOD(binder::Status, setActiveColorMode, (const sp<IBinder>&, int), (override)); + MOCK_METHOD(binder::Status, setBootDisplayMode, (const sp<IBinder>&, int), (override)); + MOCK_METHOD(binder::Status, clearBootDisplayMode, (const sp<IBinder>&), (override)); + MOCK_METHOD(binder::Status, getBootDisplayModeSupport, (bool*), (override)); + MOCK_METHOD(binder::Status, setAutoLowLatencyMode, (const sp<IBinder>&, bool), (override)); + MOCK_METHOD(binder::Status, setGameContentType, (const sp<IBinder>&, bool), (override)); + MOCK_METHOD(binder::Status, captureDisplay, + (const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&), (override)); + MOCK_METHOD(binder::Status, captureDisplayById, (int64_t, const sp<IScreenCaptureListener>&), + (override)); + MOCK_METHOD(binder::Status, captureLayers, + (const LayerCaptureArgs&, const sp<IScreenCaptureListener>&), (override)); + MOCK_METHOD(binder::Status, clearAnimationFrameStats, (), (override)); + MOCK_METHOD(binder::Status, getAnimationFrameStats, (gui::FrameStats*), (override)); + MOCK_METHOD(binder::Status, overrideHdrTypes, (const sp<IBinder>&, const std::vector<int32_t>&), + (override)); + MOCK_METHOD(binder::Status, onPullAtom, (int32_t, gui::PullAtomData*), (override)); + MOCK_METHOD(binder::Status, enableVSyncInjections, (bool), (override)); + MOCK_METHOD(binder::Status, injectVSync, (int64_t), (override)); + MOCK_METHOD(binder::Status, getLayerDebugInfo, (std::vector<gui::LayerDebugInfo>*), (override)); + MOCK_METHOD(binder::Status, getColorManagement, (bool*), (override)); + MOCK_METHOD(binder::Status, getCompositionPreference, (gui::CompositionPreference*), + (override)); + MOCK_METHOD(binder::Status, getDisplayedContentSamplingAttributes, + (const sp<IBinder>&, gui::ContentSamplingAttributes*), (override)); + MOCK_METHOD(binder::Status, setDisplayContentSamplingEnabled, + (const sp<IBinder>&, bool, int8_t, int64_t), (override)); + MOCK_METHOD(binder::Status, getDisplayedContentSample, + (const sp<IBinder>&, int64_t, int64_t, gui::DisplayedFrameStats*), (override)); + MOCK_METHOD(binder::Status, getProtectedContentSupport, (bool*), (override)); + MOCK_METHOD(binder::Status, isWideColorDisplay, (const sp<IBinder>&, bool*), (override)); + MOCK_METHOD(binder::Status, addRegionSamplingListener, + (const gui::ARect&, const sp<IBinder>&, const sp<gui::IRegionSamplingListener>&), + (override)); + MOCK_METHOD(binder::Status, removeRegionSamplingListener, + (const sp<gui::IRegionSamplingListener>&), (override)); + MOCK_METHOD(binder::Status, addFpsListener, (int32_t, const sp<gui::IFpsListener>&), + (override)); + MOCK_METHOD(binder::Status, removeFpsListener, (const sp<gui::IFpsListener>&), (override)); + MOCK_METHOD(binder::Status, addTunnelModeEnabledListener, + (const sp<gui::ITunnelModeEnabledListener>&), (override)); + MOCK_METHOD(binder::Status, removeTunnelModeEnabledListener, + (const sp<gui::ITunnelModeEnabledListener>&), (override)); + MOCK_METHOD(binder::Status, setDesiredDisplayModeSpecs, + (const sp<IBinder>&, int32_t, bool, float, float, float, + float appRequestRefreshRateMax), + (override)); + MOCK_METHOD(binder::Status, getDesiredDisplayModeSpecs, + (const sp<IBinder>&, gui::DisplayModeSpecs*), (override)); + MOCK_METHOD(binder::Status, getDisplayBrightnessSupport, (const sp<IBinder>&, bool*), + (override)); + MOCK_METHOD(binder::Status, setDisplayBrightness, + (const sp<IBinder>&, const gui::DisplayBrightness&), (override)); + MOCK_METHOD(binder::Status, addHdrLayerInfoListener, + (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override)); + MOCK_METHOD(binder::Status, removeHdrLayerInfoListener, + (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override)); + MOCK_METHOD(binder::Status, notifyPowerBoost, (int), (override)); + MOCK_METHOD(binder::Status, setGlobalShadowSettings, + (const gui::Color&, const gui::Color&, float, float, float), (override)); + MOCK_METHOD(binder::Status, getDisplayDecorationSupport, + (const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override)); + MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override)); + MOCK_METHOD(binder::Status, addTransactionTraceListener, + (const sp<gui::ITransactionTraceListener>&), (override)); + MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override)); + MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override)); + MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp<gui::IWindowInfosListener>&), + (override)); + MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&), + (override)); +}; + +class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient { +public: + MOCK_METHOD(binder::Status, createSurface, + (const std::string& name, int32_t flags, const sp<IBinder>& parent, + const gui::LayerMetadata& metadata, gui::CreateSurfaceResult* outResult), + (override)); + + MOCK_METHOD(binder::Status, clearLayerFrameStats, (const sp<IBinder>& handle), (override)); + + MOCK_METHOD(binder::Status, getLayerFrameStats, + (const sp<IBinder>& handle, gui::FrameStats* outStats), (override)); + + MOCK_METHOD(binder::Status, mirrorSurface, + (const sp<IBinder>& mirrorFromHandle, gui::MirrorSurfaceResult* outResult), + (override)); + + MOCK_METHOD(binder::Status, mirrorDisplay, + (int64_t displayId, gui::MirrorSurfaceResult* outResult), (override)); +}; + +class FakeDisplayEventDispatcher : public DisplayEventDispatcher { +public: + FakeDisplayEventDispatcher(const sp<Looper>& looper, + gui::ISurfaceComposer::VsyncSource vsyncSource, + gui::ISurfaceComposer::EventRegistration eventRegistration) + : DisplayEventDispatcher(looper, vsyncSource, eventRegistration){}; + + MOCK_METHOD4(dispatchVsync, void(nsecs_t, PhysicalDisplayId, uint32_t, VsyncEventData)); + MOCK_METHOD3(dispatchHotplug, void(nsecs_t, PhysicalDisplayId, bool)); + MOCK_METHOD4(dispatchModeChanged, void(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t)); + MOCK_METHOD2(dispatchNullEvent, void(nsecs_t, PhysicalDisplayId)); + MOCK_METHOD3(dispatchFrameRateOverrides, + void(nsecs_t, PhysicalDisplayId, std::vector<FrameRateOverride>)); +}; + +} // namespace android + +namespace android::hardware { + +namespace graphics::bufferqueue::V1_0::utils { + +class FakeGraphicBufferProducerV1 : public HGraphicBufferProducer { +public: + FakeGraphicBufferProducerV1() { + ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return 0; }); + ON_CALL(*this, setAsyncMode).WillByDefault([]() { return 0; }); + ON_CALL(*this, detachBuffer).WillByDefault([]() { return 0; }); + ON_CALL(*this, cancelBuffer).WillByDefault([]() { return 0; }); + ON_CALL(*this, disconnect).WillByDefault([]() { return 0; }); + ON_CALL(*this, setSidebandStream).WillByDefault([]() { return 0; }); + ON_CALL(*this, allowAllocation).WillByDefault([]() { return 0; }); + ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return 0; }); + ON_CALL(*this, setSharedBufferMode).WillByDefault([]() { return 0; }); + ON_CALL(*this, setAutoRefresh).WillByDefault([]() { return 0; }); + ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return 0; }); + ON_CALL(*this, setLegacyBufferDrop).WillByDefault([]() { return 0; }); + }; + MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb)); + MOCK_METHOD1(setMaxDequeuedBufferCount, Return<int32_t>(int32_t)); + MOCK_METHOD1(setAsyncMode, Return<int32_t>(bool)); + MOCK_METHOD6(dequeueBuffer, + Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t, + bool, dequeueBuffer_cb)); + MOCK_METHOD1(detachBuffer, Return<int32_t>(int)); + MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb)); + MOCK_METHOD2(attachBuffer, Return<void>(const media::V1_0::AnwBuffer&, attachBuffer_cb)); + MOCK_METHOD3( + queueBuffer, + Return<void>( + int, + const graphics::bufferqueue::V1_0::IGraphicBufferProducer::QueueBufferInput&, + queueBuffer_cb)); + MOCK_METHOD2(cancelBuffer, Return<int32_t>(int, const hidl_handle&)); + MOCK_METHOD2(query, Return<void>(int32_t, query_cb)); + MOCK_METHOD4(connect, + Return<void>(const sp<graphics::bufferqueue::V1_0::IProducerListener>&, int32_t, + bool, connect_cb)); + MOCK_METHOD2(disconnect, + Return<int32_t>( + int, graphics::bufferqueue::V1_0::IGraphicBufferProducer::DisconnectMode)); + MOCK_METHOD1(setSidebandStream, Return<int32_t>(const hidl_handle&)); + MOCK_METHOD4(allocateBuffers, + Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t)); + MOCK_METHOD1(allowAllocation, Return<int32_t>(bool)); + MOCK_METHOD1(setGenerationNumber, Return<int32_t>(uint32_t)); + MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb)); + MOCK_METHOD1(setSharedBufferMode, Return<int32_t>(bool)); + MOCK_METHOD1(setAutoRefresh, Return<int32_t>(bool)); + MOCK_METHOD1(setDequeueTimeout, Return<int32_t>(nsecs_t)); + MOCK_METHOD1(setLegacyBufferDrop, Return<int32_t>(bool)); + MOCK_METHOD1(getLastQueuedBuffer, Return<void>(getLastQueuedBuffer_cb)); + MOCK_METHOD1(getFrameTimestamps, Return<void>(getFrameTimestamps_cb)); + MOCK_METHOD1(getUniqueId, Return<void>(getUniqueId_cb)); +}; + +}; // namespace graphics::bufferqueue::V1_0::utils + +namespace graphics::bufferqueue::V2_0::utils { + +class FakeGraphicBufferProducerV2 : public HGraphicBufferProducer { +public: + FakeGraphicBufferProducerV2() { + ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, setAsyncMode).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, detachBuffer).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, cancelBuffer).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, disconnect).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, allocateBuffers).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, allowAllocation).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, getUniqueId).WillByDefault([]() { return 0; }); + }; + MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb)); + MOCK_METHOD1(setMaxDequeuedBufferCount, Return<graphics::bufferqueue::V2_0::Status>(int)); + MOCK_METHOD1(setAsyncMode, Return<graphics::bufferqueue::V2_0::Status>(bool)); + MOCK_METHOD2( + dequeueBuffer, + Return<void>( + const graphics::bufferqueue::V2_0::IGraphicBufferProducer::DequeueBufferInput&, + dequeueBuffer_cb)); + MOCK_METHOD1(detachBuffer, Return<graphics::bufferqueue::V2_0::Status>(int)); + MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb)); + MOCK_METHOD3(attachBuffer, + Return<void>(const graphics::common::V1_2::HardwareBuffer&, uint32_t, + attachBuffer_cb)); + MOCK_METHOD3( + queueBuffer, + Return<void>( + int, + const graphics::bufferqueue::V2_0::IGraphicBufferProducer::QueueBufferInput&, + queueBuffer_cb)); + MOCK_METHOD2(cancelBuffer, + Return<graphics::bufferqueue::V2_0::Status>(int, const hidl_handle&)); + MOCK_METHOD2(query, Return<void>(int32_t, query_cb)); + MOCK_METHOD4(connect, + Return<void>(const sp<graphics::bufferqueue::V2_0::IProducerListener>&, + graphics::bufferqueue::V2_0::ConnectionType, bool, connect_cb)); + MOCK_METHOD1(disconnect, + Return<graphics::bufferqueue::V2_0::Status>( + graphics::bufferqueue::V2_0::ConnectionType)); + MOCK_METHOD4(allocateBuffers, + Return<graphics::bufferqueue::V2_0::Status>(uint32_t, uint32_t, uint32_t, + uint64_t)); + MOCK_METHOD1(allowAllocation, Return<graphics::bufferqueue::V2_0::Status>(bool)); + MOCK_METHOD1(setGenerationNumber, Return<graphics::bufferqueue::V2_0::Status>(uint32_t)); + MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb)); + MOCK_METHOD1(setDequeueTimeout, Return<graphics::bufferqueue::V2_0::Status>(int64_t)); + MOCK_METHOD0(getUniqueId, Return<uint64_t>()); +}; + +}; // namespace graphics::bufferqueue::V2_0::utils +}; // namespace android::hardware diff --git a/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp b/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp new file mode 100644 index 0000000000..9f0f6cac19 --- /dev/null +++ b/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp @@ -0,0 +1,175 @@ +/* + * 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 <gui/BufferQueueConsumer.h> +#include <gui/BufferQueueCore.h> +#include <gui/BufferQueueProducer.h> +#include <gui/LayerMetadata.h> +#include <gui/OccupancyTracker.h> +#include <gui/StreamSplitter.h> +#include <gui/Surface.h> +#include <gui/SurfaceControl.h> +#include <gui/view/Surface.h> +#include <libgui_fuzzer_utils.h> +#include "android/view/LayerMetadataKey.h" + +using namespace android; + +constexpr int32_t kMaxBytes = 256; +constexpr int32_t kMatrixSize = 4; +constexpr int32_t kLayerMetadataKeyCount = 8; + +constexpr uint32_t kMetadataKey[] = { + (uint32_t)view::LayerMetadataKey::METADATA_OWNER_UID, + (uint32_t)view::LayerMetadataKey::METADATA_WINDOW_TYPE, + (uint32_t)view::LayerMetadataKey::METADATA_TASK_ID, + (uint32_t)view::LayerMetadataKey::METADATA_MOUSE_CURSOR, + (uint32_t)view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID, + (uint32_t)view::LayerMetadataKey::METADATA_OWNER_PID, + (uint32_t)view::LayerMetadataKey::METADATA_DEQUEUE_TIME, + (uint32_t)view::LayerMetadataKey::METADATA_GAME_MODE, +}; + +class ParcelableFuzzer { +public: + ParcelableFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + +private: + void invokeStreamSplitter(); + void invokeOccupancyTracker(); + void invokeLayerDebugInfo(); + void invokeLayerMetadata(); + void invokeViewSurface(); + + FuzzedDataProvider mFdp; +}; + +void ParcelableFuzzer::invokeViewSurface() { + view::Surface surface; + surface.name = String16((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str()); + Parcel parcel; + surface.writeToParcel(&parcel); + parcel.setDataPosition(0); + surface.readFromParcel(&parcel); + bool nameAlreadyWritten = mFdp.ConsumeBool(); + surface.writeToParcel(&parcel, nameAlreadyWritten); + parcel.setDataPosition(0); + surface.readFromParcel(&parcel, mFdp.ConsumeBool()); +} + +void ParcelableFuzzer::invokeLayerMetadata() { + std::unordered_map<uint32_t, std::vector<uint8_t>> map; + for (size_t idx = 0; idx < kLayerMetadataKeyCount; ++idx) { + std::vector<uint8_t> data; + for (size_t idx1 = 0; idx1 < mFdp.ConsumeIntegral<uint32_t>(); ++idx1) { + data.push_back(mFdp.ConsumeIntegral<uint8_t>()); + } + map[kMetadataKey[idx]] = data; + } + LayerMetadata metadata(map); + uint32_t key = mFdp.PickValueInArray(kMetadataKey); + metadata.setInt32(key, mFdp.ConsumeIntegral<int32_t>()); + metadata.itemToString(key, (mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str()); + + Parcel parcel; + metadata.writeToParcel(&parcel); + parcel.setDataPosition(0); + metadata.readFromParcel(&parcel); +} + +void ParcelableFuzzer::invokeLayerDebugInfo() { + gui::LayerDebugInfo info; + info.mName = mFdp.ConsumeRandomLengthString(kMaxBytes); + info.mParentName = mFdp.ConsumeRandomLengthString(kMaxBytes); + info.mType = mFdp.ConsumeRandomLengthString(kMaxBytes); + info.mLayerStack = mFdp.ConsumeIntegral<uint32_t>(); + info.mX = mFdp.ConsumeFloatingPoint<float>(); + info.mY = mFdp.ConsumeFloatingPoint<float>(); + info.mZ = mFdp.ConsumeIntegral<uint32_t>(); + info.mWidth = mFdp.ConsumeIntegral<int32_t>(); + info.mHeight = mFdp.ConsumeIntegral<int32_t>(); + info.mActiveBufferWidth = mFdp.ConsumeIntegral<int32_t>(); + info.mActiveBufferHeight = mFdp.ConsumeIntegral<int32_t>(); + info.mActiveBufferStride = mFdp.ConsumeIntegral<int32_t>(); + info.mActiveBufferFormat = mFdp.ConsumeIntegral<int32_t>(); + info.mNumQueuedFrames = mFdp.ConsumeIntegral<int32_t>(); + + info.mFlags = mFdp.ConsumeIntegral<uint32_t>(); + info.mPixelFormat = mFdp.ConsumeIntegral<int32_t>(); + info.mTransparentRegion = Region(getRect(&mFdp)); + info.mVisibleRegion = Region(getRect(&mFdp)); + info.mSurfaceDamageRegion = Region(getRect(&mFdp)); + info.mCrop = getRect(&mFdp); + info.mDataSpace = static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces)); + info.mColor = half4(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(), + mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>()); + for (size_t idx = 0; idx < kMatrixSize; ++idx) { + info.mMatrix[idx / 2][idx % 2] = mFdp.ConsumeFloatingPoint<float>(); + } + info.mIsOpaque = mFdp.ConsumeBool(); + info.mContentDirty = mFdp.ConsumeBool(); + info.mStretchEffect.width = mFdp.ConsumeFloatingPoint<float>(); + info.mStretchEffect.height = mFdp.ConsumeFloatingPoint<float>(); + info.mStretchEffect.vectorX = mFdp.ConsumeFloatingPoint<float>(); + info.mStretchEffect.vectorY = mFdp.ConsumeFloatingPoint<float>(); + info.mStretchEffect.maxAmountX = mFdp.ConsumeFloatingPoint<float>(); + info.mStretchEffect.maxAmountY = mFdp.ConsumeFloatingPoint<float>(); + info.mStretchEffect.mappedChildBounds = + FloatRect(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(), + mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>()); + + Parcel parcel; + info.writeToParcel(&parcel); + parcel.setDataPosition(0); + info.readFromParcel(&parcel); +} + +void ParcelableFuzzer::invokeOccupancyTracker() { + nsecs_t totalTime = mFdp.ConsumeIntegral<uint32_t>(); + size_t numFrames = mFdp.ConsumeIntegral<size_t>(); + float occupancyAverage = mFdp.ConsumeFloatingPoint<float>(); + OccupancyTracker::Segment segment(totalTime, numFrames, occupancyAverage, + mFdp.ConsumeBool() /*usedThirdBuffer*/); + Parcel parcel; + segment.writeToParcel(&parcel); + parcel.setDataPosition(0); + segment.readFromParcel(&parcel); +} + +void ParcelableFuzzer::invokeStreamSplitter() { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<StreamSplitter> splitter; + StreamSplitter::createSplitter(consumer, &splitter); + splitter->addOutput(producer); + std::string name = mFdp.ConsumeRandomLengthString(kMaxBytes); + splitter->setName(String8(name.c_str())); +} + +void ParcelableFuzzer::process() { + invokeStreamSplitter(); + invokeOccupancyTracker(); + invokeLayerDebugInfo(); + invokeLayerMetadata(); + invokeViewSurface(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + ParcelableFuzzer libGuiFuzzer(data, size); + libGuiFuzzer.process(); + return 0; +} diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp new file mode 100644 index 0000000000..48c90c5e8f --- /dev/null +++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp @@ -0,0 +1,306 @@ +/* + * 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 <android/hardware/power/Boost.h> +#include <fuzzbinder/libbinder_driver.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> +#include <libgui_fuzzer_utils.h> + +using namespace android; + +constexpr int32_t kRandomStringMaxBytes = 256; + +constexpr ui::ColorMode kColormodes[] = {ui::ColorMode::NATIVE, + ui::ColorMode::STANDARD_BT601_625, + ui::ColorMode::STANDARD_BT601_625_UNADJUSTED, + ui::ColorMode::STANDARD_BT601_525, + ui::ColorMode::STANDARD_BT601_525_UNADJUSTED, + ui::ColorMode::STANDARD_BT709, + ui::ColorMode::DCI_P3, + ui::ColorMode::SRGB, + ui::ColorMode::ADOBE_RGB, + ui::ColorMode::DISPLAY_P3, + ui::ColorMode::BT2020, + ui::ColorMode::BT2100_PQ, + ui::ColorMode::BT2100_HLG, + ui::ColorMode::DISPLAY_BT2020}; + +constexpr hardware::power::Boost kBoost[] = { + hardware::power::Boost::INTERACTION, hardware::power::Boost::DISPLAY_UPDATE_IMMINENT, + hardware::power::Boost::ML_ACC, hardware::power::Boost::AUDIO_LAUNCH, + hardware::power::Boost::CAMERA_LAUNCH, hardware::power::Boost::CAMERA_SHOT, +}; + +constexpr gui::TouchOcclusionMode kMode[] = { + gui::TouchOcclusionMode::BLOCK_UNTRUSTED, + gui::TouchOcclusionMode::USE_OPACITY, + gui::TouchOcclusionMode::ALLOW, +}; + +constexpr gui::WindowInfo::Flag kFlags[] = { + gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON, + gui::WindowInfo::Flag::DIM_BEHIND, + gui::WindowInfo::Flag::BLUR_BEHIND, + gui::WindowInfo::Flag::NOT_FOCUSABLE, + gui::WindowInfo::Flag::NOT_TOUCHABLE, + gui::WindowInfo::Flag::NOT_TOUCH_MODAL, + gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING, + gui::WindowInfo::Flag::KEEP_SCREEN_ON, + gui::WindowInfo::Flag::LAYOUT_IN_SCREEN, + gui::WindowInfo::Flag::LAYOUT_NO_LIMITS, + gui::WindowInfo::Flag::FULLSCREEN, + gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN, + gui::WindowInfo::Flag::DITHER, + gui::WindowInfo::Flag::SECURE, + gui::WindowInfo::Flag::SCALED, + gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES, + gui::WindowInfo::Flag::LAYOUT_INSET_DECOR, + gui::WindowInfo::Flag::ALT_FOCUSABLE_IM, + gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH, + gui::WindowInfo::Flag::SHOW_WHEN_LOCKED, + gui::WindowInfo::Flag::SHOW_WALLPAPER, + gui::WindowInfo::Flag::TURN_SCREEN_ON, + gui::WindowInfo::Flag::DISMISS_KEYGUARD, + gui::WindowInfo::Flag::SPLIT_TOUCH, + gui::WindowInfo::Flag::HARDWARE_ACCELERATED, + gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN, + gui::WindowInfo::Flag::TRANSLUCENT_STATUS, + gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION, + gui::WindowInfo::Flag::LOCAL_FOCUS_MODE, + gui::WindowInfo::Flag::SLIPPERY, + gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR, + gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS, +}; + +constexpr gui::WindowInfo::Type kType[] = { + gui::WindowInfo::Type::UNKNOWN, + gui::WindowInfo::Type::FIRST_APPLICATION_WINDOW, + gui::WindowInfo::Type::BASE_APPLICATION, + gui::WindowInfo::Type::APPLICATION, + gui::WindowInfo::Type::APPLICATION_STARTING, + gui::WindowInfo::Type::LAST_APPLICATION_WINDOW, + gui::WindowInfo::Type::FIRST_SUB_WINDOW, + gui::WindowInfo::Type::APPLICATION_PANEL, + gui::WindowInfo::Type::APPLICATION_MEDIA, + gui::WindowInfo::Type::APPLICATION_SUB_PANEL, + gui::WindowInfo::Type::APPLICATION_ATTACHED_DIALOG, + gui::WindowInfo::Type::APPLICATION_MEDIA_OVERLAY, +}; + +constexpr gui::WindowInfo::InputConfig kFeatures[] = { + gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL, + gui::WindowInfo::InputConfig::DISABLE_USER_ACTIVITY, + gui::WindowInfo::InputConfig::DROP_INPUT, + gui::WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED, + gui::WindowInfo::InputConfig::SPY, + gui::WindowInfo::InputConfig::INTERCEPTS_STYLUS, +}; + +class SurfaceComposerClientFuzzer { +public: + SurfaceComposerClientFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + +private: + void invokeSurfaceComposerClient(); + void invokeSurfaceComposerClientBinder(); + void invokeSurfaceComposerTransaction(); + void getWindowInfo(gui::WindowInfo*); + sp<SurfaceControl> makeSurfaceControl(); + BlurRegion getBlurRegion(); + void fuzzOnPullAtom(); + + FuzzedDataProvider mFdp; +}; + +BlurRegion SurfaceComposerClientFuzzer::getBlurRegion() { + int32_t left = mFdp.ConsumeIntegral<int32_t>(); + int32_t right = mFdp.ConsumeIntegral<int32_t>(); + int32_t top = mFdp.ConsumeIntegral<int32_t>(); + int32_t bottom = mFdp.ConsumeIntegral<int32_t>(); + uint32_t blurRadius = mFdp.ConsumeIntegral<uint32_t>(); + float alpha = mFdp.ConsumeFloatingPoint<float>(); + float cornerRadiusTL = mFdp.ConsumeFloatingPoint<float>(); + float cornerRadiusTR = mFdp.ConsumeFloatingPoint<float>(); + float cornerRadiusBL = mFdp.ConsumeFloatingPoint<float>(); + float cornerRadiusBR = mFdp.ConsumeFloatingPoint<float>(); + return BlurRegion{blurRadius, cornerRadiusTL, cornerRadiusTR, cornerRadiusBL, + cornerRadiusBR, alpha, left, top, + right, bottom}; +} + +void SurfaceComposerClientFuzzer::getWindowInfo(gui::WindowInfo* windowInfo) { + windowInfo->id = mFdp.ConsumeIntegral<int32_t>(); + windowInfo->name = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes); + windowInfo->layoutParamsFlags = mFdp.PickValueInArray(kFlags); + windowInfo->layoutParamsType = mFdp.PickValueInArray(kType); + windowInfo->frameLeft = mFdp.ConsumeIntegral<int32_t>(); + windowInfo->frameTop = mFdp.ConsumeIntegral<int32_t>(); + windowInfo->frameRight = mFdp.ConsumeIntegral<int32_t>(); + windowInfo->frameBottom = mFdp.ConsumeIntegral<int32_t>(); + windowInfo->surfaceInset = mFdp.ConsumeIntegral<int32_t>(); + windowInfo->alpha = mFdp.ConsumeFloatingPointInRange<float>(0, 1); + ui::Transform transform(mFdp.PickValueInArray(kOrientation)); + windowInfo->transform = transform; + windowInfo->touchableRegion = Region(getRect(&mFdp)); + windowInfo->replaceTouchableRegionWithCrop = mFdp.ConsumeBool(); + windowInfo->touchOcclusionMode = mFdp.PickValueInArray(kMode); + windowInfo->ownerPid = mFdp.ConsumeIntegral<int32_t>(); + windowInfo->ownerUid = mFdp.ConsumeIntegral<int32_t>(); + windowInfo->packageName = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes); + windowInfo->inputConfig = mFdp.PickValueInArray(kFeatures); +} + +sp<SurfaceControl> SurfaceComposerClientFuzzer::makeSurfaceControl() { + sp<IBinder> handle; + const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient()); + sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient); + sp<BnGraphicBufferProducer> producer; + uint32_t width = mFdp.ConsumeIntegral<uint32_t>(); + uint32_t height = mFdp.ConsumeIntegral<uint32_t>(); + uint32_t transformHint = mFdp.ConsumeIntegral<uint32_t>(); + uint32_t flags = mFdp.ConsumeIntegral<uint32_t>(); + int32_t format = mFdp.ConsumeIntegral<int32_t>(); + int32_t layerId = mFdp.ConsumeIntegral<int32_t>(); + return new SurfaceControl(client, handle, layerId, width, height, format, transformHint, flags); +} + +void SurfaceComposerClientFuzzer::invokeSurfaceComposerTransaction() { + sp<SurfaceControl> surface = makeSurfaceControl(); + + SurfaceComposerClient::Transaction transaction; + int32_t layer = mFdp.ConsumeIntegral<int32_t>(); + transaction.setLayer(surface, layer); + + sp<SurfaceControl> relativeSurface = makeSurfaceControl(); + transaction.setRelativeLayer(surface, relativeSurface, layer); + + Region transparentRegion(getRect(&mFdp)); + transaction.setTransparentRegionHint(surface, transparentRegion); + transaction.setAlpha(surface, mFdp.ConsumeFloatingPoint<float>()); + + transaction.setCornerRadius(surface, mFdp.ConsumeFloatingPoint<float>()); + transaction.setBackgroundBlurRadius(surface, mFdp.ConsumeFloatingPoint<float>()); + std::vector<BlurRegion> regions; + uint32_t vectorSize = mFdp.ConsumeIntegralInRange<uint32_t>(0, 100); + regions.resize(vectorSize); + for (size_t idx = 0; idx < vectorSize; ++idx) { + regions.push_back(getBlurRegion()); + } + transaction.setBlurRegions(surface, regions); + + transaction.setLayerStack(surface, {mFdp.ConsumeIntegral<uint32_t>()}); + half3 color = {mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(), + mFdp.ConsumeIntegral<uint32_t>()}; + transaction.setColor(surface, color); + transaction.setBackgroundColor(surface, color, mFdp.ConsumeFloatingPoint<float>(), + mFdp.PickValueInArray(kDataspaces)); + + transaction.setApi(surface, mFdp.ConsumeIntegral<int32_t>()); + transaction.setFrameRateSelectionPriority(surface, mFdp.ConsumeIntegral<int32_t>()); + transaction.setColorSpaceAgnostic(surface, mFdp.ConsumeBool() /*agnostic*/); + + gui::WindowInfo windowInfo; + getWindowInfo(&windowInfo); + transaction.setInputWindowInfo(surface, windowInfo); + Parcel windowParcel; + windowInfo.writeToParcel(&windowParcel); + windowParcel.setDataPosition(0); + windowInfo.readFromParcel(&windowParcel); + + windowInfo.addTouchableRegion(getRect(&mFdp)); + int32_t pointX = mFdp.ConsumeIntegral<int32_t>(); + int32_t pointY = mFdp.ConsumeIntegral<int32_t>(); + windowInfo.touchableRegionContainsPoint(pointX, pointY); + windowInfo.frameContainsPoint(pointX, pointY); + + Parcel transactionParcel; + transaction.writeToParcel(&transactionParcel); + transactionParcel.setDataPosition(0); + transaction.readFromParcel(&transactionParcel); + SurfaceComposerClient::Transaction::createFromParcel(&transactionParcel); +} + +void SurfaceComposerClientFuzzer::fuzzOnPullAtom() { + std::string outData; + bool success; + SurfaceComposerClient::onPullAtom(mFdp.ConsumeIntegral<int32_t>(), &outData, &success); +} + +void SurfaceComposerClientFuzzer::invokeSurfaceComposerClient() { + String8 displayName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str()); + sp<IBinder> displayToken = + SurfaceComposerClient::createDisplay(displayName, mFdp.ConsumeBool() /*secure*/); + SurfaceComposerClient::setDesiredDisplayModeSpecs(displayToken, mFdp.ConsumeIntegral<int32_t>(), + mFdp.ConsumeBool() /*allowGroupSwitching*/, + mFdp.ConsumeFloatingPoint<float>(), + mFdp.ConsumeFloatingPoint<float>(), + mFdp.ConsumeFloatingPoint<float>(), + mFdp.ConsumeFloatingPoint<float>()); + + ui::ColorMode colorMode = mFdp.PickValueInArray(kColormodes); + SurfaceComposerClient::setActiveColorMode(displayToken, colorMode); + SurfaceComposerClient::setAutoLowLatencyMode(displayToken, mFdp.ConsumeBool() /*on*/); + SurfaceComposerClient::setGameContentType(displayToken, mFdp.ConsumeBool() /*on*/); + SurfaceComposerClient::setDisplayPowerMode(displayToken, mFdp.ConsumeIntegral<int32_t>()); + SurfaceComposerClient::doUncacheBufferTransaction(mFdp.ConsumeIntegral<uint64_t>()); + + SurfaceComposerClient::setDisplayBrightness(displayToken, getBrightness(&mFdp)); + hardware::power::Boost boostId = mFdp.PickValueInArray(kBoost); + SurfaceComposerClient::notifyPowerBoost((int32_t)boostId); + + String8 surfaceName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str()); + sp<BBinder> handle(new BBinder()); + sp<BnGraphicBufferProducer> producer; + sp<Surface> surfaceParent( + new Surface(producer, mFdp.ConsumeBool() /*controlledByApp*/, handle)); + + SurfaceComposerClient::enableVSyncInjections(mFdp.ConsumeBool() /*secure*/); + nsecs_t when = mFdp.ConsumeIntegral<uint32_t>(); + SurfaceComposerClient::injectVSync(when); + + fuzzOnPullAtom(); + SurfaceComposerClient::setDisplayContentSamplingEnabled(displayToken, + mFdp.ConsumeBool() /*enable*/, + mFdp.ConsumeIntegral<uint8_t>(), + mFdp.ConsumeIntegral<uint64_t>()); + + sp<IBinder> stopLayerHandle; + sp<gui::IRegionSamplingListener> listener = sp<gui::IRegionSamplingListenerDefault>::make(); + sp<gui::IRegionSamplingListenerDelegator> sampleListener = + new gui::IRegionSamplingListenerDelegator(listener); + SurfaceComposerClient::addRegionSamplingListener(getRect(&mFdp), stopLayerHandle, + sampleListener); + sp<gui::IFpsListenerDefault> fpsListener; + SurfaceComposerClient::addFpsListener(mFdp.ConsumeIntegral<int32_t>(), fpsListener); +} + +void SurfaceComposerClientFuzzer::invokeSurfaceComposerClientBinder() { + sp<FakeBnSurfaceComposerClient> client(new FakeBnSurfaceComposerClient()); + fuzzService(client.get(), std::move(mFdp)); +} + +void SurfaceComposerClientFuzzer::process() { + invokeSurfaceComposerClient(); + invokeSurfaceComposerTransaction(); + invokeSurfaceComposerClientBinder(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + SurfaceComposerClientFuzzer surfaceComposerClientFuzzer(data, size); + surfaceComposerClientFuzzer.process(); + return 0; +} diff --git a/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp new file mode 100644 index 0000000000..6d5427bc9e --- /dev/null +++ b/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2021 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 <fuzzbinder/libbinder_driver.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <libgui_fuzzer_utils.h> + +using namespace android; + +class SurfaceComposerFuzzer { +public: + SurfaceComposerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + +private: + FuzzedDataProvider mFdp; +}; + +void SurfaceComposerFuzzer::process() { + sp<FakeBnSurfaceComposer> composer(new FakeBnSurfaceComposer()); + fuzzService(composer.get(), std::move(mFdp)); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + SurfaceComposerFuzzer surfaceComposerFuzzer(data, size); + surfaceComposerFuzzer.process(); + return 0; +} diff --git a/libs/gui/include/gui/AidlStatusUtil.h b/libs/gui/include/gui/AidlStatusUtil.h new file mode 100644 index 0000000000..55be27bf35 --- /dev/null +++ b/libs/gui/include/gui/AidlStatusUtil.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#pragma once + +#include <binder/Status.h> + +// Extracted from frameworks/av/media/libaudioclient/include/media/AidlConversionUtil.h +namespace android::gui::aidl_utils { + +/** + * Return the equivalent Android status_t from a binder exception code. + * + * Generally one should use statusTFromBinderStatus() instead. + * + * Exception codes can be generated from a remote Java service exception, translate + * them for use on the Native side. + * + * Note: for EX_TRANSACTION_FAILED and EX_SERVICE_SPECIFIC a more detailed error code + * can be found from transactionError() or serviceSpecificErrorCode(). + */ +static inline status_t statusTFromExceptionCode(int32_t exceptionCode) { + using namespace ::android::binder; + switch (exceptionCode) { + case Status::EX_NONE: + return OK; + case Status::EX_SECURITY: // Java SecurityException, rethrows locally in Java + return PERMISSION_DENIED; + case Status::EX_BAD_PARCELABLE: // Java BadParcelableException, rethrows in Java + case Status::EX_ILLEGAL_ARGUMENT: // Java IllegalArgumentException, rethrows in Java + case Status::EX_NULL_POINTER: // Java NullPointerException, rethrows in Java + return BAD_VALUE; + case Status::EX_ILLEGAL_STATE: // Java IllegalStateException, rethrows in Java + case Status::EX_UNSUPPORTED_OPERATION: // Java UnsupportedOperationException, rethrows + return INVALID_OPERATION; + case Status::EX_HAS_REPLY_HEADER: // Native strictmode violation + case Status::EX_PARCELABLE: // Java bootclass loader (not standard exception), rethrows + case Status::EX_NETWORK_MAIN_THREAD: // Java NetworkOnMainThreadException, rethrows + case Status::EX_TRANSACTION_FAILED: // Native - see error code + case Status::EX_SERVICE_SPECIFIC: // Java ServiceSpecificException, + // rethrows in Java with integer error code + return UNKNOWN_ERROR; + } + return UNKNOWN_ERROR; +} + +/** + * Return the equivalent Android status_t from a binder status. + * + * Used to handle errors from a AIDL method declaration + * + * [oneway] void method(type0 param0, ...) + * + * or the following (where return_type is not a status_t) + * + * return_type method(type0 param0, ...) + */ +static inline status_t statusTFromBinderStatus(const ::android::binder::Status &status) { + return status.isOk() ? OK // check OK, + : status.serviceSpecificErrorCode() // service-side error, not standard Java exception + // (fromServiceSpecificError) + ?: status.transactionError() // a native binder transaction error (fromStatusT) + ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a + // standard Java exception (fromExceptionCode) +} + +/** + * Return a binder::Status from native service status. + * + * This is used for methods not returning an explicit status_t, + * where Java callers expect an exception, not an integer return value. + */ +static inline ::android::binder::Status binderStatusFromStatusT( + status_t status, const char *optionalMessage = nullptr) { + const char *const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage; + // From binder::Status instructions: + // Prefer a generic exception code when possible, then a service specific + // code, and finally a status_t for low level failures or legacy support. + // Exception codes and service specific errors map to nicer exceptions for + // Java clients. + + using namespace ::android::binder; + switch (status) { + case OK: + return Status::ok(); + case PERMISSION_DENIED: // throw SecurityException on Java side + return Status::fromExceptionCode(Status::EX_SECURITY, emptyIfNull); + case BAD_VALUE: // throw IllegalArgumentException on Java side + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, emptyIfNull); + case INVALID_OPERATION: // throw IllegalStateException on Java side + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, emptyIfNull); + } + + // A service specific error will not show on status.transactionError() so + // be sure to use statusTFromBinderStatus() for reliable error handling. + + // throw a ServiceSpecificException. + return Status::fromServiceSpecificError(status, emptyIfNull); +} + +} // namespace android::gui::aidl_utils diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 9d287910a5..4535c98b97 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -69,9 +69,7 @@ private: bool mPreviouslyConnected GUARDED_BY(mMutex); }; -class BLASTBufferQueue - : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener -{ +class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener { public: BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true); BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width, @@ -83,7 +81,6 @@ public: sp<Surface> getSurface(bool includeSurfaceControlHandle); bool isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const; - void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override; void onFrameAvailable(const BufferItem& item) override; void onFrameDequeued(const uint64_t) override; @@ -111,7 +108,6 @@ public: uint32_t getLastTransformHint() const; uint64_t getLastAcquiredFrameNum(); - void abandon(); /** * Set a callback to be invoked when we are hung. The boolean parameter @@ -236,7 +232,7 @@ private: // Queues up transactions using this token in SurfaceFlinger. This prevents queued up // transactions from other parts of the client from blocking this transaction. - const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = new BBinder(); + const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = sp<BBinder>::make(); // Guards access to mDequeueTimestamps since we cannot hold to mMutex in onFrameDequeued or // we will deadlock. diff --git a/libs/gui/include/gui/CompositorTiming.h b/libs/gui/include/gui/CompositorTiming.h new file mode 100644 index 0000000000..cb8ca7a15c --- /dev/null +++ b/libs/gui/include/gui/CompositorTiming.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#pragma once + +#include <utils/Timers.h> + +namespace android::gui { + +// Expected timing of the next composited frame, based on the timing of the latest frames. +struct CompositorTiming { + static constexpr nsecs_t kDefaultVsyncPeriod = 16'666'667; + + CompositorTiming() = default; + CompositorTiming(nsecs_t vsyncDeadline, nsecs_t vsyncPeriod, nsecs_t vsyncPhase, + nsecs_t presentLatency); + + // Time point when compositing is expected to start. + nsecs_t deadline = 0; + + // Duration between consecutive frames. In other words, the VSYNC period. + nsecs_t interval = kDefaultVsyncPeriod; + + // Duration between composite start and present. For missed frames, the extra latency is rounded + // to a multiple of the VSYNC period, such that the remainder (presentLatency % interval) always + // evaluates to the VSYNC phase offset. + nsecs_t presentLatency = kDefaultVsyncPeriod; +}; + +} // namespace android::gui diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index a3425395bf..bf3a07b6b5 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -23,10 +23,10 @@ using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; class DisplayEventDispatcher : public LooperCallback { public: - explicit DisplayEventDispatcher( - const sp<Looper>& looper, - ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + explicit DisplayEventDispatcher(const sp<Looper>& looper, + gui::ISurfaceComposer::VsyncSource vsyncSource = + gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + EventRegistrationFlags eventRegistration = {}); status_t initialize(); void dispose(); diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index cf7a4e5522..0f4907fcb9 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -20,20 +20,26 @@ #include <stdint.h> #include <sys/types.h> +#include <ftl/flags.h> + #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/Timers.h> +#include <android/gui/ISurfaceComposer.h> #include <binder/IInterface.h> -#include <gui/ISurfaceComposer.h> #include <gui/VsyncEventData.h> +#include <ui/DisplayId.h> + // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- +using EventRegistrationFlags = ftl::Flags<gui::ISurfaceComposer::EventRegistration>; + using gui::IDisplayEventConnection; using gui::ParcelableVsyncEventData; using gui::VsyncEventData; @@ -111,9 +117,9 @@ public: * To receive ModeChanged and/or FrameRateOverrides events specify this in * the constructor. Other events start being delivered immediately. */ - explicit DisplayEventReceiver( - ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + explicit DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource = + gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + EventRegistrationFlags eventRegistration = {}); /* * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index dd3de58844..c08a9b1b6c 100644 --- a/libs/gui/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h @@ -17,6 +17,9 @@ #ifndef ANDROID_GUI_FRAMETIMESTAMPS_H #define ANDROID_GUI_FRAMETIMESTAMPS_H +#include <android/gui/FrameEvent.h> + +#include <gui/CompositorTiming.h> #include <ui/FenceTime.h> #include <utils/Flattenable.h> #include <utils/StrongPointer.h> @@ -31,22 +34,8 @@ namespace android { struct FrameEvents; class FrameEventHistoryDelta; - -// Identifiers for all the events that may be recorded or reported. -enum class FrameEvent { - POSTED, - REQUESTED_PRESENT, - LATCH, - ACQUIRE, - FIRST_REFRESH_START, - LAST_REFRESH_START, - GPU_COMPOSITION_DONE, - DISPLAY_PRESENT, - DEQUEUE_READY, - RELEASE, - EVENT_COUNT, // Not an actual event. -}; - +using gui::CompositorTiming; +using gui::FrameEvent; // A collection of timestamps corresponding to a single frame. struct FrameEvents { @@ -96,12 +85,6 @@ struct FrameEvents { std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE}; }; -struct CompositorTiming { - nsecs_t deadline{0}; - nsecs_t interval{16666667}; - nsecs_t presentLatency{16666667}; -}; - // A short history of frames that are synchronized between the consumer and // producer via deltas. class FrameEventHistory { diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 2f538ffb86..ba268ab17a 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -138,6 +138,10 @@ public: const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering); + static void computeTransformMatrix(float outTransform[16], float bufferWidth, + float bufferHeight, PixelFormat pixelFormat, + const Rect& cropRect, uint32_t transform, bool filtering); + // Scale the crop down horizontally or vertically such that it has the // same aspect ratio as the buffer does. static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index a610e940be..1e85131386 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -17,6 +17,7 @@ #pragma once #include <android/gui/DisplayBrightness.h> +#include <android/gui/FrameTimelineInfo.h> #include <android/gui/IDisplayEventConnection.h> #include <android/gui/IFpsListener.h> #include <android/gui/IHdrLayerInfoListener.h> @@ -27,8 +28,6 @@ #include <android/gui/IWindowInfosListener.h> #include <binder/IBinder.h> #include <binder/IInterface.h> -#include <ftl/flags.h> -#include <gui/FrameTimelineInfo.h> #include <gui/ITransactionCompletedListener.h> #include <gui/SpHash.h> #include <math/vec4.h> @@ -61,13 +60,10 @@ struct ComposerState; struct DisplayStatInfo; struct DisplayState; struct InputWindowCommands; -class LayerDebugInfo; class HdrCapabilities; -class IGraphicBufferProducer; -class ISurfaceComposerClient; class Rect; -enum class FrameEvent; +using gui::FrameTimelineInfo; using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; @@ -77,6 +73,7 @@ namespace gui { struct DisplayCaptureArgs; struct LayerCaptureArgs; +class LayerDebugInfo; } // namespace gui @@ -85,7 +82,6 @@ namespace ui { struct DisplayMode; struct DisplayState; struct DynamicDisplayInfo; -struct StaticDisplayInfo; } // namespace ui @@ -97,8 +93,6 @@ class ISurfaceComposer: public IInterface { public: DECLARE_META_INTERFACE(SurfaceComposer) - static constexpr size_t MAX_LAYERS = 4096; - // flags for setTransactionState() enum { eSynchronous = 0x01, @@ -116,28 +110,6 @@ public: eOneWay = 0x20 }; - enum VsyncSource { - eVsyncSourceApp = 0, - eVsyncSourceSurfaceFlinger = 1 - }; - - enum class EventRegistration { - modeChanged = 1 << 0, - frameRateOverride = 1 << 1, - }; - - using EventRegistrationFlags = ftl::Flags<EventRegistration>; - - /* - * Create a connection with SurfaceFlinger. - */ - virtual sp<ISurfaceComposerClient> createConnection() = 0; - - /* return an IDisplayEventConnection */ - virtual sp<IDisplayEventConnection> createDisplayEventConnection( - VsyncSource vsyncSource = eVsyncSourceApp, - EventRegistrationFlags eventRegistration = {}) = 0; - /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual status_t setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state, @@ -145,293 +117,6 @@ public: const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) = 0; - - /* signal that we're done booting. - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual void bootFinished() = 0; - - /* verify that an IGraphicBufferProducer was created by SurfaceFlinger. - */ - virtual bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& surface) const = 0; - - /* Returns the frame timestamps supported by SurfaceFlinger. - */ - virtual status_t getSupportedFrameTimestamps( - std::vector<FrameEvent>* outSupported) const = 0; - - /** - * Gets immutable information about given physical display. - */ - virtual status_t getStaticDisplayInfo(const sp<IBinder>& display, ui::StaticDisplayInfo*) = 0; - - /** - * Gets dynamic information about given physical display. - */ - virtual status_t getDynamicDisplayInfo(const sp<IBinder>& display, ui::DynamicDisplayInfo*) = 0; - - virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display, - ui::DisplayPrimaries& primaries) = 0; - virtual status_t setActiveColorMode(const sp<IBinder>& display, - ui::ColorMode colorMode) = 0; - - /** - * Sets the user-preferred display mode that a device should boot in. - */ - virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0; - - /* Clears the frame statistics for animations. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t clearAnimationFrameStats() = 0; - - /* Gets the frame statistics for animations. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0; - - /* Overrides the supported HDR modes for the given display device. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t overrideHdrTypes(const sp<IBinder>& display, - const std::vector<ui::Hdr>& hdrTypes) = 0; - - /* Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd. - * - * Requires the calling uid be from system server. - */ - virtual status_t onPullAtom(const int32_t atomId, std::string* outData, bool* success) = 0; - - virtual status_t enableVSyncInjections(bool enable) = 0; - - virtual status_t injectVSync(nsecs_t when) = 0; - - /* Gets the list of active layers in Z order for debugging purposes - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) = 0; - - virtual status_t getColorManagement(bool* outGetColorManagement) const = 0; - - /* Gets the composition preference of the default data space and default pixel format, - * as well as the wide color gamut data space and wide color gamut pixel format. - * If the wide color gamut data space is V0_SRGB, then it implies that the platform - * has no wide color gamut support. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace, - ui::PixelFormat* defaultPixelFormat, - ui::Dataspace* wideColorGamutDataspace, - ui::PixelFormat* wideColorGamutPixelFormat) const = 0; - /* - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display, - ui::PixelFormat* outFormat, - ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const = 0; - - /* Turns on the color sampling engine on the display. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, - uint8_t componentMask, - uint64_t maxFrames) = 0; - - /* Returns statistics on the color profile of the last frame displayed for a given display - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const = 0; - - /* - * Gets whether SurfaceFlinger can support protected content in GPU composition. - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getProtectedContentSupport(bool* outSupported) const = 0; - - /* Registers a listener to stream median luma updates from SurfaceFlinger. - * - * The sampling area is bounded by both samplingArea and the given stopLayerHandle - * (i.e., only layers behind the stop layer will be captured and sampled). - * - * Multiple listeners may be provided so long as they have independent listeners. - * If multiple listeners are provided, the effective sampling region for each listener will - * be bounded by whichever stop layer has a lower Z value. - * - * Requires the same permissions as captureLayers and captureScreen. - */ - virtual status_t addRegionSamplingListener(const Rect& samplingArea, - const sp<IBinder>& stopLayerHandle, - const sp<IRegionSamplingListener>& listener) = 0; - - /* - * Removes a listener that was streaming median luma updates from SurfaceFlinger. - */ - virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0; - - /* Registers a listener that streams fps updates from SurfaceFlinger. - * - * The listener will stream fps updates for the layer tree rooted at the layer denoted by the - * task ID, i.e., the layer must have the task ID as part of its layer metadata with key - * METADATA_TASK_ID. If there is no such layer, then no fps is expected to be reported. - * - * Multiple listeners may be supported. - * - * Requires the READ_FRAME_BUFFER permission. - */ - virtual status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) = 0; - /* - * Removes a listener that was streaming fps updates from SurfaceFlinger. - */ - virtual status_t removeFpsListener(const sp<gui::IFpsListener>& listener) = 0; - - /* Registers a listener to receive tunnel mode enabled updates from SurfaceFlinger. - * - * Requires ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t addTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) = 0; - - /* - * Removes a listener that was receiving tunnel mode enabled updates from SurfaceFlinger. - * - * Requires ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t removeTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) = 0; - - /* Sets the refresh rate boundaries for the display. - * - * The primary refresh rate range represents display manager's general guidance on the display - * modes we'll consider when switching refresh rates. Unless we get an explicit signal from an - * app, we should stay within this range. - * - * The app request refresh rate range allows us to consider more display modes when switching - * refresh rates. Although we should generally stay within the primary range, specific - * considerations, such as layer frame rate settings specified via the setFrameRate() api, may - * cause us to go outside the primary range. We never go outside the app request range. The app - * request range will be greater than or equal to the primary refresh rate range, never smaller. - * - * defaultMode is used to narrow the list of display modes SurfaceFlinger will consider - * switching between. Only modes with a mode group and resolution matching defaultMode - * will be considered for switching. The defaultMode corresponds to an ID of mode in the list - * of supported modes returned from getDynamicDisplayInfo(). - */ - virtual status_t setDesiredDisplayModeSpecs( - const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, - bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, - float appRequestRefreshRateMin, float appRequestRefreshRateMax) = 0; - - virtual status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, - ui::DisplayModeId* outDefaultMode, - bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, - float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) = 0; - - /* - * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows - * material design guidelines. - * - * ambientColor - * Color to the ambient shadow. The alpha is premultiplied. - * - * spotColor - * Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow - * depends on the light position. - * - * lightPosY/lightPosZ - * Position of the light used to cast the spot shadow. The X value is always the display - * width / 2. - * - * lightRadius - * Radius of the light casting the shadow. - */ - virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, - float lightRadius) = 0; - - /* - * Gets whether a display supports DISPLAY_DECORATION layers. - * - * displayToken - * The token of the display. - * outSupport - * An output parameter for whether/how the display supports - * DISPLAY_DECORATION layers. - * - * Returns NO_ERROR upon success. Otherwise, - * NAME_NOT_FOUND if the display is invalid, or - * BAD_VALUE if the output parameter is invalid. - */ - virtual status_t getDisplayDecorationSupport( - const sp<IBinder>& displayToken, - std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* - outSupport) const = 0; - - /* - * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. - */ - virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility, int8_t changeFrameRateStrategy) = 0; - - /* - * Set the override frame rate for a specified uid by GameManagerService. - * Passing the frame rate and uid to SurfaceFlinger to update the override mapping - * in the scheduler. - */ - virtual status_t setOverrideFrameRate(uid_t uid, float frameRate) = 0; - - /* - * Sets the frame timeline vsync info received from choreographer that corresponds to next - * buffer submitted on that surface. - */ - virtual status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, - const FrameTimelineInfo& frameTimelineInfo) = 0; - - /* - * Adds a TransactionTraceListener to listen for transaction tracing state updates. - */ - virtual status_t addTransactionTraceListener( - const sp<gui::ITransactionTraceListener>& listener) = 0; - - /** - * Gets priority of the RenderEngine in SurfaceFlinger. - */ - virtual int getGPUContextPriority() = 0; - - /** - * Gets the number of buffers SurfaceFlinger would need acquire. This number - * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the - * client could allocate enough buffers to match SF expectations of the - * pipeline depth. SurfaceFlinger will make sure that it will give the app at - * least the time configured as the 'appDuration' before trying to latch - * the buffer. - * - * The total buffers needed for a given configuration is basically the - * numbers of vsyncs a single buffer is used across the stack. For the default - * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger - * and 1 vsync by the display. The extra buffers are calculated as the - * number of additional buffers on top of the 2 buffers already present - * in MIN_UNDEQUEUED_BUFFERS. - */ - virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0; - - virtual status_t addWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0; - virtual status_t removeWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0; }; // ---------------------------------------------------------------------------- @@ -442,77 +127,77 @@ public: // Note: BOOT_FINISHED must remain this value, it is called from // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, - CREATE_CONNECTION, - GET_STATIC_DISPLAY_INFO, - CREATE_DISPLAY_EVENT_CONNECTION, - CREATE_DISPLAY, // Deprecated. Autogenerated by .aidl now. - DESTROY_DISPLAY, // Deprecated. Autogenerated by .aidl now. - GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now. + CREATE_CONNECTION, // Deprecated. Autogenerated by .aidl now. + GET_STATIC_DISPLAY_INFO, // Deprecated. Autogenerated by .aidl now. + CREATE_DISPLAY_EVENT_CONNECTION, // Deprecated. Autogenerated by .aidl now. + CREATE_DISPLAY, // Deprecated. Autogenerated by .aidl now. + DESTROY_DISPLAY, // Deprecated. Autogenerated by .aidl now. + GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now. SET_TRANSACTION_STATE, - AUTHENTICATE_SURFACE, - GET_SUPPORTED_FRAME_TIMESTAMPS, - GET_DISPLAY_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + AUTHENTICATE_SURFACE, // Deprecated. Autogenerated by .aidl now. + GET_SUPPORTED_FRAME_TIMESTAMPS, // Deprecated. Autogenerated by .aidl now. + GET_DISPLAY_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. GET_DISPLAY_STATE, - CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now. - CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now. - CLEAR_ANIMATION_FRAME_STATS, - GET_ANIMATION_FRAME_STATS, - SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now. + CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now. + CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now. + CLEAR_ANIMATION_FRAME_STATS, // Deprecated. Autogenerated by .aidl now. + GET_ANIMATION_FRAME_STATS, // Deprecated. Autogenerated by .aidl now. + SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now. GET_DISPLAY_STATS, - GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - GET_ACTIVE_COLOR_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - SET_ACTIVE_COLOR_MODE, - ENABLE_VSYNC_INJECTIONS, - INJECT_VSYNC, - GET_LAYER_DEBUG_INFO, - GET_COMPOSITION_PREFERENCE, - GET_COLOR_MANAGEMENT, - GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, - SET_DISPLAY_CONTENT_SAMPLING_ENABLED, + GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_ACTIVE_COLOR_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + SET_ACTIVE_COLOR_MODE, // Deprecated. Autogenerated by .aidl now. + ENABLE_VSYNC_INJECTIONS, // Deprecated. Autogenerated by .aidl now. + INJECT_VSYNC, // Deprecated. Autogenerated by .aidl now. + GET_LAYER_DEBUG_INFO, // Deprecated. Autogenerated by .aidl now. + GET_COMPOSITION_PREFERENCE, // Deprecated. Autogenerated by .aidl now. + GET_COLOR_MANAGEMENT, // Deprecated. Autogenerated by .aidl now. + GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, // Deprecated. Autogenerated by .aidl now. + SET_DISPLAY_CONTENT_SAMPLING_ENABLED, // Deprecated. Autogenerated by .aidl now. GET_DISPLAYED_CONTENT_SAMPLE, - GET_PROTECTED_CONTENT_SUPPORT, - IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now. - GET_DISPLAY_NATIVE_PRIMARIES, - GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now. - ADD_REGION_SAMPLING_LISTENER, - REMOVE_REGION_SAMPLING_LISTENER, - SET_DESIRED_DISPLAY_MODE_SPECS, - GET_DESIRED_DISPLAY_MODE_SPECS, - GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now. - SET_DISPLAY_BRIGHTNESS, // Deprecated. Autogenerated by .aidl now. - CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now. - NOTIFY_POWER_BOOST, // Deprecated. Autogenerated by .aidl now. + GET_PROTECTED_CONTENT_SUPPORT, // Deprecated. Autogenerated by .aidl now. + IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now. + GET_DISPLAY_NATIVE_PRIMARIES, // Deprecated. Autogenerated by .aidl now. + GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now. + ADD_REGION_SAMPLING_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_REGION_SAMPLING_LISTENER, // Deprecated. Autogenerated by .aidl now. + SET_DESIRED_DISPLAY_MODE_SPECS, // Deprecated. Autogenerated by .aidl now. + GET_DESIRED_DISPLAY_MODE_SPECS, // Deprecated. Autogenerated by .aidl now. + GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now. + SET_DISPLAY_BRIGHTNESS, // Deprecated. Autogenerated by .aidl now. + CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now. + NOTIFY_POWER_BOOST, // Deprecated. Autogenerated by .aidl now. SET_GLOBAL_SHADOW_SETTINGS, GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. SET_AUTO_LOW_LATENCY_MODE, // Deprecated. Autogenerated by .aidl now. GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. SET_GAME_CONTENT_TYPE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - SET_FRAME_RATE, + SET_FRAME_RATE, // Deprecated. Autogenerated by .aidl now. // Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true); ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, - SET_FRAME_TIMELINE_INFO, - ADD_TRANSACTION_TRACE_LISTENER, + SET_FRAME_TIMELINE_INFO, // Deprecated. Autogenerated by .aidl now. + ADD_TRANSACTION_TRACE_LISTENER, // Deprecated. Autogenerated by .aidl now. GET_GPU_CONTEXT_PRIORITY, GET_MAX_ACQUIRED_BUFFER_COUNT, - GET_DYNAMIC_DISPLAY_INFO, - ADD_FPS_LISTENER, - REMOVE_FPS_LISTENER, - OVERRIDE_HDR_TYPES, - ADD_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now. - REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now. - ON_PULL_ATOM, - ADD_TUNNEL_MODE_ENABLED_LISTENER, - REMOVE_TUNNEL_MODE_ENABLED_LISTENER, - ADD_WINDOW_INFOS_LISTENER, - REMOVE_WINDOW_INFOS_LISTENER, - GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now. + GET_DYNAMIC_DISPLAY_INFO, // Deprecated. Autogenerated by .aidl now. + ADD_FPS_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_FPS_LISTENER, // Deprecated. Autogenerated by .aidl now. + OVERRIDE_HDR_TYPES, // Deprecated. Autogenerated by .aidl now. + ADD_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now. + ON_PULL_ATOM, // Deprecated. Autogenerated by .aidl now. + ADD_TUNNEL_MODE_ENABLED_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_TUNNEL_MODE_ENABLED_LISTENER, // Deprecated. Autogenerated by .aidl now. + ADD_WINDOW_INFOS_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_WINDOW_INFOS_LISTENER, // Deprecated. Autogenerated by .aidl now. + GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now. GET_DISPLAY_DECORATION_SUPPORT, GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now. - SET_BOOT_DISPLAY_MODE, - CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now. - SET_OVERRIDE_FRAME_RATE, + SET_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now. + CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now. + SET_OVERRIDE_FRAME_RATE, // Deprecated. Autogenerated by .aidl now. // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h deleted file mode 100644 index 9e9e191480..0000000000 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#pragma once - -#include <binder/IInterface.h> -#include <binder/SafeInterface.h> -#include <gui/LayerMetadata.h> -#include <ui/PixelFormat.h> - -#include <unordered_map> - -namespace android { - -class FrameStats; -class IGraphicBufferProducer; - -class ISurfaceComposerClient : public IInterface { -public: - DECLARE_META_INTERFACE(SurfaceComposerClient) - - // flags for createSurface() - enum { // (keep in sync with SurfaceControl.java) - eHidden = 0x00000004, - eDestroyBackbuffer = 0x00000020, - eSkipScreenshot = 0x00000040, - eSecure = 0x00000080, - eNonPremultiplied = 0x00000100, - eOpaque = 0x00000400, - eProtectedByApp = 0x00000800, - eProtectedByDRM = 0x00001000, - eCursorWindow = 0x00002000, - eNoColorFill = 0x00004000, - - eFXSurfaceBufferQueue = 0x00000000, - eFXSurfaceEffect = 0x00020000, - eFXSurfaceBufferState = 0x00040000, - eFXSurfaceContainer = 0x00080000, - eFXSurfaceMask = 0x000F0000, - }; - - // TODO(b/172002646): Clean up the Surface Creation Arguments - /* - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) = 0; - - /* - * 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, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) = 0; - - /* - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0; - - /* - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0; - - virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle, - int32_t* outLayerId) = 0; -}; - -class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> { -public: - BnSurfaceComposerClient() - : SafeBnInterface<ISurfaceComposerClient>("BnSurfaceComposerClient") {} - - status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override; -}; - -} // namespace android diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h index ce9716f1fe..1dddeba616 100644 --- a/libs/gui/include/gui/JankInfo.h +++ b/libs/gui/include/gui/JankInfo.h @@ -24,9 +24,9 @@ enum JankType { None = 0x0, // Jank that occurs in the layers below SurfaceFlinger DisplayHAL = 0x1, - // SF took too long on the CPU + // SF took too long on the CPU; deadline missed during HWC SurfaceFlingerCpuDeadlineMissed = 0x2, - // SF took too long on the GPU + // SF took too long on the GPU; deadline missed during GPU composition SurfaceFlingerGpuDeadlineMissed = 0x4, // Either App or GPU took too long on the frame AppDeadlineMissed = 0x8, diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h index af834d78df..dbb80e583c 100644 --- a/libs/gui/include/gui/LayerDebugInfo.h +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -25,7 +25,7 @@ #include <string> #include <math/vec4.h> -namespace android { +namespace android::gui { /* Class for transporting debug info from SurfaceFlinger to authorized * recipients. The class is intended to be a data container. There are @@ -52,7 +52,7 @@ public: uint32_t mZ = 0 ; int32_t mWidth = -1; int32_t mHeight = -1; - Rect mCrop = Rect::INVALID_RECT; + android::Rect mCrop = android::Rect::INVALID_RECT; half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf); uint32_t mFlags = 0; PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; @@ -71,4 +71,4 @@ public: std::string to_string(const LayerDebugInfo& info); -} // namespace android +} // namespace android::gui diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index 27f4d379e9..5af598956b 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -20,7 +20,7 @@ #include <unordered_map> -namespace android { +namespace android::gui { enum { METADATA_OWNER_UID = 1, @@ -69,4 +69,13 @@ enum class GameMode : int32_t { ftl_last = Battery }; -} // namespace android +} // namespace android::gui + +using android::gui::METADATA_ACCESSIBILITY_ID; +using android::gui::METADATA_DEQUEUE_TIME; +using android::gui::METADATA_GAME_MODE; +using android::gui::METADATA_MOUSE_CURSOR; +using android::gui::METADATA_OWNER_PID; +using android::gui::METADATA_OWNER_UID; +using android::gui::METADATA_TASK_ID; +using android::gui::METADATA_WINDOW_TYPE; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 0a9b75a7f1..c8927ad55a 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -21,6 +21,7 @@ #include <stdint.h> #include <sys/types.h> +#include <android/gui/IWindowInfosReportedListener.h> #include <android/native_window.h> #include <gui/IGraphicBufferProducer.h> #include <gui/ITransactionCompletedListener.h> @@ -51,7 +52,9 @@ namespace android { class Parcel; -class ISurfaceComposerClient; + +using gui::ISurfaceComposerClient; +using gui::LayerMetadata; struct client_cache_t { wp<IBinder> token = nullptr; @@ -130,7 +133,7 @@ struct layer_state_t { eLayerOpaque = 0x02, // SURFACE_OPAQUE eLayerSkipScreenshot = 0x40, // SKIP_SCREENSHOT eLayerSecure = 0x80, // SECURE - // Queue up BufferStateLayer buffers instead of dropping the oldest buffer when this flag is + // Queue up layer buffers instead of dropping the oldest buffer when this flag is // set. This blocks the client until all the buffers have been presented. If the buffers // have presentation timestamps, then we may drop buffers. eEnableBackpressure = 0x100, // ENABLE_BACKPRESSURE @@ -145,7 +148,7 @@ struct layer_state_t { enum { ePositionChanged = 0x00000001, eLayerChanged = 0x00000002, - eSizeChanged = 0x00000004, + // unused = 0x00000004, eAlphaChanged = 0x00000008, eMatrixChanged = 0x00000010, eTransparentRegionChanged = 0x00000020, @@ -153,7 +156,7 @@ struct layer_state_t { eLayerStackChanged = 0x00000080, eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, - /* unused 0x00001000, */ + eRenderBorderChanged = 0x00001000, eBufferCropChanged = 0x00002000, eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, @@ -163,7 +166,7 @@ struct layer_state_t { eTransformToDisplayInverseChanged = 0x00080000, eCropChanged = 0x00100000, eBufferChanged = 0x00200000, - /* unused 0x00400000, */ + eDefaultFrameRateCompatibilityChanged = 0x00400000, eDataspaceChanged = 0x00800000, eHdrMetadataChanged = 0x01000000, eSurfaceDamageRegionChanged = 0x02000000, @@ -214,8 +217,6 @@ struct layer_state_t { float x; float y; int32_t z; - uint32_t w; - uint32_t h; ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK; float alpha; uint32_t flags; @@ -247,7 +248,7 @@ struct layer_state_t { mat4 colorTransform; std::vector<BlurRegion> blurRegions; - sp<gui::WindowInfoHandle> windowInfoHandle = new gui::WindowInfoHandle(); + sp<gui::WindowInfoHandle> windowInfoHandle = sp<gui::WindowInfoHandle>::make(); LayerMetadata metadata; @@ -273,6 +274,9 @@ struct layer_state_t { int8_t frameRateCompatibility; int8_t changeFrameRateStrategy; + // Default frame rate compatibility used to set the layer refresh rate votetype. + int8_t defaultFrameRateCompatibility; + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the @@ -291,6 +295,11 @@ struct layer_state_t { // should be trusted for input occlusion detection purposes bool isTrustedOverlay; + // Flag to indicate if border needs to be enabled on the layer + bool borderEnabled; + float borderWidth; + half4 borderColor; + // Stretch effect to be applied to this layer StretchEffect stretchEffect; @@ -352,7 +361,9 @@ struct DisplayState { struct InputWindowCommands { std::vector<gui::FocusRequest> focusRequests; - bool syncInputWindows{false}; + std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>> + windowInfosReportedListeners; // Merges the passed in commands and returns true if there were any changes. bool merge(const InputWindowCommands& other); diff --git a/libs/gui/include/gui/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h index 724c11c881..6e17791a29 100644 --- a/libs/gui/include/gui/ScreenCaptureResults.h +++ b/libs/gui/include/gui/ScreenCaptureResults.h @@ -19,6 +19,7 @@ #include <binder/Parcel.h> #include <binder/Parcelable.h> #include <ui/Fence.h> +#include <ui/FenceResult.h> #include <ui/GraphicBuffer.h> namespace android::gui { @@ -31,11 +32,10 @@ public: status_t readFromParcel(const android::Parcel* parcel) override; sp<GraphicBuffer> buffer; - sp<Fence> fence = Fence::NO_FENCE; + FenceResult fenceResult = Fence::NO_FENCE; bool capturedSecureLayers{false}; bool capturedHdrLayers{false}; ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB}; - status_t result = OK; }; } // namespace android::gui diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index ab9ebaa882..634acb68b9 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -17,8 +17,8 @@ #ifndef ANDROID_GUI_SURFACE_H #define ANDROID_GUI_SURFACE_H +#include <android/gui/FrameTimelineInfo.h> #include <gui/BufferQueueDefs.h> -#include <gui/FrameTimelineInfo.h> #include <gui/HdrMetadata.h> #include <gui/IGraphicBufferProducer.h> #include <gui/IProducerListener.h> @@ -41,6 +41,8 @@ class ISurfaceComposer; class ISurfaceComposer; +using gui::FrameTimelineInfo; + /* This is the same as ProducerListener except that onBuffersDiscarded is * called with a vector of graphic buffers instead of buffer slots. */ @@ -283,6 +285,10 @@ private: int dispatchGetLastQueuedBuffer2(va_list args); int dispatchSetFrameTimelineInfo(va_list args); + std::mutex mNameMutex; + std::string mName; + const char* getDebugName(); + protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index b598b43403..61d47145e9 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -38,6 +38,9 @@ #include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> #include <ui/Rotation.h> +#include <ui/StaticDisplayInfo.h> + +#include <android/gui/ISurfaceComposerClient.h> #include <gui/CpuConsumer.h> #include <gui/ISurfaceComposer.h> @@ -52,14 +55,15 @@ namespace android { class HdrCapabilities; -class ISurfaceComposerClient; class IGraphicBufferProducer; class ITunnelModeEnabledListener; class Region; using gui::DisplayCaptureArgs; using gui::IRegionSamplingListener; +using gui::ISurfaceComposerClient; using gui::LayerCaptureArgs; +using gui::LayerMetadata; struct SurfaceControlStats { SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, @@ -215,7 +219,7 @@ public: /** * Gets the context priority of surface flinger's render engine. */ - static int getGPUContextPriority(); + static int getGpuContextPriority(); /** * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is @@ -311,7 +315,7 @@ public: uint32_t w, // width in pixel uint32_t h, // height in pixel PixelFormat format, // pixel-format desired - uint32_t flags = 0, // usage flags + int32_t flags = 0, // usage flags const sp<IBinder>& parentHandle = nullptr, // parentHandle LayerMetadata metadata = LayerMetadata(), // metadata uint32_t* outTransformHint = nullptr); @@ -321,21 +325,11 @@ public: uint32_t h, // height in pixel PixelFormat format, // pixel-format desired sp<SurfaceControl>* outSurface, - uint32_t flags = 0, // usage flags + int32_t flags = 0, // usage flags const sp<IBinder>& parentHandle = nullptr, // parentHandle LayerMetadata metadata = LayerMetadata(), // metadata uint32_t* outTransformHint = nullptr); - //! 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 - LayerMetadata metadata = LayerMetadata(), // metadata - uint32_t* outTransformHint = nullptr); - // Creates a mirrored hierarchy for the mirrorFromSurface. This returns a SurfaceControl // which is a parent of the root of the mirrored hierarchy. // @@ -347,6 +341,8 @@ public: // B B' sp<SurfaceControl> mirrorSurface(SurfaceControl* mirrorFromSurface); + sp<SurfaceControl> mirrorDisplay(DisplayId displayId); + //! Create a virtual display static sp<IBinder> createDisplay(const String8& displayName, bool secure); @@ -355,7 +351,6 @@ public: //! Get stable IDs for connected physical displays static std::vector<PhysicalDisplayId> getPhysicalDisplayIds(); - static status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*); static std::optional<PhysicalDisplayId> getInternalDisplayId(); //! Get token for a physical display given its stable ID @@ -395,7 +390,10 @@ public: class Transaction : public Parcelable { private: + static sp<IBinder> sApplyToken; void releaseBufferIfOverwriting(const layer_state_t& state); + static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other); + static void clearFrameTimelineInfo(FrameTimelineInfo& t); protected: std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates; @@ -405,14 +403,15 @@ public: uint64_t mId; - uint32_t mForceSynchronous = 0; uint32_t mTransactionNestCount = 0; bool mAnimation = false; bool mEarlyWakeupStart = false; bool mEarlyWakeupEnd = false; - // Indicates that the Transaction contains a buffer that should be cached - bool mContainsBuffer = false; + // Indicates that the Transaction may contain buffers that should be cached. The reason this + // is only a guess is that buffers can be removed before cache is called. This is only a + // hint that at some point a buffer was added to this transaction before apply was called. + bool mMayContainBuffer = false; // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction // to be presented. When it is not possible to present at exactly that time, it will be @@ -471,10 +470,9 @@ public: Transaction& merge(Transaction&& other); Transaction& show(const sp<SurfaceControl>& sc); Transaction& hide(const sp<SurfaceControl>& sc); - Transaction& setPosition(const sp<SurfaceControl>& sc, - float x, float y); - Transaction& setSize(const sp<SurfaceControl>& sc, - uint32_t w, uint32_t h); + Transaction& setPosition(const sp<SurfaceControl>& sc, float x, float y); + // b/243180033 remove once functions are not called from vendor code + Transaction& setSize(const sp<SurfaceControl>&, uint32_t, uint32_t) { return *this; } Transaction& setLayer(const sp<SurfaceControl>& sc, int32_t z); @@ -574,7 +572,9 @@ public: Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const gui::WindowInfo& info); Transaction& setFocusedWindow(const gui::FocusRequest& request); - Transaction& syncInputWindows(); + + Transaction& addWindowInfosReportedListener( + sp<gui::IWindowInfosReportedListener> windowInfosReportedListener); // Set a color transform matrix on the given layer on the built-in display. Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix, @@ -587,6 +587,9 @@ public: Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy); + Transaction& setDefaultFrameRateCompatibility(const sp<SurfaceControl>& sc, + int8_t compatibility); + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the @@ -633,6 +636,9 @@ public: const Rect& destinationFrame); Transaction& setDropInputMode(const sp<SurfaceControl>& sc, gui::DropInputMode mode); + Transaction& enableBorder(const sp<SurfaceControl>& sc, bool shouldEnable, float width, + const half4& color); + status_t setDisplaySurface(const sp<IBinder>& token, const sp<IGraphicBufferProducer>& bufferProducer); @@ -664,6 +670,9 @@ public: * TODO (b/213644870): Remove all permissioned things from Transaction */ void sanitize(); + + static sp<IBinder> getDefaultApplyToken(); + static void setDefaultApplyToken(sp<IBinder> applyToken); }; status_t clearLayerFrameStats(const sp<IBinder>& token) const; diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index b72cf8390e..e4a1350643 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -24,11 +24,12 @@ #include <utils/RefBase.h> #include <utils/threads.h> +#include <android/gui/ISurfaceComposerClient.h> + #include <ui/FrameStats.h> #include <ui/PixelFormat.h> #include <ui/Region.h> -#include <gui/ISurfaceComposerClient.h> #include <math/vec3.h> namespace android { @@ -93,8 +94,7 @@ public: explicit SurfaceControl(const sp<SurfaceControl>& other); SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp, int32_t layerId, - uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0, + int32_t layerId, uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0, uint32_t transformHint = 0, uint32_t flags = 0); sp<SurfaceControl> getParentingLayer(); @@ -115,8 +115,7 @@ private: status_t validate() const; sp<SurfaceComposerClient> mClient; - sp<IBinder> mHandle; - sp<IGraphicBufferProducer> mGraphicBufferProducer; + sp<IBinder> mHandle; mutable Mutex mLock; mutable sp<Surface> mSurfaceData; mutable sp<BLASTBufferQueue> mBbq; diff --git a/libs/gui/include/gui/SyncScreenCaptureListener.h b/libs/gui/include/gui/SyncScreenCaptureListener.h index 0784fbc058..bcf565a494 100644 --- a/libs/gui/include/gui/SyncScreenCaptureListener.h +++ b/libs/gui/include/gui/SyncScreenCaptureListener.h @@ -34,7 +34,9 @@ public: ScreenCaptureResults waitForResults() { std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future(); const auto screenCaptureResults = resultsFuture.get(); - screenCaptureResults.fence->waitForever(""); + if (screenCaptureResults.fenceResult.ok()) { + screenCaptureResults.fenceResult.value()->waitForever(""); + } return screenCaptureResults; } @@ -42,4 +44,4 @@ private: std::promise<ScreenCaptureResults> resultsPromise; }; -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h index e5d268445c..4c01683a86 100644 --- a/libs/gui/include/gui/TraceUtils.h +++ b/libs/gui/include/gui/TraceUtils.h @@ -21,11 +21,14 @@ #include <cutils/trace.h> #include <utils/Trace.h> -#define ATRACE_FORMAT(fmt, ...) \ - TraceUtils::TraceEnder __traceEnder = \ - (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder()) +#define ATRACE_FORMAT(fmt, ...) \ + TraceUtils::TraceEnder traceEnder = \ + (CC_UNLIKELY(ATRACE_ENABLED()) && \ + (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), true), \ + TraceUtils::TraceEnder()) -#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__) +#define ATRACE_FORMAT_INSTANT(fmt, ...) \ + (CC_UNLIKELY(ATRACE_ENABLED()) && (TraceUtils::instantFormat(fmt, ##__VA_ARGS__), true)) namespace android { @@ -37,8 +40,6 @@ public: }; static void atraceFormatBegin(const char* fmt, ...) { - if (CC_LIKELY(!ATRACE_ENABLED())) return; - const int BUFFER_SIZE = 256; va_list ap; char buf[BUFFER_SIZE]; @@ -50,6 +51,17 @@ public: ATRACE_BEGIN(buf); } -}; // class TraceUtils + static void instantFormat(const char* fmt, ...) { + const int BUFFER_SIZE = 256; + va_list ap; + char buf[BUFFER_SIZE]; + + va_start(ap, fmt); + vsnprintf(buf, BUFFER_SIZE, fmt, ap); + va_end(ap); + + ATRACE_INSTANT(buf); + } +}; -} /* namespace android */ +} // namespace android diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h index 8e99539fe9..dfdae214d2 100644 --- a/libs/gui/include/gui/VsyncEventData.h +++ b/libs/gui/include/gui/VsyncEventData.h @@ -16,7 +16,7 @@ #pragma once -#include <gui/FrameTimelineInfo.h> +#include <android/gui/FrameTimelineInfo.h> #include <array> diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 169f7f022b..ac74c8a91f 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -171,6 +171,8 @@ struct WindowInfo : public Parcelable { static_cast<uint32_t>(os::InputConfig::SPY), INTERCEPTS_STYLUS = static_cast<uint32_t>(os::InputConfig::INTERCEPTS_STYLUS), + CLONE = + static_cast<uint32_t>(os::InputConfig::CLONE), // clang-format on }; @@ -236,8 +238,6 @@ 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/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 3b4aed442e..2754442a95 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -17,15 +17,14 @@ #pragma once #include <android/gui/BnWindowInfosListener.h> +#include <android/gui/ISurfaceComposer.h> #include <android/gui/IWindowInfosReportedListener.h> #include <binder/IBinder.h> -#include <gui/ISurfaceComposer.h> #include <gui/SpHash.h> #include <gui/WindowInfosListener.h> #include <unordered_set> namespace android { -class ISurfaceComposer; class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: @@ -33,17 +32,17 @@ public: binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>&, const std::vector<gui::DisplayInfo>&, const sp<gui::IWindowInfosReportedListener>&) override; - status_t addWindowInfosListener( - const sp<gui::WindowInfosListener>& windowInfosListener, const sp<ISurfaceComposer>&, + const sp<gui::WindowInfosListener>& windowInfosListener, + const sp<gui::ISurfaceComposer>&, std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo); status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener, - const sp<ISurfaceComposer>& surfaceComposer); - void reconnect(const sp<ISurfaceComposer>&); + const sp<gui::ISurfaceComposer>& surfaceComposer); + void reconnect(const sp<gui::ISurfaceComposer>&); private: std::mutex mListenersMutex; - std::unordered_set<sp<gui::WindowInfosListener>, SpHash<gui::WindowInfosListener>> + std::unordered_set<sp<gui::WindowInfosListener>, gui::SpHash<gui::WindowInfosListener>> mWindowInfosListeners GUARDED_BY(mListenersMutex); std::vector<gui::WindowInfo> mLastWindowInfos GUARDED_BY(mListenersMutex); diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h index 9a96976c0f..296358329b 100644 --- a/libs/gui/include/private/gui/ComposerServiceAIDL.h +++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h @@ -20,6 +20,7 @@ #include <sys/types.h> #include <android/gui/ISurfaceComposer.h> +#include <ui/DisplayId.h> #include <utils/Singleton.h> #include <utils/StrongPointer.h> diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index fc68ad27c5..7b37b25a61 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -24,6 +24,7 @@ cc_test { "BLASTBufferQueue_test.cpp", "BufferItemConsumer_test.cpp", "BufferQueue_test.cpp", + "CompositorTiming_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", "DisplayInfo_test.cpp", diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index b993289e6a..c4c2fa5b85 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -19,6 +19,7 @@ #include <gui/BLASTBufferQueue.h> #include <android/hardware/graphics/common/1.2/types.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> #include <gui/FrameTimestamps.h> @@ -305,11 +306,12 @@ protected: const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); binder::Status status = sf->captureDisplay(captureArgs, captureListener); - if (status.transactionError() != NO_ERROR) { - return status.transactionError(); + status_t err = gui::aidl_utils::statusTFromBinderStatus(status); + if (err != NO_ERROR) { + return err; } captureResults = captureListener->waitForResults(); - return captureResults.result; + return fenceStatus(captureResults.fenceResult); } void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b, @@ -1146,6 +1148,7 @@ TEST_F(BLASTBufferQueueTest, SyncNextTransactionDropBuffer) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + sync.apply(); } // This test will currently fail because the old surfacecontrol will steal the last presented buffer diff --git a/libs/gui/tests/CompositorTiming_test.cpp b/libs/gui/tests/CompositorTiming_test.cpp new file mode 100644 index 0000000000..d8bb21d582 --- /dev/null +++ b/libs/gui/tests/CompositorTiming_test.cpp @@ -0,0 +1,61 @@ +/* + * 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 <gtest/gtest.h> +#include <gui/CompositorTiming.h> + +namespace android::test { +namespace { + +constexpr nsecs_t kMillisecond = 1'000'000; +constexpr nsecs_t kVsyncPeriod = 8'333'333; +constexpr nsecs_t kVsyncPhase = -2'166'667; +constexpr nsecs_t kIdealLatency = -kVsyncPhase; + +} // namespace + +TEST(CompositorTimingTest, InvalidVsyncPeriod) { + const nsecs_t vsyncDeadline = systemTime(); + constexpr nsecs_t kInvalidVsyncPeriod = -1; + + const gui::CompositorTiming timing(vsyncDeadline, kInvalidVsyncPeriod, kVsyncPhase, + kIdealLatency); + + EXPECT_EQ(timing.deadline, 0); + EXPECT_EQ(timing.interval, gui::CompositorTiming::kDefaultVsyncPeriod); + EXPECT_EQ(timing.presentLatency, gui::CompositorTiming::kDefaultVsyncPeriod); +} + +TEST(CompositorTimingTest, PresentLatencySnapping) { + for (nsecs_t presentDelay = 0, compositeTime = systemTime(); presentDelay < 10 * kVsyncPeriod; + presentDelay += kMillisecond, compositeTime += kVsyncPeriod) { + const nsecs_t presentLatency = kIdealLatency + presentDelay; + const nsecs_t vsyncDeadline = compositeTime + presentLatency + kVsyncPeriod; + + const gui::CompositorTiming timing(vsyncDeadline, kVsyncPeriod, kVsyncPhase, + presentLatency); + + EXPECT_EQ(timing.deadline, compositeTime + presentDelay + kVsyncPeriod); + EXPECT_EQ(timing.interval, kVsyncPeriod); + + // The presentDelay should be rounded to a multiple of the VSYNC period, such that the + // remainder (presentLatency % interval) always evaluates to the VSYNC phase offset. + EXPECT_GE(timing.presentLatency, kIdealLatency); + EXPECT_EQ(timing.presentLatency % timing.interval, kIdealLatency); + } +} + +} // namespace android::test diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index c9106bed4c..b18b544257 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -19,14 +19,16 @@ #include <android/gui/BnRegionSamplingListener.h> #include <binder/ProcessState.h> +#include <gui/AidlStatusUtil.h> #include <gui/DisplayEventReceiver.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <utils/Looper.h> using namespace std::chrono_literals; +using android::gui::aidl_utils::statusTFromBinderStatus; namespace android::test { @@ -242,24 +244,33 @@ protected: }; TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) { - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; // Passing in composer service as the layer handle should not crash, we'll // treat it as a layer that no longer exists and silently allow sampling to // occur. - status_t status = composer->addRegionSamplingListener(sampleArea, - IInterface::asBinder(composer), listener); - ASSERT_EQ(NO_ERROR, status); + binder::Status status = + composer->addRegionSamplingListener(sampleArea, IInterface::asBinder(composer), + listener); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); composer->removeRegionSamplingListener(listener); } TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) { fill_render(rgba_green); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; @@ -271,9 +282,13 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) { TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) { fill_render(rgba_green); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; @@ -291,13 +306,21 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) { TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) { fill_render(rgba_green); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> greenListener = new Listener(); - const Rect greenSampleArea{100, 100, 200, 200}; + gui::ARect greenSampleArea; + greenSampleArea.left = 100; + greenSampleArea.top = 100; + greenSampleArea.right = 200; + greenSampleArea.bottom = 200; composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener); sp<Listener> grayListener = new Listener(); - const Rect graySampleArea{500, 100, 600, 200}; + gui::ARect graySampleArea; + graySampleArea.left = 500; + graySampleArea.top = 100; + graySampleArea.right = 600; + graySampleArea.bottom = 200; composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener); EXPECT_TRUE(grayListener->wait_event(300ms)) @@ -312,29 +335,49 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) { } TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) { - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + + gui::ARect invalidRect; + invalidRect.left = Rect::INVALID_RECT.left; + invalidRect.top = Rect::INVALID_RECT.top; + invalidRect.right = Rect::INVALID_RECT.right; + invalidRect.bottom = Rect::INVALID_RECT.bottom; + + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; // Invalid input sampleArea EXPECT_EQ(BAD_VALUE, - composer->addRegionSamplingListener(Rect::INVALID_RECT, mTopLayer->getHandle(), - listener)); + statusTFromBinderStatus(composer->addRegionSamplingListener(invalidRect, + mTopLayer->getHandle(), + listener))); listener->reset(); // Invalid input binder - EXPECT_EQ(NO_ERROR, composer->addRegionSamplingListener(sampleArea, NULL, listener)); + EXPECT_EQ(NO_ERROR, + statusTFromBinderStatus( + composer->addRegionSamplingListener(sampleArea, NULL, listener))); // Invalid input listener EXPECT_EQ(BAD_VALUE, - composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), NULL)); - EXPECT_EQ(BAD_VALUE, composer->removeRegionSamplingListener(NULL)); + statusTFromBinderStatus(composer->addRegionSamplingListener(sampleArea, + mTopLayer->getHandle(), + NULL))); + EXPECT_EQ(BAD_VALUE, statusTFromBinderStatus(composer->removeRegionSamplingListener(NULL))); // remove the listener composer->removeRegionSamplingListener(listener); } TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) { fill_render(rgba_green); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); fill_render(rgba_green); @@ -349,13 +392,18 @@ TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) { } TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) { - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleAreaA; + sampleAreaA.left = sampleArea.left; + sampleAreaA.top = sampleArea.top; + sampleAreaA.right = sampleArea.right; + sampleAreaA.bottom = sampleArea.bottom; // Test: listener in (100, 100). See layer before move, no layer after move. fill_render(rgba_blue); - composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener); EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; EXPECT_NEAR(listener->luma(), luma_blue, error_margin); listener->reset(); @@ -367,7 +415,11 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) { // Test: listener offset to (600, 600). No layer before move, see layer after move. fill_render(rgba_green); sampleArea.offsetTo(600, 600); - composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + sampleAreaA.left = sampleArea.left; + sampleAreaA.top = sampleArea.top; + sampleAreaA.right = sampleArea.right; + sampleAreaA.bottom = sampleArea.bottom; + composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener); EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; EXPECT_NEAR(listener->luma(), luma_gray, error_margin); listener->reset(); diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp index a083a228a6..f98437b4f8 100644 --- a/libs/gui/tests/SamplingDemo.cpp +++ b/libs/gui/tests/SamplingDemo.cpp @@ -26,7 +26,7 @@ #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <gui/SurfaceControl.h> -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <utils/Trace.h> using namespace std::chrono_literals; @@ -121,10 +121,22 @@ int main(int, const char**) { const Rect backButtonArea{200, 1606, 248, 1654}; sp<android::Button> backButton = new android::Button("BackButton", backButtonArea); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); - composer->addRegionSamplingListener(homeButtonArea, homeButton->getStopLayerHandle(), + gui::ARect homeButtonAreaA; + homeButtonAreaA.left = 490; + homeButtonAreaA.top = 1606; + homeButtonAreaA.right = 590; + homeButtonAreaA.bottom = 1654; + + gui::ARect backButtonAreaA; + backButtonAreaA.left = 200; + backButtonAreaA.top = 1606; + backButtonAreaA.right = 248; + backButtonAreaA.bottom = 1654; + + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); + composer->addRegionSamplingListener(homeButtonAreaA, homeButton->getStopLayerHandle(), homeButton); - composer->addRegionSamplingListener(backButtonArea, backButton->getStopLayerHandle(), + composer->addRegionSamplingListener(backButtonAreaA, backButton->getStopLayerHandle(), backButton); ProcessState::self()->startThreadPool(); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 065cd7a5c7..b9358e7717 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -24,6 +24,7 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <binder/ProcessState.h> #include <configstore/Utils.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferItemConsumer.h> #include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> @@ -212,11 +213,12 @@ protected: const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); binder::Status status = sf->captureDisplay(captureArgs, captureListener); - if (status.transactionError() != NO_ERROR) { - return status.transactionError(); + status_t err = gui::aidl_utils::statusTFromBinderStatus(status); + if (err != NO_ERROR) { + return err; } captureResults = captureListener->waitForResults(); - return captureResults.result; + return fenceStatus(captureResults.fenceResult); } sp<Surface> mSurface; @@ -690,11 +692,6 @@ public: mSupportsPresent = supportsPresent; } - sp<ISurfaceComposerClient> createConnection() override { return nullptr; } - sp<IDisplayEventConnection> createDisplayEventConnection( - ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override { - return nullptr; - } status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/, const Vector<ComposerState>& /*state*/, const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/, @@ -708,260 +705,232 @@ public: return NO_ERROR; } - void bootFinished() override {} - bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& /*surface*/) const override { - return false; - } +protected: + IBinder* onAsBinder() override { return nullptr; } - status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) - const override { - *outSupported = { - FrameEvent::REQUESTED_PRESENT, - FrameEvent::ACQUIRE, - FrameEvent::LATCH, - FrameEvent::FIRST_REFRESH_START, - FrameEvent::LAST_REFRESH_START, - FrameEvent::GPU_COMPOSITION_DONE, - FrameEvent::DEQUEUE_READY, - FrameEvent::RELEASE - }; - if (mSupportsPresent) { - outSupported->push_back( - FrameEvent::DISPLAY_PRESENT); - } - return NO_ERROR; - } +private: + bool mSupportsPresent{true}; +}; - status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override { - return NO_ERROR; - } - status_t getDynamicDisplayInfo(const sp<IBinder>& /*display*/, - ui::DynamicDisplayInfo*) override { - return NO_ERROR; - } - status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/, - ui::DisplayPrimaries& /*primaries*/) override { - return NO_ERROR; - } - status_t setActiveColorMode(const sp<IBinder>& /*display*/, ColorMode /*colorMode*/) override { - return NO_ERROR; - } - status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override { - return NO_ERROR; - } +class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer { +public: + ~FakeSurfaceComposerAIDL() override {} - status_t clearAnimationFrameStats() override { return NO_ERROR; } - status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { - return NO_ERROR; + void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; } + + binder::Status bootFinished() override { return binder::Status::ok(); } + + binder::Status createDisplayEventConnection( + VsyncSource /*vsyncSource*/, EventRegistration /*eventRegistration*/, + sp<gui::IDisplayEventConnection>* outConnection) override { + *outConnection = nullptr; + return binder::Status::ok(); } - status_t overrideHdrTypes(const sp<IBinder>& /*display*/, - const std::vector<ui::Hdr>& /*hdrTypes*/) override { - return NO_ERROR; + + binder::Status createConnection(sp<gui::ISurfaceComposerClient>* outClient) override { + *outClient = nullptr; + return binder::Status::ok(); } - status_t onPullAtom(const int32_t /*atomId*/, std::string* /*outData*/, - bool* /*success*/) override { - return NO_ERROR; + + binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/, + sp<IBinder>* /*outDisplay*/) override { + return binder::Status::ok(); } - status_t enableVSyncInjections(bool /*enable*/) override { - return NO_ERROR; + + binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override { + return binder::Status::ok(); } - status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; } - status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) override { - return NO_ERROR; + + binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override { + return binder::Status::ok(); } - status_t getCompositionPreference( - ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/, - ui::Dataspace* /*outWideColorGamutDataspace*/, - ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override { - return NO_ERROR; + + binder::Status getPhysicalDisplayToken(int64_t /*displayId*/, + sp<IBinder>* /*outDisplay*/) override { + return binder::Status::ok(); } - status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& /*display*/, - ui::PixelFormat* /*outFormat*/, - ui::Dataspace* /*outDataspace*/, - uint8_t* /*outComponentMask*/) const override { - return NO_ERROR; + + binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override { + return binder::Status::ok(); } - status_t setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/, - uint8_t /*componentMask*/, - uint64_t /*maxFrames*/) override { - return NO_ERROR; + + binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override { + *outSupported = {FrameEvent::REQUESTED_PRESENT, + FrameEvent::ACQUIRE, + FrameEvent::LATCH, + FrameEvent::FIRST_REFRESH_START, + FrameEvent::LAST_REFRESH_START, + FrameEvent::GPU_COMPOSITION_DONE, + FrameEvent::DEQUEUE_READY, + FrameEvent::RELEASE}; + if (mSupportsPresent) { + outSupported->push_back(FrameEvent::DISPLAY_PRESENT); + } + return binder::Status::ok(); } - status_t getDisplayedContentSample(const sp<IBinder>& /*display*/, uint64_t /*maxFrames*/, - uint64_t /*timestamp*/, - DisplayedFrameStats* /*outStats*/) const override { - return NO_ERROR; + + binder::Status getDisplayStats(const sp<IBinder>& /*display*/, + gui::DisplayStatInfo* /*outStatInfo*/) override { + return binder::Status::ok(); } - status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; } - status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; } + binder::Status getDisplayState(const sp<IBinder>& /*display*/, + gui::DisplayState* /*outState*/) override { + return binder::Status::ok(); + } - status_t addRegionSamplingListener(const Rect& /*samplingArea*/, - const sp<IBinder>& /*stopLayerHandle*/, - const sp<IRegionSamplingListener>& /*listener*/) override { - return NO_ERROR; + binder::Status getStaticDisplayInfo(const sp<IBinder>& /*display*/, + gui::StaticDisplayInfo* /*outInfo*/) override { + return binder::Status::ok(); } - status_t removeRegionSamplingListener( - const sp<IRegionSamplingListener>& /*listener*/) override { - return NO_ERROR; + + binder::Status getDynamicDisplayInfo(const sp<IBinder>& /*display*/, + gui::DynamicDisplayInfo* /*outInfo*/) override { + return binder::Status::ok(); } - status_t addFpsListener(int32_t /*taskId*/, const sp<gui::IFpsListener>& /*listener*/) { - return NO_ERROR; + + binder::Status getDisplayNativePrimaries(const sp<IBinder>& /*display*/, + gui::DisplayPrimaries* /*outPrimaries*/) override { + return binder::Status::ok(); } - status_t removeFpsListener(const sp<gui::IFpsListener>& /*listener*/) { return NO_ERROR; } - status_t addTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& /*listener*/) { - return NO_ERROR; + binder::Status setActiveColorMode(const sp<IBinder>& /*display*/, int /*colorMode*/) override { + return binder::Status::ok(); } - status_t removeTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& /*listener*/) { - return NO_ERROR; + binder::Status setBootDisplayMode(const sp<IBinder>& /*display*/, + int /*displayModeId*/) override { + return binder::Status::ok(); } - status_t setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, - ui::DisplayModeId /*defaultMode*/, - bool /*allowGroupSwitching*/, - float /*primaryRefreshRateMin*/, - float /*primaryRefreshRateMax*/, - float /*appRequestRefreshRateMin*/, - float /*appRequestRefreshRateMax*/) { - return NO_ERROR; + binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override { + return binder::Status::ok(); } - status_t getDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, - ui::DisplayModeId* /*outDefaultMode*/, - bool* /*outAllowGroupSwitching*/, - float* /*outPrimaryRefreshRateMin*/, - float* /*outPrimaryRefreshRateMax*/, - float* /*outAppRequestRefreshRateMin*/, - float* /*outAppRequestRefreshRateMax*/) override { - return NO_ERROR; - }; - status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/, - float /*lightPosY*/, float /*lightPosZ*/, - float /*lightRadius*/) override { - return NO_ERROR; + binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override { + return binder::Status::ok(); } - status_t getDisplayDecorationSupport( - const sp<IBinder>& /*displayToken*/, - std::optional<DisplayDecorationSupport>* /*outSupport*/) const override { - return NO_ERROR; + binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override { + return binder::Status::ok(); } - status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/, - int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) override { - return NO_ERROR; + binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override { + return binder::Status::ok(); } - status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& /*surface*/, - const FrameTimelineInfo& /*frameTimelineInfo*/) override { - return NO_ERROR; + binder::Status captureDisplay(const DisplayCaptureArgs&, + const sp<IScreenCaptureListener>&) override { + return binder::Status::ok(); } - status_t addTransactionTraceListener( - const sp<gui::ITransactionTraceListener>& /*listener*/) override { - return NO_ERROR; + binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override { + return binder::Status::ok(); } - int getGPUContextPriority() override { return 0; }; + binder::Status captureLayers(const LayerCaptureArgs&, + const sp<IScreenCaptureListener>&) override { + return binder::Status::ok(); + } - status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; } + binder::Status clearAnimationFrameStats() override { return binder::Status::ok(); } - status_t addWindowInfosListener( - const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override { - return NO_ERROR; + binder::Status getAnimationFrameStats(gui::FrameStats* /*outStats*/) override { + return binder::Status::ok(); } - status_t removeWindowInfosListener( - const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override { - return NO_ERROR; + binder::Status overrideHdrTypes(const sp<IBinder>& /*display*/, + const std::vector<int32_t>& /*hdrTypes*/) override { + return binder::Status::ok(); } - status_t setOverrideFrameRate(uid_t /*uid*/, float /*frameRate*/) override { return NO_ERROR; } - -protected: - IBinder* onAsBinder() override { return nullptr; } - -private: - bool mSupportsPresent{true}; -}; + binder::Status onPullAtom(int32_t /*atomId*/, gui::PullAtomData* /*outPullData*/) override { + return binder::Status::ok(); + } -class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer { -public: - ~FakeSurfaceComposerAIDL() override {} + binder::Status enableVSyncInjections(bool /*enable*/) override { return binder::Status::ok(); } - void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; } + binder::Status injectVSync(int64_t /*when*/) override { return binder::Status::ok(); } - binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/, - sp<IBinder>* /*outDisplay*/) override { + binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* /*outLayers*/) override { return binder::Status::ok(); } - binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override { + binder::Status getColorManagement(bool* /*outGetColorManagement*/) override { return binder::Status::ok(); } - binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override { + binder::Status getCompositionPreference(gui::CompositionPreference* /*outPref*/) override { return binder::Status::ok(); } - binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override { + binder::Status getDisplayedContentSamplingAttributes( + const sp<IBinder>& /*display*/, gui::ContentSamplingAttributes* /*outAttrs*/) override { return binder::Status::ok(); } - binder::Status getPhysicalDisplayToken(int64_t /*displayId*/, - sp<IBinder>* /*outDisplay*/) override { + binder::Status setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/, + int8_t /*componentMask*/, + int64_t /*maxFrames*/) override { return binder::Status::ok(); } - binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override { + binder::Status getProtectedContentSupport(bool* /*outSupporte*/) override { return binder::Status::ok(); } - binder::Status getDisplayStats(const sp<IBinder>& /*display*/, - gui::DisplayStatInfo* /*outStatInfo*/) override { + binder::Status getDisplayedContentSample(const sp<IBinder>& /*display*/, int64_t /*maxFrames*/, + int64_t /*timestamp*/, + gui::DisplayedFrameStats* /*outStats*/) override { return binder::Status::ok(); } - binder::Status getDisplayState(const sp<IBinder>& /*display*/, - gui::DisplayState* /*outState*/) override { + binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/, + bool* /*outIsWideColorDisplay*/) override { return binder::Status::ok(); } - binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override { + binder::Status addRegionSamplingListener( + const gui::ARect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/, + const sp<gui::IRegionSamplingListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override { + binder::Status removeRegionSamplingListener( + const sp<gui::IRegionSamplingListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override { + binder::Status addFpsListener(int32_t /*taskId*/, + const sp<gui::IFpsListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override { + binder::Status removeFpsListener(const sp<gui::IFpsListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status captureDisplay(const DisplayCaptureArgs&, - const sp<IScreenCaptureListener>&) override { + binder::Status addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override { + binder::Status removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status captureLayers(const LayerCaptureArgs&, - const sp<IScreenCaptureListener>&) override { + binder::Status setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, + int32_t /*defaultMode*/, bool /*allowGroupSwitching*/, + float /*primaryRefreshRateMin*/, + float /*primaryRefreshRateMax*/, + float /*appRequestRefreshRateMin*/, + float /*appRequestRefreshRateMax*/) override { return binder::Status::ok(); } - binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/, - bool* /*outIsWideColorDisplay*/) override { + binder::Status getDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, + gui::DisplayModeSpecs* /*outSpecs*/) override { return binder::Status::ok(); } @@ -989,6 +958,45 @@ public: binder::Status notifyPowerBoost(int /*boostId*/) override { return binder::Status::ok(); } + binder::Status setGlobalShadowSettings(const gui::Color& /*ambientColor*/, + const gui::Color& /*spotColor*/, float /*lightPosY*/, + float /*lightPosZ*/, float /*lightRadius*/) override { + return binder::Status::ok(); + } + + binder::Status getDisplayDecorationSupport( + const sp<IBinder>& /*displayToken*/, + std::optional<gui::DisplayDecorationSupport>* /*outSupport*/) override { + return binder::Status::ok(); + } + + binder::Status setOverrideFrameRate(int32_t /*uid*/, float /*frameRate*/) override { + return binder::Status::ok(); + } + + binder::Status addTransactionTraceListener( + const sp<gui::ITransactionTraceListener>& /*listener*/) override { + return binder::Status::ok(); + } + + binder::Status getGpuContextPriority(int32_t* /*outPriority*/) override { + return binder::Status::ok(); + } + + binder::Status getMaxAcquiredBufferCount(int32_t* /*buffers*/) override { + return binder::Status::ok(); + } + + binder::Status addWindowInfosListener( + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override { + return binder::Status::ok(); + } + + binder::Status removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } @@ -1034,10 +1042,10 @@ protected: class TestSurface : public Surface { public: - TestSurface(const sp<IGraphicBufferProducer>& bufferProducer, - FenceToFenceTimeMap* fenceMap) - : Surface(bufferProducer), - mFakeSurfaceComposer(new FakeSurfaceComposer) { + TestSurface(const sp<IGraphicBufferProducer>& bufferProducer, FenceToFenceTimeMap* fenceMap) + : Surface(bufferProducer), + mFakeSurfaceComposer(new FakeSurfaceComposer), + mFakeSurfaceComposerAIDL(new FakeSurfaceComposerAIDL) { mFakeFrameEventHistory = new FakeProducerFrameEventHistory(fenceMap); mFrameEventHistory.reset(mFakeFrameEventHistory); } @@ -1048,6 +1056,10 @@ public: return mFakeSurfaceComposer; } + sp<gui::ISurfaceComposer> composerServiceAIDL() const override { + return mFakeSurfaceComposerAIDL; + } + nsecs_t now() const override { return mNow; } @@ -1058,6 +1070,7 @@ public: public: sp<FakeSurfaceComposer> mFakeSurfaceComposer; + sp<FakeSurfaceComposerAIDL> mFakeSurfaceComposerAIDL; nsecs_t mNow = 0; // mFrameEventHistory owns the instance of FakeProducerFrameEventHistory, @@ -1070,20 +1083,30 @@ class GetFrameTimestampsTest : public ::testing::Test { protected: struct FenceAndFenceTime { explicit FenceAndFenceTime(FenceToFenceTimeMap& fenceMap) - : mFence(new Fence), - mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {} - sp<Fence> mFence { nullptr }; - std::shared_ptr<FenceTime> mFenceTime { nullptr }; + : mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {} + + sp<Fence> mFence = sp<Fence>::make(); + std::shared_ptr<FenceTime> mFenceTime; }; + static CompositorTiming makeCompositorTiming(nsecs_t deadline = 1'000'000'000, + nsecs_t interval = 16'666'667, + nsecs_t presentLatency = 50'000'000) { + CompositorTiming timing; + timing.deadline = deadline; + timing.interval = interval; + timing.presentLatency = presentLatency; + return timing; + } + struct RefreshEvents { RefreshEvents(FenceToFenceTimeMap& fenceMap, nsecs_t refreshStart) - : mFenceMap(fenceMap), - kCompositorTiming( - {refreshStart, refreshStart + 1, refreshStart + 2 }), - kStartTime(refreshStart + 3), - kGpuCompositionDoneTime(refreshStart + 4), - kPresentTime(refreshStart + 5) {} + : mFenceMap(fenceMap), + kCompositorTiming( + makeCompositorTiming(refreshStart, refreshStart + 1, refreshStart + 2)), + kStartTime(refreshStart + 3), + kGpuCompositionDoneTime(refreshStart + 4), + kPresentTime(refreshStart + 5) {} void signalPostCompositeFences() { mFenceMap.signalAllForTest( @@ -1093,8 +1116,8 @@ protected: FenceToFenceTimeMap& mFenceMap; - FenceAndFenceTime mGpuCompositionDone { mFenceMap }; - FenceAndFenceTime mPresent { mFenceMap }; + FenceAndFenceTime mGpuCompositionDone{mFenceMap}; + FenceAndFenceTime mPresent{mFenceMap}; const CompositorTiming kCompositorTiming; @@ -1360,11 +1383,7 @@ TEST_F(GetFrameTimestampsTest, DefaultDisabled) { // This test verifies that the frame timestamps are retrieved if explicitly // enabled via native_window_enable_frame_timestamps. TEST_F(GetFrameTimestampsTest, EnabledSimple) { - CompositorTiming initialCompositorTiming { - 1000000000, // 1s deadline - 16666667, // 16ms interval - 50000000, // 50ms present latency - }; + const CompositorTiming initialCompositorTiming = makeCompositorTiming(); mCfeh->initializeCompositorTiming(initialCompositorTiming); enableFrameTimestamps(); @@ -1424,6 +1443,7 @@ TEST_F(GetFrameTimestampsTest, EnabledSimple) { TEST_F(GetFrameTimestampsTest, QueryPresentSupported) { bool displayPresentSupported = true; mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported); + mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(displayPresentSupported); // Verify supported bits are forwarded. int supportsPresent = -1; @@ -1435,6 +1455,7 @@ TEST_F(GetFrameTimestampsTest, QueryPresentSupported) { TEST_F(GetFrameTimestampsTest, QueryPresentNotSupported) { bool displayPresentSupported = false; mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported); + mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(displayPresentSupported); // Verify supported bits are forwarded. int supportsPresent = -1; @@ -1501,11 +1522,7 @@ TEST_F(GetFrameTimestampsTest, SnapToNextTickOverflow) { // This verifies the compositor timing is updated by refresh events // and piggy backed on a queue, dequeue, and enabling of timestamps.. TEST_F(GetFrameTimestampsTest, CompositorTimingUpdatesBasic) { - CompositorTiming initialCompositorTiming { - 1000000000, // 1s deadline - 16666667, // 16ms interval - 50000000, // 50ms present latency - }; + const CompositorTiming initialCompositorTiming = makeCompositorTiming(); mCfeh->initializeCompositorTiming(initialCompositorTiming); enableFrameTimestamps(); @@ -1586,11 +1603,7 @@ TEST_F(GetFrameTimestampsTest, CompositorTimingUpdatesBasic) { // This verifies the compositor deadline properly snaps to the the next // deadline based on the current time. TEST_F(GetFrameTimestampsTest, CompositorTimingDeadlineSnaps) { - CompositorTiming initialCompositorTiming { - 1000000000, // 1s deadline - 16666667, // 16ms interval - 50000000, // 50ms present latency - }; + const CompositorTiming initialCompositorTiming = makeCompositorTiming(); mCfeh->initializeCompositorTiming(initialCompositorTiming); enableFrameTimestamps(); @@ -2012,6 +2025,7 @@ TEST_F(GetFrameTimestampsTest, NoReleaseNoSync) { TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) { enableFrameTimestamps(); mSurface->mFakeSurfaceComposer->setSupportsPresent(false); + mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(false); // Dequeue and queue frame 1. const uint64_t fId1 = getNextFrameId(); diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index 99658ccd4b..c51b244c50 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -71,7 +71,6 @@ TEST(WindowInfo, Parcelling) { i.applicationInfo.name = "ApplicationFooBar"; i.applicationInfo.token = new BBinder(); i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD; - i.isClone = true; Parcel p; i.writeToParcel(&p); @@ -102,7 +101,6 @@ 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/Android.bp b/libs/input/Android.bp index b2fec7917b..29e02cf73a 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -26,7 +26,7 @@ package { filegroup { name: "inputconstants_aidl", srcs: [ - "android/os/BlockUntrustedTouchesMode.aidl", + "android/hardware/input/InputDeviceCountryCode.aidl", "android/os/IInputConstants.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 2b7483d27d..579b28e588 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -87,6 +87,8 @@ const char* motionClassificationToString(MotionClassification classification) { return "AMBIGUOUS_GESTURE"; case MotionClassification::DEEP_PRESS: return "DEEP_PRESS"; + case MotionClassification::TWO_FINGER_SWIPE: + return "TWO_FINGER_SWIPE"; } } diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index a9089690b0..3fe03c7979 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -26,6 +26,7 @@ #include <input/InputEventLabels.h> using android::base::StringPrintf; +using android::hardware::input::InputDeviceCountryCode; namespace android { @@ -177,6 +178,7 @@ InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) mAlias(other.mAlias), mIsExternal(other.mIsExternal), mHasMic(other.mHasMic), + mCountryCode(other.mCountryCode), mSources(other.mSources), mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), @@ -192,8 +194,8 @@ InputDeviceInfo::~InputDeviceInfo() { } void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal, - bool hasMic) { + const InputDeviceIdentifier& identifier, const std::string& alias, + bool isExternal, bool hasMic, InputDeviceCountryCode countryCode) { mId = id; mGeneration = generation; mControllerNumber = controllerNumber; @@ -201,6 +203,7 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control mAlias = alias; mIsExternal = isExternal; mHasMic = hasMic; + mCountryCode = countryCode; mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index c0aa2e26a2..163a2fe924 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -23,6 +23,8 @@ namespace android { +// clang-format off + // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. #define KEYCODES_SEQUENCE \ @@ -314,7 +316,30 @@ namespace android { DEFINE_KEYCODE(REFRESH), \ DEFINE_KEYCODE(THUMBS_UP), \ DEFINE_KEYCODE(THUMBS_DOWN), \ - DEFINE_KEYCODE(PROFILE_SWITCH) + DEFINE_KEYCODE(PROFILE_SWITCH), \ + DEFINE_KEYCODE(VIDEO_APP_1), \ + DEFINE_KEYCODE(VIDEO_APP_2), \ + DEFINE_KEYCODE(VIDEO_APP_3), \ + DEFINE_KEYCODE(VIDEO_APP_4), \ + DEFINE_KEYCODE(VIDEO_APP_5), \ + DEFINE_KEYCODE(VIDEO_APP_6), \ + DEFINE_KEYCODE(VIDEO_APP_7), \ + DEFINE_KEYCODE(VIDEO_APP_8), \ + DEFINE_KEYCODE(FEATURED_APP_1), \ + DEFINE_KEYCODE(FEATURED_APP_2), \ + DEFINE_KEYCODE(FEATURED_APP_3), \ + DEFINE_KEYCODE(FEATURED_APP_4), \ + DEFINE_KEYCODE(DEMO_APP_1), \ + DEFINE_KEYCODE(DEMO_APP_2), \ + DEFINE_KEYCODE(DEMO_APP_3), \ + DEFINE_KEYCODE(DEMO_APP_4), \ + DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_DOWN), \ + DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_UP), \ + DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_TOGGLE), \ + DEFINE_KEYCODE(STYLUS_BUTTON_PRIMARY), \ + DEFINE_KEYCODE(STYLUS_BUTTON_SECONDARY), \ + DEFINE_KEYCODE(STYLUS_BUTTON_TERTIARY), \ + DEFINE_KEYCODE(STYLUS_BUTTON_TAIL) // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. @@ -368,7 +393,6 @@ namespace android { DEFINE_AXIS(GENERIC_15), \ DEFINE_AXIS(GENERIC_16) - // NOTE: If you add new LEDs here, you must also add them to Input.h #define LEDS_SEQUENCE \ DEFINE_LED(NUM_LOCK), \ @@ -393,6 +417,8 @@ namespace android { DEFINE_FLAG(GESTURE), \ DEFINE_FLAG(WAKE) +// clang-format on + // --- InputEventLookup --- const std::unordered_map<std::string, int> InputEventLookup::KEYCODES = {KEYCODES_SEQUENCE}; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 61950522ff..8d8433b973 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -51,7 +51,7 @@ static const nsecs_t NANOS_PER_MS = 1000000; // Latency added during resampling. A few milliseconds doesn't hurt much but // reduces the impact of mispredicted touch positions. -static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS; +const std::chrono::duration RESAMPLE_LATENCY = 5ms; // Minimum time difference between consecutive samples before attempting to resample. static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS; @@ -721,7 +721,11 @@ android::base::Result<InputPublisher::ConsumerResponse> InputPublisher::receiveC // --- InputConsumer --- InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel) - : mResampleTouch(isTouchResamplingEnabled()), mChannel(channel), mMsgDeferred(false) {} + : InputConsumer(channel, isTouchResamplingEnabled()) {} + +InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel, + bool enableTouchResampling) + : mResampleTouch(enableTouchResampling), mChannel(channel), mMsgDeferred(false) {} InputConsumer::~InputConsumer() { } @@ -751,7 +755,10 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum // Receive a fresh message. status_t result = mChannel->receiveMessage(&mMsg); if (result == OK) { - mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC)); + const auto [_, inserted] = + mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC)); + LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32, + mMsg.header.seq); } if (result) { // Consume the next batched event unless batches are being held for later. @@ -918,7 +925,7 @@ status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, nsecs_t sampleTime = frameTime; if (mResampleTouch) { - sampleTime -= RESAMPLE_LATENCY; + sampleTime -= std::chrono::nanoseconds(RESAMPLE_LATENCY).count(); } ssize_t split = findSampleNoLaterThan(batch, sampleTime); if (split < 0) { @@ -1166,6 +1173,11 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, return; } + if (current->eventTime == sampleTime) { + // Prevents having 2 events with identical times and coordinates. + return; + } + // Resample touch coordinates. History oldLastResample; oldLastResample.initializeFrom(touchState.lastResample); diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 2039fa6553..422e6e09eb 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -304,9 +304,8 @@ char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { char16_t result = 0; - const Key* key; - const Behavior* behavior; - if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { + const Behavior* behavior = getKeyBehavior(keyCode, metaState); + if (behavior != nullptr) { result = behavior->character; } #if DEBUG_MAPPING @@ -321,9 +320,8 @@ bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, outFallbackAction->metaState = 0; bool result = false; - const Key* key; - const Behavior* behavior; - if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { + const Behavior* behavior = getKeyBehavior(keyCode, metaState); + if (behavior != nullptr) { if (behavior->fallbackKeyCode) { outFallbackAction->keyCode = behavior->fallbackKeyCode; outFallbackAction->metaState = metaState & ~behavior->metaState; @@ -347,12 +345,12 @@ char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_ // Try to find the most general behavior that maps to this character. // For example, the base key behavior will usually be last in the list. // However, if we find a perfect meta state match for one behavior then use that one. - for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { - if (behavior->character) { + for (const Behavior& behavior : key->behaviors) { + if (behavior.character) { for (size_t i = 0; i < numChars; i++) { - if (behavior->character == chars[i]) { - result = behavior->character; - if ((behavior->metaState & metaState) == behavior->metaState) { + if (behavior.character == chars[i]) { + result = behavior.character; + if ((behavior.metaState & metaState) == behavior.metaState) { goto ExactMatch; } break; @@ -438,9 +436,8 @@ void KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState, *outKeyCode = keyCode; *outMetaState = metaState; - const Key* key; - const Behavior* behavior; - if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { + const Behavior* behavior = getKeyBehavior(keyCode, metaState); + if (behavior != nullptr) { if (behavior->replacementKeyCode) { *outKeyCode = behavior->replacementKeyCode; int32_t newMetaState = metaState & ~behavior->metaState; @@ -484,21 +481,17 @@ bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { return false; } -bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, - const Key** outKey, const Behavior** outBehavior) const { +const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode, + int32_t metaState) const { const Key* key; if (getKey(keyCode, &key)) { - const Behavior* behavior = key->firstBehavior; - while (behavior) { - if (matchesMetaState(metaState, behavior->metaState)) { - *outKey = key; - *outBehavior = behavior; - return true; + for (const Behavior& behavior : key->behaviors) { + if (matchesMetaState(metaState, behavior.metaState)) { + return &behavior; } - behavior = behavior->next; } } - return false; + return nullptr; } bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) { @@ -543,12 +536,12 @@ bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMeta // Try to find the most general behavior that maps to this character. // For example, the base key behavior will usually be last in the list. const Behavior* found = nullptr; - for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { - if (behavior->character == ch) { - found = behavior; + for (const Behavior& behavior : key->behaviors) { + if (behavior.character == ch) { + found = &behavior; } } - if (found) { + if (found != nullptr) { *outKeyCode = mKeys.keyAt(i); *outMetaState = found->metaState; return true; @@ -706,7 +699,6 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) key->number = number; map->mKeys.add(keyCode, key); - Behavior* lastBehavior = nullptr; while (parcel->readInt32()) { int32_t metaState = parcel->readInt32(); char16_t character = parcel->readInt32(); @@ -716,17 +708,12 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) return nullptr; } - Behavior* behavior = new Behavior(); - behavior->metaState = metaState; - behavior->character = character; - behavior->fallbackKeyCode = fallbackKeyCode; - behavior->replacementKeyCode = replacementKeyCode; - if (lastBehavior) { - lastBehavior->next = behavior; - } else { - key->firstBehavior = behavior; - } - lastBehavior = behavior; + key->behaviors.push_back({ + .metaState = metaState, + .character = character, + .fallbackKeyCode = fallbackKeyCode, + .replacementKeyCode = replacementKeyCode, + }); } if (parcel->errorCheck()) { @@ -777,13 +764,12 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const { parcel->writeInt32(keyCode); parcel->writeInt32(key->label); parcel->writeInt32(key->number); - for (const Behavior* behavior = key->firstBehavior; behavior != nullptr; - behavior = behavior->next) { + for (const Behavior& behavior : key->behaviors) { parcel->writeInt32(1); - parcel->writeInt32(behavior->metaState); - parcel->writeInt32(behavior->character); - parcel->writeInt32(behavior->fallbackKeyCode); - parcel->writeInt32(behavior->replacementKeyCode); + parcel->writeInt32(behavior.metaState); + parcel->writeInt32(behavior.character); + parcel->writeInt32(behavior.fallbackKeyCode); + parcel->writeInt32(behavior.replacementKeyCode); } parcel->writeInt32(0); } @@ -804,38 +790,10 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const { // --- KeyCharacterMap::Key --- -KeyCharacterMap::Key::Key() : - label(0), number(0), firstBehavior(nullptr) { -} - -KeyCharacterMap::Key::Key(const Key& other) : - label(other.label), number(other.number), - firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : nullptr) { -} - -KeyCharacterMap::Key::~Key() { - Behavior* behavior = firstBehavior; - while (behavior) { - Behavior* next = behavior->next; - delete behavior; - behavior = next; - } -} - - -// --- KeyCharacterMap::Behavior --- - -KeyCharacterMap::Behavior::Behavior() : - next(nullptr), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) { -} - -KeyCharacterMap::Behavior::Behavior(const Behavior& other) : - next(other.next ? new Behavior(*other.next) : nullptr), - metaState(other.metaState), character(other.character), - fallbackKeyCode(other.fallbackKeyCode), - replacementKeyCode(other.replacementKeyCode) { -} +KeyCharacterMap::Key::Key() : label(0), number(0) {} +KeyCharacterMap::Key::Key(const Key& other) + : label(other.label), number(other.number), behaviors(other.behaviors) {} // --- KeyCharacterMap::Parser --- @@ -1213,23 +1171,21 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { #endif break; case PROPERTY_META: { - for (Behavior* b = key->firstBehavior; b; b = b->next) { - if (b->metaState == property.metaState) { + for (const Behavior& b : key->behaviors) { + if (b.metaState == property.metaState) { ALOGE("%s: Duplicate key behavior for modifier.", mTokenizer->getLocation().string()); return BAD_VALUE; } } - Behavior* newBehavior = new Behavior(behavior); - newBehavior->metaState = property.metaState; - newBehavior->next = key->firstBehavior; - key->firstBehavior = newBehavior; -#if DEBUG_PARSER - ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.", - mKeyCode, - newBehavior->metaState, newBehavior->character, - newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode); -#endif + Behavior newBehavior = behavior; + newBehavior.metaState = property.metaState; + key->behaviors.push_front(newBehavior); + ALOGD_IF(DEBUG_PARSER, + "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.", + mKeyCode, key->behaviors.front().metaState, key->behaviors.front().character, + key->behaviors.front().fallbackKeyCode, + key->behaviors.front().replacementKeyCode); break; } } @@ -1242,8 +1198,8 @@ status_t KeyCharacterMap::Parser::finishKey(Key* key) { if (!key->number) { char16_t digit = 0; char16_t symbol = 0; - for (Behavior* b = key->firstBehavior; b; b = b->next) { - char16_t ch = b->character; + for (const Behavior& b : key->behaviors) { + char16_t ch = b.character; if (ch) { if (ch >= '0' && ch <= '9') { digit = ch; diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index d6b4579a94..73710330d0 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -192,7 +192,8 @@ status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode, } // Return pair of sensor type and sensor data index, for the input device abs code -base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(int32_t absCode) { +base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor( + int32_t absCode) const { auto it = mSensorsByAbsCode.find(absCode); if (it == mSensorsByAbsCode.end()) { ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode); diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index c3f5151fd1..3f8467d818 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -49,25 +49,23 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { - String8 keyLayoutName; - if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), - keyLayoutName)) { + std::string keyLayoutName; + if (deviceConfiguration->tryGetProperty("keyboard.layout", keyLayoutName)) { status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " - "it was not found.", - deviceIdentifier.name.c_str(), keyLayoutName.string()); + "it was not found.", + deviceIdentifier.name.c_str(), keyLayoutName.c_str()); } } - String8 keyCharacterMapName; - if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), - keyCharacterMapName)) { + std::string keyCharacterMapName; + if (deviceConfiguration->tryGetProperty("keyboard.characterMap", keyCharacterMapName)) { status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " - "map '%s' but it was not found.", - deviceIdentifier.name.c_str(), keyCharacterMapName.string()); + "map '%s' but it was not found.", + deviceIdentifier.name.c_str(), keyCharacterMapName.c_str()); } } @@ -165,7 +163,7 @@ bool isKeyboardSpecialFunction(const PropertyMap* config) { return false; } bool isSpecialFunction = false; - config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction); + config->tryGetProperty("keyboard.specialFunction", isSpecialFunction); return isSpecialFunction; } @@ -180,8 +178,7 @@ bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, if (deviceConfiguration) { bool builtIn = false; - if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) - && builtIn) { + if (deviceConfiguration->tryGetProperty("keyboard.builtIn", builtIn) && builtIn) { return true; } } diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp index a842166761..16ffa10223 100644 --- a/libs/input/PropertyMap.cpp +++ b/libs/input/PropertyMap.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "PropertyMap" #include <input/PropertyMap.h> +#include <log/log.h> // Enables debug output for the parser. #define DEBUG_PARSER 0 @@ -39,25 +40,25 @@ void PropertyMap::clear() { mProperties.clear(); } -void PropertyMap::addProperty(const String8& key, const String8& value) { - mProperties.add(key, value); +void PropertyMap::addProperty(const std::string& key, const std::string& value) { + mProperties.emplace(key, value); } -bool PropertyMap::hasProperty(const String8& key) const { - return mProperties.indexOfKey(key) >= 0; +bool PropertyMap::hasProperty(const std::string& key) const { + return mProperties.find(key) != mProperties.end(); } -bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const { - ssize_t index = mProperties.indexOfKey(key); - if (index < 0) { +bool PropertyMap::tryGetProperty(const std::string& key, std::string& outValue) const { + auto it = mProperties.find(key); + if (it == mProperties.end()) { return false; } - outValue = mProperties.valueAt(index); + outValue = it->second; return true; } -bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { +bool PropertyMap::tryGetProperty(const std::string& key, bool& outValue) const { int32_t intValue; if (!tryGetProperty(key, intValue)) { return false; @@ -67,34 +68,34 @@ bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { return true; } -bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { - String8 stringValue; +bool PropertyMap::tryGetProperty(const std::string& key, int32_t& outValue) const { + std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; - int value = strtol(stringValue.string(), &end, 10); + int32_t value = static_cast<int32_t>(strtol(stringValue.c_str(), &end, 10)); if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.string(), - stringValue.string()); + ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(), + stringValue.c_str()); return false; } outValue = value; return true; } -bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { - String8 stringValue; +bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const { + std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; - float value = strtof(stringValue.string(), &end); + float value = strtof(stringValue.c_str(), &end); if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.string(), - stringValue.string()); + ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.c_str(), + stringValue.c_str()); return false; } outValue = value; @@ -102,8 +103,8 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { } void PropertyMap::addAll(const PropertyMap* map) { - for (size_t i = 0; i < map->mProperties.size(); i++) { - mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i)); + for (const auto& [key, value] : map->mProperties) { + mProperties.emplace(key, value); } } @@ -184,13 +185,13 @@ status_t PropertyMap::Parser::parse() { return BAD_VALUE; } - if (mMap->hasProperty(keyToken)) { + if (mMap->hasProperty(keyToken.string())) { ALOGE("%s: Duplicate property value for key '%s'.", mTokenizer->getLocation().string(), keyToken.string()); return BAD_VALUE; } - mMap->addProperty(keyToken, valueToken); + mMap->addProperty(keyToken.string(), valueToken.string()); } mTokenizer->nextLine(); diff --git a/libs/input/PropertyMap_fuzz.cpp b/libs/input/PropertyMap_fuzz.cpp index afb97a1d47..d985dc1748 100755 --- a/libs/input/PropertyMap_fuzz.cpp +++ b/libs/input/PropertyMap_fuzz.cpp @@ -17,32 +17,22 @@ #include "android-base/file.h" #include "fuzzer/FuzzedDataProvider.h" #include "input/PropertyMap.h" -#include "utils/String8.h" static constexpr int MAX_FILE_SIZE = 256; static constexpr int MAX_STR_LEN = 2048; static constexpr int MAX_OPERATIONS = 1000; -static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap)>> +static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap&)>> operations = { - [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { - propertyMap.getProperties(); - }, - [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { + [](FuzzedDataProvider*, android::PropertyMap& propertyMap) -> void { propertyMap.clear(); }, - [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { - std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); - android::String8 key = android::String8(keyStr.c_str()); - propertyMap.hasProperty(key); - }, - [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { - std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); - android::String8 key = android::String8(keyStr.c_str()); - android::String8 out; + [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void { + std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); + std::string out; propertyMap.tryGetProperty(key, out); }, - [](FuzzedDataProvider* dataProvider, android::PropertyMap /*unused*/) -> void { + [](FuzzedDataProvider* dataProvider, android::PropertyMap& /*unused*/) -> void { TemporaryFile tf; // Generate file contents std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE); @@ -54,17 +44,15 @@ static const std::vector<std::function<void(FuzzedDataProvider*, android::Proper } android::PropertyMap::load(tf.path); }, - [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { - std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); - std::string valStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); - android::String8 key = android::String8(keyStr.c_str()); - android::String8 val = android::String8(valStr.c_str()); + [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void { + std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); + std::string val = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); propertyMap.addProperty(key, val); }, }; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider dataProvider(data, size); - android::PropertyMap propertyMap = android::PropertyMap(); + android::PropertyMap propertyMap; int opsRun = 0; while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) { diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp index 6e991e98bb..e2bfb508e1 100644 --- a/libs/input/VelocityControl.cpp +++ b/libs/input/VelocityControl.cpp @@ -44,8 +44,8 @@ void VelocityControl::setParameters(const VelocityControlParameters& parameters) void VelocityControl::reset() { mLastMovementTime = LLONG_MIN; - mRawPosition.x = 0; - mRawPosition.y = 0; + mRawPositionX = 0; + mRawPositionY = 0; mVelocityTracker.clear(); } @@ -61,17 +61,20 @@ void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { mLastMovementTime = eventTime; if (deltaX) { - mRawPosition.x += *deltaX; + mRawPositionX += *deltaX; } if (deltaY) { - mRawPosition.y += *deltaY; + mRawPositionY += *deltaY; } - mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), {mRawPosition}); + mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), + {{AMOTION_EVENT_AXIS_X, {mRawPositionX}}, + {AMOTION_EVENT_AXIS_Y, {mRawPositionY}}}); - float vx, vy; + std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0); + std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0); float scale = mParameters.scale; - if (mVelocityTracker.getVelocity(0, &vx, &vy)) { - float speed = hypotf(vx, vy) * scale; + if (vx && vy) { + float speed = hypotf(*vx, *vy) * scale; if (speed >= mParameters.highThreshold) { // Apply full acceleration above the high speed threshold. scale *= mParameters.acceleration; @@ -85,10 +88,9 @@ void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { if (DEBUG_ACCELERATION) { ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " - "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", - mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, - mParameters.acceleration, - vx, vy, speed, scale / mParameters.scale); + "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", + mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, + mParameters.acceleration, *vx, *vy, speed, scale / mParameters.scale); } } else { diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 7f427f2364..4a4f734a86 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -27,6 +27,8 @@ #include <utils/BitSet.h> #include <utils/Timers.h> +using std::literals::chrono_literals::operator""ms; + namespace android { /** @@ -53,12 +55,34 @@ const bool DEBUG_IMPULSE = // Nanoseconds per milliseconds. static const nsecs_t NANOS_PER_MS = 1000000; +// All axes supported for velocity tracking, mapped to their default strategies. +// Although other strategies are available for testing and comparison purposes, +// the default strategy is the one that applications will actually use. Be very careful +// when adjusting the default strategy because it can dramatically affect +// (often in a bad way) the user experience. +static const std::map<int32_t, VelocityTracker::Strategy> DEFAULT_STRATEGY_BY_AXIS = + {{AMOTION_EVENT_AXIS_X, VelocityTracker::Strategy::LSQ2}, + {AMOTION_EVENT_AXIS_Y, VelocityTracker::Strategy::LSQ2}, + {AMOTION_EVENT_AXIS_SCROLL, VelocityTracker::Strategy::IMPULSE}}; + +// Axes specifying location on a 2D plane (i.e. X and Y). +static const std::set<int32_t> PLANAR_AXES = {AMOTION_EVENT_AXIS_X, AMOTION_EVENT_AXIS_Y}; + +// Axes whose motion values are differential values (i.e. deltas). +static const std::set<int32_t> DIFFERENTIAL_AXES = {AMOTION_EVENT_AXIS_SCROLL}; + // Threshold for determining that a pointer has stopped moving. // Some input devices do not send ACTION_MOVE events in the case where a pointer has // stopped. We need to detect this case so that we can accurately predict the // velocity after the pointer starts moving again. -static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS; +static const std::chrono::duration ASSUME_POINTER_STOPPED_TIME = 40ms; +static std::string toString(std::chrono::nanoseconds t) { + std::stringstream stream; + stream.precision(1); + stream << std::fixed << std::chrono::duration<float, std::milli>(t).count() << " ms"; + return stream.str(); +} static float vectorDot(const float* a, const float* b, uint32_t m) { float r = 0; @@ -118,46 +142,42 @@ static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool r // --- VelocityTracker --- VelocityTracker::VelocityTracker(const Strategy strategy) - : mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) { - // Configure the strategy. - if (!configureStrategy(strategy)) { - ALOGE("Unrecognized velocity tracker strategy %" PRId32 ".", strategy); - if (!configureStrategy(VelocityTracker::DEFAULT_STRATEGY)) { - LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%" PRId32 - "'!", - strategy); - } - } -} + : mLastEventTime(0), + mCurrentPointerIdBits(0), + mActivePointerId(-1), + mOverrideStrategy(strategy) {} VelocityTracker::~VelocityTracker() { } -bool VelocityTracker::configureStrategy(Strategy strategy) { - if (strategy == VelocityTracker::Strategy::DEFAULT) { - mStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY); +void VelocityTracker::configureStrategy(int32_t axis) { + const bool isDifferentialAxis = DIFFERENTIAL_AXES.find(axis) != DIFFERENTIAL_AXES.end(); + + std::unique_ptr<VelocityTrackerStrategy> createdStrategy; + if (mOverrideStrategy != VelocityTracker::Strategy::DEFAULT) { + createdStrategy = createStrategy(mOverrideStrategy, isDifferentialAxis /* deltaValues */); } else { - mStrategy = createStrategy(strategy); + createdStrategy = createStrategy(DEFAULT_STRATEGY_BY_AXIS.at(axis), + isDifferentialAxis /* deltaValues */); } - return mStrategy != nullptr; + + LOG_ALWAYS_FATAL_IF(createdStrategy == nullptr, + "Could not create velocity tracker strategy for axis '%" PRId32 "'!", axis); + mConfiguredStrategies[axis] = std::move(createdStrategy); } std::unique_ptr<VelocityTrackerStrategy> VelocityTracker::createStrategy( - VelocityTracker::Strategy strategy) { + VelocityTracker::Strategy strategy, bool deltaValues) { switch (strategy) { case VelocityTracker::Strategy::IMPULSE: - if (DEBUG_STRATEGY) { - ALOGI("Initializing impulse strategy"); - } - return std::make_unique<ImpulseVelocityTrackerStrategy>(); + ALOGI_IF(DEBUG_STRATEGY, "Initializing impulse strategy"); + return std::make_unique<ImpulseVelocityTrackerStrategy>(deltaValues); case VelocityTracker::Strategy::LSQ1: return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1); case VelocityTracker::Strategy::LSQ2: - if (DEBUG_STRATEGY && !DEBUG_IMPULSE) { - ALOGI("Initializing lsq2 strategy"); - } + ALOGI_IF(DEBUG_STRATEGY && !DEBUG_IMPULSE, "Initializing lsq2 strategy"); return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2); case VelocityTracker::Strategy::LSQ3: @@ -197,8 +217,7 @@ std::unique_ptr<VelocityTrackerStrategy> VelocityTracker::createStrategy( void VelocityTracker::clear() { mCurrentPointerIdBits.clear(); mActivePointerId = -1; - - mStrategy->clear(); + mConfiguredStrategies.clear(); } void VelocityTracker::clearPointers(BitSet32 idBits) { @@ -209,27 +228,25 @@ void VelocityTracker::clearPointers(BitSet32 idBits) { mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1; } - mStrategy->clearPointers(idBits); + for (const auto& [_, strategy] : mConfiguredStrategies) { + strategy->clearPointers(idBits); + } } void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) { - LOG_ALWAYS_FATAL_IF(idBits.count() != positions.size(), - "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu", - idBits.count(), positions.size()); + const std::map<int32_t /*axis*/, std::vector<float>>& positions) { while (idBits.count() > MAX_POINTERS) { idBits.clearLastMarkedBit(); } - if ((mCurrentPointerIdBits.value & idBits.value) - && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) { - if (DEBUG_VELOCITY) { - ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.", - (eventTime - mLastEventTime) * 0.000001f); - } + if ((mCurrentPointerIdBits.value & idBits.value) && + std::chrono::nanoseconds(eventTime - mLastEventTime) > ASSUME_POINTER_STOPPED_TIME) { + ALOGD_IF(DEBUG_VELOCITY, "VelocityTracker: stopped for %s, clearing state.", + toString(std::chrono::nanoseconds(eventTime - mLastEventTime)).c_str()); + // We have not received any movements for too long. Assume that all pointers // have stopped. - mStrategy->clear(); + mConfiguredStrategies.clear(); } mLastEventTime = eventTime; @@ -238,29 +255,40 @@ void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit(); } - mStrategy->addMovement(eventTime, idBits, positions); + for (const auto& [axis, positionValues] : positions) { + LOG_ALWAYS_FATAL_IF(idBits.count() != positionValues.size(), + "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu", + idBits.count(), positionValues.size()); + if (mConfiguredStrategies.find(axis) == mConfiguredStrategies.end()) { + configureStrategy(axis); + } + mConfiguredStrategies[axis]->addMovement(eventTime, idBits, positionValues); + } if (DEBUG_VELOCITY) { ALOGD("VelocityTracker: addMovement eventTime=%" PRId64 ", idBits=0x%08x, activePointerId=%d", eventTime, idBits.value, mActivePointerId); - for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) { - uint32_t id = iterBits.firstMarkedBit(); - uint32_t index = idBits.getIndexOfBit(id); - iterBits.clearBit(id); - Estimator estimator; - getEstimator(id, &estimator); - ALOGD(" %d: position (%0.3f, %0.3f), " - "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)", - id, positions[index].x, positions[index].y, int(estimator.degree), - vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(), - vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(), - estimator.confidence); + for (const auto& positionsEntry : positions) { + for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) { + uint32_t id = iterBits.firstMarkedBit(); + uint32_t index = idBits.getIndexOfBit(id); + iterBits.clearBit(id); + Estimator estimator; + getEstimator(positionsEntry.first, id, &estimator); + ALOGD(" %d: axis=%d, position=%0.3f, " + "estimator (degree=%d, coeff=%s, confidence=%f)", + id, positionsEntry.first, positionsEntry.second[index], int(estimator.degree), + vectorToString(estimator.coeff, estimator.degree + 1).c_str(), + estimator.confidence); + } } } } void VelocityTracker::addMovement(const MotionEvent* event) { + // Stores data about which axes to process based on the incoming motion event. + std::set<int32_t> axesToProcess; int32_t actionMasked = event->getActionMasked(); switch (actionMasked) { @@ -268,6 +296,7 @@ void VelocityTracker::addMovement(const MotionEvent* event) { case AMOTION_EVENT_ACTION_HOVER_ENTER: // Clear all pointers on down before adding the new movement. clear(); + axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end()); break; case AMOTION_EVENT_ACTION_POINTER_DOWN: { // Start a new movement trace for a pointer that just went down. @@ -276,13 +305,27 @@ void VelocityTracker::addMovement(const MotionEvent* event) { BitSet32 downIdBits; downIdBits.markBit(event->getPointerId(event->getActionIndex())); clearPointers(downIdBits); + axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end()); break; } case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_HOVER_MOVE: + axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end()); break; - default: - // Ignore all other actions because they do not convey any new information about + case AMOTION_EVENT_ACTION_POINTER_UP: + case AMOTION_EVENT_ACTION_UP: { + std::chrono::nanoseconds delaySinceLastEvent(event->getEventTime() - mLastEventTime); + if (delaySinceLastEvent > ASSUME_POINTER_STOPPED_TIME) { + ALOGD_IF(DEBUG_VELOCITY, + "VelocityTracker: stopped for %s, clearing state upon pointer liftoff.", + toString(delaySinceLastEvent).c_str()); + // We have not received any movements for too long. Assume that all pointers + // have stopped. + for (int32_t axis : PLANAR_AXES) { + mConfiguredStrategies.erase(axis); + } + } + // These actions because they do not convey any new information about // pointer movement. We also want to preserve the last known velocity of the pointers. // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position // of the pointers that went up. ACTION_POINTER_UP does include the new position of @@ -292,6 +335,13 @@ void VelocityTracker::addMovement(const MotionEvent* event) { // before adding the movement. return; } + case AMOTION_EVENT_ACTION_SCROLL: + axesToProcess.insert(AMOTION_EVENT_AXIS_SCROLL); + break; + default: + // Ignore all other actions. + return; + } size_t pointerCount = event->getPointerCount(); if (pointerCount > MAX_POINTERS) { @@ -308,62 +358,74 @@ void VelocityTracker::addMovement(const MotionEvent* event) { pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i)); } - std::vector<Position> positions; - positions.resize(pointerCount); + std::map<int32_t, std::vector<float>> positions; + for (int32_t axis : axesToProcess) { + positions[axis].resize(pointerCount); + } size_t historySize = event->getHistorySize(); for (size_t h = 0; h <= historySize; h++) { nsecs_t eventTime = event->getHistoricalEventTime(h); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t index = pointerIndex[i]; - positions[index].x = event->getHistoricalX(i, h); - positions[index].y = event->getHistoricalY(i, h); + for (int32_t axis : axesToProcess) { + for (size_t i = 0; i < pointerCount; i++) { + positions[axis][pointerIndex[i]] = event->getHistoricalAxisValue(axis, i, h); + } } addMovement(eventTime, idBits, positions); } } -bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const { +std::optional<float> VelocityTracker::getVelocity(int32_t axis, uint32_t id) const { Estimator estimator; - if (getEstimator(id, &estimator) && estimator.degree >= 1) { - *outVx = estimator.xCoeff[1]; - *outVy = estimator.yCoeff[1]; - return true; + bool validVelocity = getEstimator(axis, id, &estimator) && estimator.degree >= 1; + if (validVelocity) { + return estimator.coeff[1]; } - *outVx = 0; - *outVy = 0; - return false; + return {}; } -bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { - return mStrategy->getEstimator(id, outEstimator); +VelocityTracker::ComputedVelocity VelocityTracker::getComputedVelocity(int32_t units, + float maxVelocity) { + ComputedVelocity computedVelocity; + for (const auto& [axis, _] : mConfiguredStrategies) { + BitSet32 copyIdBits = BitSet32(mCurrentPointerIdBits); + while (!copyIdBits.isEmpty()) { + uint32_t id = copyIdBits.clearFirstMarkedBit(); + std::optional<float> velocity = getVelocity(axis, id); + if (velocity) { + float adjustedVelocity = + std::clamp(*velocity * units / 1000, -maxVelocity, maxVelocity); + computedVelocity.addVelocity(axis, id, adjustedVelocity); + } + } + } + return computedVelocity; } +bool VelocityTracker::getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const { + const auto& it = mConfiguredStrategies.find(axis); + if (it == mConfiguredStrategies.end()) { + return false; + } + return it->second->getEstimator(id, outEstimator); +} // --- LeastSquaresVelocityTrackerStrategy --- -LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( - uint32_t degree, Weighting weighting) : - mDegree(degree), mWeighting(weighting) { - clear(); -} +LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree, + Weighting weighting) + : mDegree(degree), mWeighting(weighting), mIndex(0) {} LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() { } -void LeastSquaresVelocityTrackerStrategy::clear() { - mIndex = 0; - mMovements[0].idBits.clear(); -} - void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); mMovements[mIndex].idBits = remainingIdBits; } -void LeastSquaresVelocityTrackerStrategy::addMovement( - nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) { +void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, + const std::vector<float>& positions) { if (mMovements[mIndex].eventTime != eventTime) { // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include @@ -438,10 +500,10 @@ void LeastSquaresVelocityTrackerStrategy::addMovement( static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y, const std::vector<float>& w, uint32_t n, float* outB, float* outDet) { const size_t m = x.size(); - if (DEBUG_STRATEGY) { - ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), - vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str()); - } + + ALOGD_IF(DEBUG_STRATEGY, "solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), + vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str()); + LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes"); // Expand the X vector to a matrix A, pre-multiplied by the weights. @@ -452,9 +514,9 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo a[i][h] = a[i - 1][h] * x[h]; } } - if (DEBUG_STRATEGY) { - ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str()); - } + + ALOGD_IF(DEBUG_STRATEGY, " - a=%s", + matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str()); // Apply the Gram-Schmidt process to A to obtain its QR decomposition. float q[n][m]; // orthonormal basis, column-major order @@ -473,9 +535,7 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo float norm = vectorNorm(&q[j][0], m); if (norm < 0.000001f) { // vectors are linearly dependent or zero so no solution - if (DEBUG_STRATEGY) { - ALOGD(" - no solution, norm=%f", norm); - } + ALOGD_IF(DEBUG_STRATEGY, " - no solution, norm=%f", norm); return false; } @@ -518,9 +578,8 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo } outB[i] /= r[i][i]; } - if (DEBUG_STRATEGY) { - ALOGD(" - b=%s", vectorToString(outB, n).c_str()); - } + + ALOGD_IF(DEBUG_STRATEGY, " - b=%s", vectorToString(outB, n).c_str()); // Calculate the coefficient of determination as 1 - (SSerr / SStot) where // SSerr is the residual sum of squares (variance of the error), @@ -546,11 +605,11 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo sstot += w[h] * w[h] * var * var; } *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; - if (DEBUG_STRATEGY) { - ALOGD(" - sserr=%f", sserr); - ALOGD(" - sstot=%f", sstot); - ALOGD(" - det=%f", *outDet); - } + + ALOGD_IF(DEBUG_STRATEGY, " - sserr=%f", sserr); + ALOGD_IF(DEBUG_STRATEGY, " - sstot=%f", sstot); + ALOGD_IF(DEBUG_STRATEGY, " - det=%f", *outDet); + return true; } @@ -613,8 +672,7 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, outEstimator->clear(); // Iterate over movement samples in reverse time order and collect samples. - std::vector<float> x; - std::vector<float> y; + std::vector<float> positions; std::vector<float> w; std::vector<float> time; @@ -631,15 +689,13 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, break; } - const VelocityTracker::Position& position = movement.getPosition(id); - x.push_back(position.x); - y.push_back(position.y); + positions.push_back(movement.getPosition(id)); w.push_back(chooseWeight(index)); time.push_back(-age * 0.000000001f); index = (index == 0 ? HISTORY_SIZE : index) - 1; - } while (x.size() < HISTORY_SIZE); + } while (positions.size() < HISTORY_SIZE); - const size_t m = x.size(); + const size_t m = positions.size(); if (m == 0) { return false; // no data } @@ -652,39 +708,36 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, if (degree == 2 && mWeighting == WEIGHTING_NONE) { // Optimize unweighted, quadratic polynomial fit - std::optional<std::array<float, 3>> xCoeff = solveUnweightedLeastSquaresDeg2(time, x); - std::optional<std::array<float, 3>> yCoeff = solveUnweightedLeastSquaresDeg2(time, y); - if (xCoeff && yCoeff) { + std::optional<std::array<float, 3>> coeff = + solveUnweightedLeastSquaresDeg2(time, positions); + if (coeff) { outEstimator->time = newestMovement.eventTime; outEstimator->degree = 2; outEstimator->confidence = 1; for (size_t i = 0; i <= outEstimator->degree; i++) { - outEstimator->xCoeff[i] = (*xCoeff)[i]; - outEstimator->yCoeff[i] = (*yCoeff)[i]; + outEstimator->coeff[i] = (*coeff)[i]; } return true; } } else if (degree >= 1) { // General case for an Nth degree polynomial fit - float xdet, ydet; + float det; uint32_t n = degree + 1; - if (solveLeastSquares(time, x, w, n, outEstimator->xCoeff, &xdet) && - solveLeastSquares(time, y, w, n, outEstimator->yCoeff, &ydet)) { + if (solveLeastSquares(time, positions, w, n, outEstimator->coeff, &det)) { outEstimator->time = newestMovement.eventTime; outEstimator->degree = degree; - outEstimator->confidence = xdet * ydet; - if (DEBUG_STRATEGY) { - ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", - int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(), - vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence); - } + outEstimator->confidence = det; + + ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, coeff=%s, confidence=%f", + int(outEstimator->degree), vectorToString(outEstimator->coeff, n).c_str(), + outEstimator->confidence); + return true; } } // No velocity data available for this pointer, but we do have its current position. - outEstimator->xCoeff[0] = x[0]; - outEstimator->yCoeff[0] = y[0]; + outEstimator->coeff[0] = positions[0]; outEstimator->time = newestMovement.eventTime; outEstimator->degree = 0; outEstimator->confidence = 1; @@ -768,26 +821,21 @@ IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() { } -void IntegratingVelocityTrackerStrategy::clear() { - mPointerIdBits.clear(); -} - void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { mPointerIdBits.value &= ~idBits.value; } -void IntegratingVelocityTrackerStrategy::addMovement( - nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) { +void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, + const std::vector<float>& positions) { uint32_t index = 0; for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) { uint32_t id = iterIdBits.clearFirstMarkedBit(); State& state = mPointerState[id]; - const VelocityTracker::Position& position = positions[index++]; + const float position = positions[index++]; if (mPointerIdBits.hasBit(id)) { - updateState(state, eventTime, position.x, position.y); + updateState(state, eventTime, position); } else { - initState(state, eventTime, position.x, position.y); + initState(state, eventTime, position); } } @@ -807,21 +855,18 @@ bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id, return false; } -void IntegratingVelocityTrackerStrategy::initState(State& state, - nsecs_t eventTime, float xpos, float ypos) const { +void IntegratingVelocityTrackerStrategy::initState(State& state, nsecs_t eventTime, + float pos) const { state.updateTime = eventTime; state.degree = 0; - state.xpos = xpos; - state.xvel = 0; - state.xaccel = 0; - state.ypos = ypos; - state.yvel = 0; - state.yaccel = 0; + state.pos = pos; + state.accel = 0; + state.vel = 0; } -void IntegratingVelocityTrackerStrategy::updateState(State& state, - nsecs_t eventTime, float xpos, float ypos) const { +void IntegratingVelocityTrackerStrategy::updateState(State& state, nsecs_t eventTime, + float pos) const { const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS; const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds @@ -832,34 +877,26 @@ void IntegratingVelocityTrackerStrategy::updateState(State& state, float dt = (eventTime - state.updateTime) * 0.000000001f; state.updateTime = eventTime; - float xvel = (xpos - state.xpos) / dt; - float yvel = (ypos - state.ypos) / dt; + float vel = (pos - state.pos) / dt; if (state.degree == 0) { - state.xvel = xvel; - state.yvel = yvel; + state.vel = vel; state.degree = 1; } else { float alpha = dt / (FILTER_TIME_CONSTANT + dt); if (mDegree == 1) { - state.xvel += (xvel - state.xvel) * alpha; - state.yvel += (yvel - state.yvel) * alpha; + state.vel += (vel - state.vel) * alpha; } else { - float xaccel = (xvel - state.xvel) / dt; - float yaccel = (yvel - state.yvel) / dt; + float accel = (vel - state.vel) / dt; if (state.degree == 1) { - state.xaccel = xaccel; - state.yaccel = yaccel; + state.accel = accel; state.degree = 2; } else { - state.xaccel += (xaccel - state.xaccel) * alpha; - state.yaccel += (yaccel - state.yaccel) * alpha; + state.accel += (accel - state.accel) * alpha; } - state.xvel += (state.xaccel * dt) * alpha; - state.yvel += (state.yaccel * dt) * alpha; + state.vel += (state.accel * dt) * alpha; } } - state.xpos = xpos; - state.ypos = ypos; + state.pos = pos; } void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, @@ -867,37 +904,26 @@ void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, outEstimator->time = state.updateTime; outEstimator->confidence = 1.0f; outEstimator->degree = state.degree; - outEstimator->xCoeff[0] = state.xpos; - outEstimator->xCoeff[1] = state.xvel; - outEstimator->xCoeff[2] = state.xaccel / 2; - outEstimator->yCoeff[0] = state.ypos; - outEstimator->yCoeff[1] = state.yvel; - outEstimator->yCoeff[2] = state.yaccel / 2; + outEstimator->coeff[0] = state.pos; + outEstimator->coeff[1] = state.vel; + outEstimator->coeff[2] = state.accel / 2; } // --- LegacyVelocityTrackerStrategy --- -LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { - clear(); -} +LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() : mIndex(0) {} LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { } -void LegacyVelocityTrackerStrategy::clear() { - mIndex = 0; - mMovements[0].idBits.clear(); -} - void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); mMovements[mIndex].idBits = remainingIdBits; } -void LegacyVelocityTrackerStrategy::addMovement( - nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) { +void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, + const std::vector<float>& positions) { if (++mIndex == HISTORY_SIZE) { mIndex = 0; } @@ -945,12 +971,11 @@ bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, // overestimate the velocity at that time point. Most samples might be measured // 16ms apart but some consecutive samples could be only 0.5sm apart because // the hardware or driver reports them irregularly or in bursts. - float accumVx = 0; - float accumVy = 0; + float accumV = 0; uint32_t index = oldestIndex; uint32_t samplesUsed = 0; const Movement& oldestMovement = mMovements[oldestIndex]; - const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id); + float oldestPosition = oldestMovement.getPosition(id); nsecs_t lastDuration = 0; while (numTouches-- > 1) { @@ -964,26 +989,22 @@ bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, // the velocity. Consequently, we impose a minimum duration constraint on the // samples that we include in the calculation. if (duration >= MIN_DURATION) { - const VelocityTracker::Position& position = movement.getPosition(id); + float position = movement.getPosition(id); float scale = 1000000000.0f / duration; // one over time delta in seconds - float vx = (position.x - oldestPosition.x) * scale; - float vy = (position.y - oldestPosition.y) * scale; - accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration); - accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration); + float v = (position - oldestPosition) * scale; + accumV = (accumV * lastDuration + v * duration) / (duration + lastDuration); lastDuration = duration; samplesUsed += 1; } } // Report velocity. - const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id); + float newestPosition = newestMovement.getPosition(id); outEstimator->time = newestMovement.eventTime; outEstimator->confidence = 1; - outEstimator->xCoeff[0] = newestPosition.x; - outEstimator->yCoeff[0] = newestPosition.y; + outEstimator->coeff[0] = newestPosition; if (samplesUsed) { - outEstimator->xCoeff[1] = accumVx; - outEstimator->yCoeff[1] = accumVy; + outEstimator->coeff[1] = accumV; outEstimator->degree = 1; } else { outEstimator->degree = 0; @@ -993,26 +1014,19 @@ bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, // --- ImpulseVelocityTrackerStrategy --- -ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() { - clear(); -} +ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy(bool deltaValues) + : mDeltaValues(deltaValues), mIndex(0) {} ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() { } -void ImpulseVelocityTrackerStrategy::clear() { - mIndex = 0; - mMovements[0].idBits.clear(); -} - void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); mMovements[mIndex].idBits = remainingIdBits; } -void ImpulseVelocityTrackerStrategy::addMovement( - nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) { +void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, + const std::vector<float>& positions) { if (mMovements[mIndex].eventTime != eventTime) { // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include @@ -1109,7 +1123,8 @@ static float kineticEnergyToVelocity(float work) { return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2; } -static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) { +static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count, + bool deltaValues) { // The input should be in reversed time order (most recent sample at index i=0) // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function static constexpr float SECONDS_PER_NANO = 1E-9; @@ -1120,12 +1135,26 @@ static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t c if (t[1] > t[0]) { // Algorithm will still work, but not perfectly ALOGE("Samples provided to calculateImpulseVelocity in the wrong order"); } + + // If the data values are delta values, we do not have to calculate deltas here. + // We can use the delta values directly, along with the calculated time deltas. + // Since the data value input is in reversed time order: + // [a] for non-delta inputs, instantenous velocity = (x[i] - x[i-1])/(t[i] - t[i-1]) + // [b] for delta inputs, instantenous velocity = -x[i-1]/(t[i] - t[i - 1]) + // e.g., let the non-delta values are: V = [2, 3, 7], the equivalent deltas are D = [2, 1, 4]. + // Since the input is in reversed time order, the input values for this function would be + // V'=[7, 3, 2] and D'=[4, 1, 2] for the non-delta and delta values, respectively. + // + // The equivalent of {(V'[2] - V'[1]) = 2 - 3 = -1} would be {-D'[1] = -1} + // Similarly, the equivalent of {(V'[1] - V'[0]) = 3 - 7 = -4} would be {-D'[0] = -4} + if (count == 2) { // if 2 points, basic linear calculation if (t[1] == t[0]) { ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]); return 0; } - return (x[1] - x[0]) / (SECONDS_PER_NANO * (t[1] - t[0])); + const float deltaX = deltaValues ? -x[0] : x[1] - x[0]; + return deltaX / (SECONDS_PER_NANO * (t[1] - t[0])); } // Guaranteed to have at least 3 points here float work = 0; @@ -1135,7 +1164,8 @@ static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t c continue; } float vprev = kineticEnergyToVelocity(work); // v[i-1] - float vcurr = (x[i] - x[i-1]) / (SECONDS_PER_NANO * (t[i] - t[i-1])); // v[i] + const float deltaX = deltaValues ? -x[i-1] : x[i] - x[i-1]; + float vcurr = deltaX / (SECONDS_PER_NANO * (t[i] - t[i-1])); // v[i] work += (vcurr - vprev) * fabsf(vcurr); if (i == count - 1) { work *= 0.5; // initial condition, case 2) above @@ -1149,8 +1179,7 @@ bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id, outEstimator->clear(); // Iterate over movement samples in reverse time order and collect samples. - float x[HISTORY_SIZE]; - float y[HISTORY_SIZE]; + float positions[HISTORY_SIZE]; nsecs_t time[HISTORY_SIZE]; size_t m = 0; // number of points that will be used for fitting size_t index = mIndex; @@ -1166,9 +1195,7 @@ bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id, break; } - const VelocityTracker::Position& position = movement.getPosition(id); - x[m] = position.x; - y[m] = position.y; + positions[m] = movement.getPosition(id); time[m] = movement.eventTime; index = (index == 0 ? HISTORY_SIZE : index) - 1; } while (++m < HISTORY_SIZE); @@ -1176,32 +1203,30 @@ bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id, if (m == 0) { return false; // no data } - outEstimator->xCoeff[0] = 0; - outEstimator->yCoeff[0] = 0; - outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m); - outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m); - outEstimator->xCoeff[2] = 0; - outEstimator->yCoeff[2] = 0; + outEstimator->coeff[0] = 0; + outEstimator->coeff[1] = calculateImpulseVelocity(time, positions, m, mDeltaValues); + outEstimator->coeff[2] = 0; + outEstimator->time = newestMovement.eventTime; outEstimator->degree = 2; // similar results to 2nd degree fit outEstimator->confidence = 1; - if (DEBUG_STRATEGY) { - ALOGD("velocity: (%.1f, %.1f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]); - } + + ALOGD_IF(DEBUG_STRATEGY, "velocity: %.1f", outEstimator->coeff[1]); + if (DEBUG_IMPULSE) { // TODO(b/134179997): delete this block once the switch to 'impulse' is complete. - // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons + // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons. + // X axis chosen arbitrarily for velocity comparisons. VelocityTracker lsq2(VelocityTracker::Strategy::LSQ2); BitSet32 idBits; const uint32_t pointerId = 0; idBits.markBit(pointerId); for (ssize_t i = m - 1; i >= 0; i--) { - lsq2.addMovement(time[i], idBits, {{x[i], y[i]}}); + lsq2.addMovement(time[i], idBits, {{AMOTION_EVENT_AXIS_X, {positions[i]}}}); } - float outVx = 0, outVy = 0; - const bool computed = lsq2.getVelocity(pointerId, &outVx, &outVy); - if (computed) { - ALOGD("lsq2 velocity: (%.1f, %.1f)", outVx, outVy); + std::optional<float> v = lsq2.getVelocity(AMOTION_EVENT_AXIS_X, pointerId); + if (v) { + ALOGD("lsq2 velocity: %.1f", *v); } else { ALOGD("lsq2 velocity: could not compute velocity"); } diff --git a/libs/input/android/hardware/input/InputDeviceCountryCode.aidl b/libs/input/android/hardware/input/InputDeviceCountryCode.aidl new file mode 100644 index 0000000000..6bb1a60dda --- /dev/null +++ b/libs/input/android/hardware/input/InputDeviceCountryCode.aidl @@ -0,0 +1,212 @@ +/* + * 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. + */ + +package android.hardware.input; + +/** + * Constant for HID country code declared by a HID device. These constants are declared as AIDL to + * be used by java and native input code. + * + * @hide + */ +@Backing(type="int") +enum InputDeviceCountryCode { + /** + * Used as default value where country code is not set in the device HID descriptor + */ + INVALID = -1, + + /** + * Used as default value when country code is not supported by the HID device. The HID + * descriptor sets "00" as the country code in this case. + */ + NOT_SUPPORTED = 0, + + /** + * Arabic + */ + ARABIC = 1, + + /** + * Belgian + */ + BELGIAN = 2, + + /** + * Canadian (Bilingual) + */ + CANADIAN_BILINGUAL = 3, + + /** + * Canadian (French) + */ + CANADIAN_FRENCH = 4, + + /** + * Czech Republic + */ + CZECH_REPUBLIC = 5, + + /** + * Danish + */ + DANISH = 6, + + /** + * Finnish + */ + FINNISH = 7, + + /** + * French + */ + FRENCH = 8, + + /** + * German + */ + GERMAN = 9, + + /** + * Greek + */ + GREEK = 10, + + /** + * Hebrew + */ + HEBREW = 11, + + /** + * Hungary + */ + HUNGARY = 12, + + /** + * International (ISO) + */ + INTERNATIONAL = 13, + + /** + * Italian + */ + ITALIAN = 14, + + /** + * Japan (Katakana) + */ + JAPAN = 15, + + /** + * Korean + */ + KOREAN = 16, + + /** + * Latin American + */ + LATIN_AMERICAN = 17, + + /** + * Netherlands (Dutch) + */ + DUTCH = 18, + + /** + * Norwegian + */ + NORWEGIAN = 19, + + /** + * Persian + */ + PERSIAN = 20, + + /** + * Poland + */ + POLAND = 21, + + /** + * Portuguese + */ + PORTUGUESE = 22, + + /** + * Russia + */ + RUSSIA = 23, + + /** + * Slovakia + */ + SLOVAKIA = 24, + + /** + * Spanish + */ + SPANISH = 25, + + /** + * Swedish + */ + SWEDISH = 26, + + /** + * Swiss (French) + */ + SWISS_FRENCH = 27, + + /** + * Swiss (German) + */ + SWISS_GERMAN = 28, + + /** + * Switzerland + */ + SWITZERLAND = 29, + + /** + * Taiwan + */ + TAIWAN = 30, + + /** + * Turkish_Q + */ + TURKISH_Q = 31, + + /** + * UK + */ + UK = 32, + + /** + * US + */ + US = 33, + + /** + * Yugoslavia + */ + YUGOSLAVIA = 34, + + /** + * Turkish_F + */ + TURKISH_F = 35, +}
\ No newline at end of file diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl index 6d1b3967f7..4e644fff06 100644 --- a/libs/input/android/os/InputConfig.aidl +++ b/libs/input/android/os/InputConfig.aidl @@ -144,4 +144,10 @@ enum InputConfig { * It is not valid to set this configuration if {@link #TRUSTED_OVERLAY} is not set. */ INTERCEPTS_STYLUS = 1 << 15, + + /** + * The window is a clone of another window. This may be treated differently since there's + * likely a duplicate window with the same client token, but different bounds. + */ + CLONE = 1 << 16, } diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index d947cd99e8..c53811a92d 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -16,6 +16,7 @@ cc_test { "InputDevice_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", + "TouchResampling_test.cpp", "TouchVideoFrame_test.cpp", "VelocityTracker_test.cpp", "VerifiedInputEvent_test.cpp", diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 05bc0bcbe8..70e4fda662 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -16,17 +16,10 @@ #include "TestHelpers.h" -#include <unistd.h> -#include <sys/mman.h> -#include <time.h> - #include <attestation/HmacKeyManager.h> -#include <cutils/ashmem.h> #include <gtest/gtest.h> #include <gui/constants.h> #include <input/InputTransport.h> -#include <utils/StopWatch.h> -#include <utils/Timers.h> using android::base::Result; diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp new file mode 100644 index 0000000000..c09a8e9358 --- /dev/null +++ b/libs/input/tests/TouchResampling_test.cpp @@ -0,0 +1,562 @@ +/* + * 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 "TestHelpers.h" + +#include <chrono> +#include <vector> + +#include <attestation/HmacKeyManager.h> +#include <gtest/gtest.h> +#include <input/InputTransport.h> + +using namespace std::chrono_literals; + +namespace android { + +struct Pointer { + int32_t id; + float x; + float y; +}; + +struct InputEventEntry { + std::chrono::nanoseconds eventTime; + std::vector<Pointer> pointers; + int32_t action; +}; + +class TouchResamplingTest : public testing::Test { +protected: + std::unique_ptr<InputPublisher> mPublisher; + std::unique_ptr<InputConsumer> mConsumer; + PreallocatedInputEventFactory mEventFactory; + + uint32_t mSeq = 1; + + void SetUp() override { + std::unique_ptr<InputChannel> serverChannel, clientChannel; + status_t result = + InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); + ASSERT_EQ(OK, result); + + mPublisher = std::make_unique<InputPublisher>(std::move(serverChannel)); + mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel), + true /* enableTouchResampling */); + } + + status_t publishSimpleMotionEventWithCoords(int32_t action, nsecs_t eventTime, + const std::vector<PointerProperties>& properties, + const std::vector<PointerCoords>& coords); + void publishSimpleMotionEvent(int32_t action, nsecs_t eventTime, + const std::vector<Pointer>& pointers); + void publishInputEventEntries(const std::vector<InputEventEntry>& entries); + void consumeInputEventEntries(const std::vector<InputEventEntry>& entries, + std::chrono::nanoseconds frameTime); + void receiveResponseUntilSequence(uint32_t seq); +}; + +status_t TouchResamplingTest::publishSimpleMotionEventWithCoords( + int32_t action, nsecs_t eventTime, const std::vector<PointerProperties>& properties, + const std::vector<PointerCoords>& coords) { + const ui::Transform identityTransform; + const nsecs_t downTime = 0; + + if (action == AMOTION_EVENT_ACTION_DOWN && eventTime != 0) { + ADD_FAILURE() << "Downtime should be equal to 0 (hardcoded for convenience)"; + } + return mPublisher->publishMotionEvent(mSeq++, InputEvent::nextId(), 1 /*deviceId*/, + AINPUT_SOURCE_TOUCHSCREEN, 0 /*displayId*/, INVALID_HMAC, + action, 0 /*actionButton*/, 0 /*flags*/, 0 /*edgeFlags*/, + AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, + identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, + downTime, eventTime, properties.size(), properties.data(), + coords.data()); +} + +void TouchResamplingTest::publishSimpleMotionEvent(int32_t action, nsecs_t eventTime, + const std::vector<Pointer>& pointers) { + std::vector<PointerProperties> properties; + std::vector<PointerCoords> coords; + + for (const Pointer& pointer : pointers) { + properties.push_back({}); + properties.back().clear(); + properties.back().id = pointer.id; + properties.back().toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + coords.push_back({}); + coords.back().clear(); + coords.back().setAxisValue(AMOTION_EVENT_AXIS_X, pointer.x); + coords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, pointer.y); + } + + status_t result = publishSimpleMotionEventWithCoords(action, eventTime, properties, coords); + ASSERT_EQ(OK, result); +} + +/** + * Each entry is published separately, one entry at a time. As a result, action is used here + * on a per-entry basis. + */ +void TouchResamplingTest::publishInputEventEntries(const std::vector<InputEventEntry>& entries) { + for (const InputEventEntry& entry : entries) { + publishSimpleMotionEvent(entry.action, entry.eventTime.count(), entry.pointers); + } +} + +/** + * Inside the publisher, read responses repeatedly until the desired sequence number is returned. + * + * Sometimes, when you call 'sendFinishedSignal', you would be finishing a batch which is comprised + * of several input events. As a result, consumer will generate multiple 'finish' signals on your + * behalf. + * + * In this function, we call 'receiveConsumerResponse' in a loop until the desired sequence number + * is returned. + */ +void TouchResamplingTest::receiveResponseUntilSequence(uint32_t seq) { + size_t consumedEvents = 0; + while (consumedEvents < 100) { + android::base::Result<InputPublisher::ConsumerResponse> response = + mPublisher->receiveConsumerResponse(); + ASSERT_TRUE(response.ok()); + ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*response)); + const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*response); + ASSERT_TRUE(finish.handled) + << "publisher receiveFinishedSignal should have set handled to consumer's reply"; + if (finish.seq == seq) { + return; + } + consumedEvents++; + } + FAIL() << "Got " << consumedEvents << "events, but still no event with seq=" << seq; +} + +/** + * All entries are compared against a single MotionEvent, but the same data structure + * InputEventEntry is used here for simpler code. As a result, the entire array of InputEventEntry + * must contain identical values for the action field. + */ +void TouchResamplingTest::consumeInputEventEntries(const std::vector<InputEventEntry>& entries, + std::chrono::nanoseconds frameTime) { + ASSERT_GE(entries.size(), 1U) << "Must have at least 1 InputEventEntry to compare against"; + + uint32_t consumeSeq; + InputEvent* event; + + status_t status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, frameTime.count(), + &consumeSeq, &event); + ASSERT_EQ(OK, status); + MotionEvent* motionEvent = static_cast<MotionEvent*>(event); + + ASSERT_EQ(entries.size() - 1, motionEvent->getHistorySize()); + for (size_t i = 0; i < entries.size(); i++) { // most recent sample is last + SCOPED_TRACE(i); + const InputEventEntry& entry = entries[i]; + ASSERT_EQ(entry.action, motionEvent->getAction()); + ASSERT_EQ(entry.eventTime.count(), motionEvent->getHistoricalEventTime(i)); + ASSERT_EQ(entry.pointers.size(), motionEvent->getPointerCount()); + + for (size_t p = 0; p < motionEvent->getPointerCount(); p++) { + SCOPED_TRACE(p); + // The pointers can be in any order, both in MotionEvent as well as InputEventEntry + ssize_t motionEventPointerIndex = motionEvent->findPointerIndex(entry.pointers[p].id); + ASSERT_GE(motionEventPointerIndex, 0) << "Pointer must be present in MotionEvent"; + ASSERT_EQ(entry.pointers[p].x, + motionEvent->getHistoricalAxisValue(AMOTION_EVENT_AXIS_X, + motionEventPointerIndex, i)); + ASSERT_EQ(entry.pointers[p].x, + motionEvent->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_X, + motionEventPointerIndex, i)); + ASSERT_EQ(entry.pointers[p].y, + motionEvent->getHistoricalAxisValue(AMOTION_EVENT_AXIS_Y, + motionEventPointerIndex, i)); + ASSERT_EQ(entry.pointers[p].y, + motionEvent->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, + motionEventPointerIndex, i)); + } + } + + status = mConsumer->sendFinishedSignal(consumeSeq, true); + ASSERT_EQ(OK, status); + + receiveResponseUntilSequence(consumeSeq); +} + +/** + * Timeline + * ---------+------------------+------------------+--------+-----------------+---------------------- + * 0 ms 10 ms 20 ms 25 ms 35 ms + * ACTION_DOWN ACTION_MOVE ACTION_MOVE ^ ^ + * | | + * resampled value | + * frameTime + * Typically, the prediction is made for time frameTime - RESAMPLE_LATENCY, or 30 ms in this case + * However, that would be 10 ms later than the last real sample (which came in at 20 ms). + * Therefore, the resampling should happen at 20 ms + RESAMPLE_MAX_PREDICTION = 28 ms. + * In this situation, though, resample time is further limited by taking half of the difference + * between the last two real events, which would put this time at: + * 20 ms + (20 ms - 10 ms) / 2 = 25 ms. + */ +TEST_F(TouchResamplingTest, EventIsResampled) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +/** + * Same as above test, but use pointer id=1 instead of 0 to make sure that system does not + * have these hardcoded. + */ +TEST_F(TouchResamplingTest, EventIsResampledWithDifferentId) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{1, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{1, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{1, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{1, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{1, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{1, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {25ms, {{1, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +/** + * Event should not be resampled when sample time is equal to event time. + */ +TEST_F(TouchResamplingTest, SampleTimeEqualsEventTime) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 20ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + // no resampled event because the time of resample falls exactly on the existing event + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +/** + * Once we send a resampled value to the app, we should continue to "lie" if the pointer + * does not move. So, if the pointer keeps the same coordinates, resampled value should continue + * to be used. + */ +TEST_F(TouchResamplingTest, ResampledValueIsUsedForIdenticalCoordinates) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Coordinate value 30 has been resampled to 35. When a new event comes in with value 30 again, + // the system should still report 35. + entries = { + // id x y + {40ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 45ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {40ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten + {45ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled event, rewritten + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +TEST_F(TouchResamplingTest, OldEventReceivedAfterResampleOccurs) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); + // Above, the resampled event is at 25ms rather than at 30 ms = 35ms - RESAMPLE_LATENCY + // because we are further bound by how far we can extrapolate by the "last time delta". + // That's 50% of (20 ms - 10ms) => 5ms. So we can't predict more than 5 ms into the future + // from the event at 20ms, which is why the resampled event is at t = 25 ms. + + // We resampled the event to 25 ms. Now, an older 'real' event comes in. + entries = { + // id x y + {24ms, {{0, 40, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 50ms; + expectedEntries = { + // id x y + {24ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten + {26ms, {{0, 45, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled event, rewritten + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +TEST_F(TouchResamplingTest, TwoPointersAreResampledIndependently) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // full action for when a pointer with id=1 appears (some other pointer must already be present) + constexpr int32_t actionPointer1Down = + AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + + // full action for when a pointer with id=0 disappears (some other pointer must still remain) + constexpr int32_t actionPointer0Up = + AMOTION_EVENT_ACTION_POINTER_UP + (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + entries = { + // id x y + {10ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 10ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {10ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_MOVE}, + // no resampled value because frameTime - RESAMPLE_LATENCY == eventTime + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Second pointer id=1 appears + entries = { + // id x y + {15ms, {{0, 100, 100}, {1, 500, 500}}, actionPointer1Down}, + }; + publishInputEventEntries(entries); + frameTime = 20ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {15ms, {{0, 100, 100}, {1, 500, 500}}, actionPointer1Down}, + // no resampled value because frameTime - RESAMPLE_LATENCY == eventTime + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Both pointers move + entries = { + // id x y + {30ms, {{0, 100, 100}, {1, 500, 500}}, AMOTION_EVENT_ACTION_MOVE}, + {40ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 45ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {30ms, {{0, 100, 100}, {1, 500, 500}}, AMOTION_EVENT_ACTION_MOVE}, + {40ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + {45ms, {{0, 130, 130}, {1, 650, 650}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Both pointers move again + entries = { + // id x y + {60ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + {70ms, {{0, 130, 130}, {1, 700, 700}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 75ms + 5ms /*RESAMPLE_LATENCY*/; + /** + * The sample at t = 60, pointer id 0 is not equal to 120, because this value of 120 was + * received twice, and resampled to 130. So if we already reported it as "130", we continue + * to report it as such. Similar with pointer id 1. + */ + expectedEntries = { + {60ms, + {{0, 130, 130}, // not 120! because it matches previous real event + {1, 650, 650}}, + AMOTION_EVENT_ACTION_MOVE}, + {70ms, {{0, 130, 130}, {1, 700, 700}}, AMOTION_EVENT_ACTION_MOVE}, + {75ms, {{0, 135, 135}, {1, 750, 750}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // First pointer id=0 leaves the screen + entries = { + // id x y + {80ms, {{1, 600, 600}}, actionPointer0Up}, + }; + publishInputEventEntries(entries); + frameTime = 90ms; + expectedEntries = { + // id x y + {80ms, {{1, 600, 600}}, actionPointer0Up}, + // no resampled event for ACTION_POINTER_UP + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Remaining pointer id=1 is still present, but doesn't move + entries = { + // id x y + {90ms, {{1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 100ms; + expectedEntries = { + // id x y + {90ms, {{1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + /** + * The latest event with ACTION_MOVE was at t = 70, coord = 700. + * Use that value for resampling here: (600 - 700) / (90 - 70) * 5 + 600 + */ + {95ms, {{1, 575, 575}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +} // namespace android diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index a87b1873f0..8b00b5c44d 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -16,9 +16,10 @@ #define LOG_TAG "VelocityTracker_test" +#include <math.h> #include <array> #include <chrono> -#include <math.h> +#include <limits> #include <android-base/stringprintf.h> #include <attestation/HmacKeyManager.h> @@ -26,7 +27,9 @@ #include <gui/constants.h> #include <input/VelocityTracker.h> -using namespace std::chrono_literals; +using std::literals::chrono_literals::operator""ms; +using std::literals::chrono_literals::operator""ns; +using std::literals::chrono_literals::operator""us; using android::base::StringPrintf; namespace android { @@ -84,7 +87,7 @@ struct Position { } }; -struct MotionEventEntry { +struct PlanarMotionEventEntry { std::chrono::nanoseconds eventTime; std::vector<Position> positions; }; @@ -133,15 +136,43 @@ static int32_t resolveAction(const std::vector<Position>& lastPositions, return AMOTION_EVENT_ACTION_MOVE; } -static std::vector<MotionEvent> createMotionEventStream( - const std::vector<MotionEventEntry>& motions) { +static std::vector<MotionEvent> createAxisScrollMotionEventStream( + const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions) { + std::vector<MotionEvent> events; + for (const auto& [timeStamp, value] : motions) { + EXPECT_TRUE(!isnan(value)) << "The entry at pointerId must be valid"; + + PointerCoords coords[1]; + coords[0].setAxisValue(AMOTION_EVENT_AXIS_SCROLL, value); + + PointerProperties properties[1]; + properties[0].id = DEFAULT_POINTER_ID; + + MotionEvent event; + ui::Transform identityTransform; + event.initialize(InputEvent::nextId(), 5 /*deviceId*/, AINPUT_SOURCE_ROTARY_ENCODER, + ADISPLAY_ID_NONE, INVALID_HMAC, AMOTION_EVENT_ACTION_SCROLL, + 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, + 0 /*buttonState*/, MotionClassification::NONE, identityTransform, + 0 /*xPrecision*/, 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/, + timeStamp.count(), 1 /*pointerCount*/, properties, coords); + + events.emplace_back(event); + } + + return events; +} + +static std::vector<MotionEvent> createTouchMotionEventStream( + const std::vector<PlanarMotionEventEntry>& motions) { if (motions.empty()) { ADD_FAILURE() << "Need at least 1 sample to create a MotionEvent. Received empty vector."; } std::vector<MotionEvent> events; for (size_t i = 0; i < motions.size(); i++) { - const MotionEventEntry& entry = motions[i]; + const PlanarMotionEventEntry& entry = motions[i]; BitSet32 pointers = getValidPointers(entry.positions); const uint32_t pointerCount = pointers.count(); @@ -149,12 +180,11 @@ static std::vector<MotionEvent> createMotionEventStream( if (i == 0) { action = AMOTION_EVENT_ACTION_DOWN; EXPECT_EQ(1U, pointerCount) << "First event should only have 1 pointer"; - } else if (i == motions.size() - 1) { - EXPECT_EQ(1U, pointerCount) << "Last event should only have 1 pointer"; + } else if ((i == motions.size() - 1) && pointerCount == 1) { action = AMOTION_EVENT_ACTION_UP; } else { - const MotionEventEntry& previousEntry = motions[i-1]; - const MotionEventEntry& nextEntry = motions[i+1]; + const PlanarMotionEventEntry& previousEntry = motions[i-1]; + const PlanarMotionEventEntry& nextEntry = motions[i+1]; action = resolveAction(previousEntry.positions, entry.positions, nextEntry.positions); } @@ -194,53 +224,168 @@ static std::vector<MotionEvent> createMotionEventStream( } static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy, - const std::vector<MotionEventEntry>& motions, int32_t axis, - float targetVelocity) { + const std::vector<PlanarMotionEventEntry>& motions, + int32_t axis, float targetVelocity, + uint32_t pointerId = DEFAULT_POINTER_ID) { VelocityTracker vt(strategy); - float Vx, Vy; - std::vector<MotionEvent> events = createMotionEventStream(motions); + std::vector<MotionEvent> events = createTouchMotionEventStream(motions); for (MotionEvent event : events) { vt.addMovement(&event); } - vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy); - - switch (axis) { - case AMOTION_EVENT_AXIS_X: - checkVelocity(Vx, targetVelocity); - break; - case AMOTION_EVENT_AXIS_Y: - checkVelocity(Vy, targetVelocity); - break; - default: - FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y"; + checkVelocity(vt.getVelocity(axis, pointerId).value_or(0), targetVelocity); +} + +static void computeAndCheckAxisScrollVelocity( + const VelocityTracker::Strategy strategy, + const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions, + std::optional<float> targetVelocity) { + VelocityTracker vt(strategy); + + std::vector<MotionEvent> events = createAxisScrollMotionEventStream(motions); + for (const MotionEvent& event : events) { + vt.addMovement(&event); + } + + std::optional<float> velocity = vt.getVelocity(AMOTION_EVENT_AXIS_SCROLL, DEFAULT_POINTER_ID); + if (velocity && !targetVelocity) { + FAIL() << "Expected no velocity, but found " << *velocity; + } + if (!velocity && targetVelocity) { + FAIL() << "Expected velocity, but found no velocity"; + } + if (velocity) { + checkVelocity(*velocity, *targetVelocity); } } -static void computeAndCheckQuadraticEstimate(const std::vector<MotionEventEntry>& motions, - const std::array<float, 3>& coefficients) { +static void computeAndCheckQuadraticEstimate(const std::vector<PlanarMotionEventEntry>& motions, + const std::array<float, 3>& coefficients) { VelocityTracker vt(VelocityTracker::Strategy::LSQ2); - std::vector<MotionEvent> events = createMotionEventStream(motions); + std::vector<MotionEvent> events = createTouchMotionEventStream(motions); for (MotionEvent event : events) { vt.addMovement(&event); } - VelocityTracker::Estimator estimator; - EXPECT_TRUE(vt.getEstimator(0, &estimator)); + VelocityTracker::Estimator estimatorX; + VelocityTracker::Estimator estimatorY; + EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_X, 0, &estimatorX)); + EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_Y, 0, &estimatorY)); for (size_t i = 0; i< coefficients.size(); i++) { - checkCoefficient(estimator.xCoeff[i], coefficients[i]); - checkCoefficient(estimator.yCoeff[i], coefficients[i]); + checkCoefficient(estimatorX.coeff[i], coefficients[i]); + checkCoefficient(estimatorY.coeff[i], coefficients[i]); } } /* * ================== VelocityTracker tests generated manually ===================================== */ +TEST_F(VelocityTrackerTest, TestComputedVelocity) { + VelocityTracker::ComputedVelocity computedVelocity; + + computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 0 /*id*/, 200 /*velocity*/); + computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/, 400 /*velocity*/); + computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/, 650 /*velocity*/); + computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID, 750 /*velocity*/); + computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 0 /*id*/, 1000 /*velocity*/); + computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/, 2000 /*velocity*/); + computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/, 3000 /*velocity*/); + computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID, 4000 /*velocity*/); + + // Check the axes/indices with velocity. + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 0U /*id*/)), 200); + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/)), 400); + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/)), 650); + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID)), 750); + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 0U /*id*/)), 1000); + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/)), 2000); + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/)), 3000); + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID)), 4000); + for (uint32_t id = 0; id <= MAX_POINTER_ID; id++) { + // Since no data was added for AXIS_SCROLL, expect empty value for the axis for any id. + EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, id)) + << "Empty scroll data expected at id=" << id; + if (id == 0 || id == 26U || id == 27U || id == MAX_POINTER_ID) { + // Already checked above; continue. + continue; + } + // No data was added to X/Y for this id, expect empty value. + EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, id)) + << "Empty X data expected at id=" << id; + EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, id)) + << "Empty Y data expected at id=" << id; + } + // Out-of-bounds ids should given empty values. + EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, -1)); + EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID + 1)); +} + +TEST_F(VelocityTrackerTest, TestGetComputedVelocity) { + std::vector<PlanarMotionEventEntry> motions = { + {235089067457000ns, {{528.00, 0}}}, {235089084684000ns, {{527.00, 0}}}, + {235089093349000ns, {{527.00, 0}}}, {235089095677625ns, {{527.00, 0}}}, + {235089101859000ns, {{527.00, 0}}}, {235089110378000ns, {{528.00, 0}}}, + {235089112497111ns, {{528.25, 0}}}, {235089118760000ns, {{531.00, 0}}}, + {235089126686000ns, {{535.00, 0}}}, {235089129316820ns, {{536.33, 0}}}, + {235089135199000ns, {{540.00, 0}}}, {235089144297000ns, {{546.00, 0}}}, + {235089146136443ns, {{547.21, 0}}}, {235089152923000ns, {{553.00, 0}}}, + {235089160784000ns, {{559.00, 0}}}, {235089162955851ns, {{560.66, 0}}}, + {235089162955851ns, {{560.66, 0}}}, // ACTION_UP + }; + VelocityTracker vt(VelocityTracker::Strategy::IMPULSE); + std::vector<MotionEvent> events = createTouchMotionEventStream(motions); + for (const MotionEvent& event : events) { + vt.addMovement(&event); + } + + float maxFloat = std::numeric_limits<float>::max(); + VelocityTracker::ComputedVelocity computedVelocity; + computedVelocity = vt.getComputedVelocity(1000 /* units */, maxFloat); + checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)), + 764.345703); + + // Expect X velocity to be scaled with respective to provided units. + computedVelocity = vt.getComputedVelocity(1000000 /* units */, maxFloat); + checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)), + 764345.703); + + // Expect X velocity to be clamped by provided max velocity. + computedVelocity = vt.getComputedVelocity(1000000 /* units */, 1000); + checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)), 1000); + + // All 0 data for Y; expect 0 velocity. + EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, DEFAULT_POINTER_ID)), 0); + + // No data for scroll-axis; expect empty velocity. + EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, DEFAULT_POINTER_ID)); +} + +TEST_F(VelocityTrackerTest, TestApiInteractionsWithNoMotionEvents) { + VelocityTracker vt(VelocityTracker::Strategy::DEFAULT); + + EXPECT_FALSE(vt.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)); + + VelocityTracker::Estimator estimator; + EXPECT_FALSE(vt.getEstimator(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID, &estimator)); + + VelocityTracker::ComputedVelocity computedVelocity = vt.getComputedVelocity(1000, 1000); + for (uint32_t id = 0; id <= MAX_POINTER_ID; id++) { + EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, id)); + EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, id)); + } + + EXPECT_EQ(-1, vt.getActivePointerId()); + + // Make sure that the clearing functions execute without an issue. + vt.clearPointers(BitSet32(7U)); + vt.clear(); +} + TEST_F(VelocityTrackerTest, ThreePointsPositiveVelocityTest) { // Same coordinate is reported 2 times in a row // It is difficult to determine the correct answer here, but at least the direction // of the reported velocity should be positive. - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { {0ms, {{273, 0}}}, {12585us, {{293, 0}}}, {14730us, {{293, 0}}}, @@ -252,7 +397,7 @@ TEST_F(VelocityTrackerTest, ThreePointsPositiveVelocityTest) { TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) { // Same coordinate is reported 3 times in a row - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { {0ms, {{293, 0}}}, {6132us, {{293, 0}}}, {11283us, {{293, 0}}}, @@ -264,7 +409,7 @@ TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) { TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) { // Fixed velocity at 5 points per 10 milliseconds - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { {0ms, {{0, 0}}}, {10ms, {{5, 0}}}, {20ms, {{10, 0}}}, {20ms, {{10, 0}}}, // ACTION_UP }; computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 500); @@ -288,7 +433,7 @@ TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) { // --------------- Recorded by hand on swordfish --------------------------------------------------- TEST_F(VelocityTrackerTest, SwordfishFlingDown) { // Recording of a fling on Swordfish that could cause a fling in the wrong direction - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 0ms, {{271, 96}} }, { 16071042ns, {{269.786346, 106.922775}} }, { 35648403ns, {{267.983063, 156.660034}} }, @@ -323,7 +468,7 @@ TEST_F(VelocityTrackerTest, SwordfishFlingDown) { TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) { // Sailfish - fling up - slow - 1 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235089067457000ns, {{528.00, 983.00}} }, { 235089084684000ns, {{527.00, 981.00}} }, { 235089093349000ns, {{527.00, 977.00}} }, @@ -355,7 +500,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) { TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) { // Sailfish - fling up - slow - 2 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235110560704000ns, {{522.00, 1107.00}} }, { 235110575764000ns, {{522.00, 1107.00}} }, { 235110584385000ns, {{522.00, 1107.00}} }, @@ -384,7 +529,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) { TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) { // Sailfish - fling up - slow - 3 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 792536237000ns, {{580.00, 1317.00}} }, { 792541538987ns, {{580.63, 1311.94}} }, { 792544613000ns, {{581.00, 1309.00}} }, @@ -418,7 +563,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) { TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) { // Sailfish - fling up - faster - 1 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235160420675000ns, {{610.00, 1042.00}} }, { 235160428220000ns, {{609.00, 1026.00}} }, { 235160436544000ns, {{609.00, 1024.00}} }, @@ -452,7 +597,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) { TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) { // Sailfish - fling up - faster - 2 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 847153808000ns, {{576.00, 1264.00}} }, { 847171174000ns, {{576.00, 1262.00}} }, { 847179640000ns, {{576.00, 1257.00}} }, @@ -478,7 +623,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) { TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) { // Sailfish - fling up - faster - 3 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235200532789000ns, {{507.00, 1084.00}} }, { 235200549221000ns, {{507.00, 1083.00}} }, { 235200557841000ns, {{507.00, 1081.00}} }, @@ -504,7 +649,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) { TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) { // Sailfish - fling up - fast - 1 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 920922149000ns, {{561.00, 1412.00}} }, { 920930185000ns, {{559.00, 1377.00}} }, { 920930262463ns, {{558.98, 1376.66}} }, @@ -533,7 +678,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) { TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) { // Sailfish - fling up - fast - 2 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235247153233000ns, {{518.00, 1168.00}} }, { 235247170452000ns, {{517.00, 1167.00}} }, { 235247178908000ns, {{515.00, 1159.00}} }, @@ -556,7 +701,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) { TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) { // Sailfish - fling up - fast - 3 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235302568736000ns, {{529.00, 1167.00}} }, { 235302576644000ns, {{523.00, 1140.00}} }, { 235302579395063ns, {{520.91, 1130.61}} }, @@ -577,7 +722,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) { TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) { // Sailfish - fling down - slow - 1 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235655749552755ns, {{582.00, 432.49}} }, { 235655750638000ns, {{582.00, 433.00}} }, { 235655758865000ns, {{582.00, 440.00}} }, @@ -611,7 +756,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) { TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) { // Sailfish - fling down - slow - 2 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235671152083370ns, {{485.24, 558.28}} }, { 235671154126000ns, {{485.00, 559.00}} }, { 235671162497000ns, {{484.00, 566.00}} }, @@ -645,7 +790,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) { TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) { // Sailfish - fling down - slow - 3 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 170983201000ns, {{557.00, 533.00}} }, { 171000668000ns, {{556.00, 534.00}} }, { 171007359750ns, {{554.73, 535.27}} }, @@ -672,7 +817,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) { TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) { // Sailfish - fling down - faster - 1 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235695280333000ns, {{558.00, 451.00}} }, { 235695283971237ns, {{558.43, 454.45}} }, { 235695289038000ns, {{559.00, 462.00}} }, @@ -702,7 +847,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) { TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) { // Sailfish - fling down - faster - 2 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235709624766000ns, {{535.00, 579.00}} }, { 235709642256000ns, {{534.00, 580.00}} }, { 235709643350278ns, {{533.94, 580.06}} }, @@ -733,7 +878,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) { TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) { // Sailfish - fling down - faster - 3 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235727628927000ns, {{540.00, 440.00}} }, { 235727636810000ns, {{537.00, 454.00}} }, { 235727646176000ns, {{536.00, 454.00}} }, @@ -762,7 +907,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) { TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) { // Sailfish - fling down - fast - 1 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235762352849000ns, {{467.00, 286.00}} }, { 235762360250000ns, {{443.00, 344.00}} }, { 235762362787412ns, {{434.77, 363.89}} }, @@ -783,7 +928,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) { TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) { // Sailfish - fling down - fast - 2 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 235772487188000ns, {{576.00, 204.00}} }, { 235772495159000ns, {{553.00, 236.00}} }, { 235772503568000ns, {{551.00, 240.00}} }, @@ -804,7 +949,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) { TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) { // Sailfish - fling down - fast - 3 - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 507650295000ns, {{628.00, 233.00}} }, { 507658234000ns, {{605.00, 269.00}} }, { 507666784000ns, {{601.00, 274.00}} }, @@ -835,7 +980,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) { * part of the fitted data), this can cause large velocity values to be reported instead. */ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_ThreeFingerTap) { - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 0us, {{1063, 1128}, {NAN, NAN}, {NAN, NAN}} }, { 10800us, {{1063, 1128}, {682, 1318}, {NAN, NAN}} }, // POINTER_DOWN { 10800us, {{1063, 1128}, {682, 1318}, {397, 1747}} }, // POINTER_DOWN @@ -846,13 +991,71 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_ThreeFi // Velocity should actually be zero, but we expect 0.016 here instead. // This is close enough to zero, and is likely caused by division by a very small number. - computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, -0.016); - computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, -0.016); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, 0); computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0); computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y, 0); } /** + * ================= Pointer liftoff =============================================================== + */ + +/** + * The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a short delay + * between the last ACTION_MOVE and the next ACTION_POINTER_UP or ACTION_UP, velocity should not be + * affected by the liftoff. + */ +TEST_F(VelocityTrackerTest, ShortDelayBeforeActionUp) { + std::vector<PlanarMotionEventEntry> motions = { + {0ms, {{10, 0}}}, {10ms, {{20, 0}}}, {20ms, {{30, 0}}}, {30ms, {{30, 0}}}, // ACTION_UP + }; + computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, + 1000); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 1000); +} + +/** + * The last movement of a single pointer is ACTION_UP. If there's a long delay between the last + * ACTION_MOVE and the final ACTION_UP, velocity should be reported as zero because the pointer + * should be assumed to have stopped. + */ +TEST_F(VelocityTrackerTest, LongDelayBeforeActionUp) { + std::vector<PlanarMotionEventEntry> motions = { + {0ms, {{10, 0}}}, + {10ms, {{20, 0}}}, + {20ms, {{30, 0}}}, + {3000ms, {{30, 0}}}, // ACTION_UP + }; + computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0); +} + +/** + * The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a long delay + * before ACTION_POINTER_UP event, the movement should be assumed to have stopped. + * The final velocity should be reported as zero for all pointers. + */ +TEST_F(VelocityTrackerTest, LongDelayBeforeActionPointerUp) { + std::vector<PlanarMotionEventEntry> motions = { + {0ms, {{10, 0}}}, + {10ms, {{20, 0}, {100, 0}}}, + {20ms, {{30, 0}, {200, 0}}}, + {30ms, {{30, 0}, {300, 0}}}, + {40ms, {{30, 0}, {400, 0}}}, + {3000ms, {{30, 0}}}, // ACTION_POINTER_UP + }; + computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0, + /*pointerId*/ 0); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0, + /*pointerId*/ 0); + computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0, + /*pointerId*/ 1); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0, + /*pointerId*/ 1); +} + +/** * ================== Tests for least squares fitting ============================================== * * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy @@ -878,7 +1081,7 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_ThreeFi * In the test, we would convert these coefficients to (0*(1E3)^0, 0*(1E3)^1, 1*(1E3)^2). */ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constant) { - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 0ms, {{1, 1}} }, // 0 s { 1ms, {{1, 1}} }, // 0.001 s { 2ms, {{1, 1}} }, // 0.002 s @@ -896,7 +1099,7 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constan * Straight line y = x :: the constant and quadratic coefficients are zero. */ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) { - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 0ms, {{-2, -2}} }, { 1ms, {{-1, -1}} }, { 2ms, {{-0, -0}} }, @@ -914,7 +1117,7 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) * Parabola */ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic) { - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 0ms, {{1, 1}} }, { 1ms, {{4, 4}} }, { 2ms, {{8, 8}} }, @@ -932,7 +1135,7 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabol * Parabola */ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic2) { - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 0ms, {{1, 1}} }, { 1ms, {{4, 4}} }, { 2ms, {{9, 9}} }, @@ -950,7 +1153,7 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabol * Parabola :: y = x^2 :: the constant and linear coefficients are zero. */ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic3) { - std::vector<MotionEventEntry> motions = { + std::vector<PlanarMotionEventEntry> motions = { { 0ms, {{4, 4}} }, { 1ms, {{1, 1}} }, { 2ms, {{0, 0}} }, @@ -964,4 +1167,100 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabol computeAndCheckQuadraticEstimate(motions, std::array<float, 3>({0, 0E3, 1E6})); } +// Recorded by hand on sailfish, but only the diffs are taken to test cumulative axis velocity. +TEST_F(VelocityTrackerTest, AxisScrollVelocity) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = { + {235089067457000ns, 0.00}, {235089084684000ns, -1.00}, {235089093349000ns, 0.00}, + {235089095677625ns, 0.00}, {235089101859000ns, 0.00}, {235089110378000ns, 0.00}, + {235089112497111ns, 0.25}, {235089118760000ns, 1.75}, {235089126686000ns, 4.00}, + {235089129316820ns, 1.33}, {235089135199000ns, 3.67}, {235089144297000ns, 6.00}, + {235089146136443ns, 1.21}, {235089152923000ns, 5.79}, {235089160784000ns, 6.00}, + {235089162955851ns, 1.66}, + }; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, {764.345703}); +} + +// --------------- Recorded by hand on a Wear OS device using a rotating side button --------------- +TEST_F(VelocityTrackerTest, AxisScrollVelocity_ScrollDown) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = { + {224598065152ns, -0.050100}, {224621871104ns, -0.133600}, {224645464064ns, -0.551100}, + {224669171712ns, -0.801600}, {224687063040ns, -1.035400}, {224706691072ns, -0.484300}, + {224738213888ns, -0.334000}, {224754401280ns, -0.083500}, + }; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, {-27.86}); +} + +TEST_F(VelocityTrackerTest, AxisScrollVelocity_ScrollUp) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = { + {269606010880ns, 0.050100}, {269626064896ns, 0.217100}, {269641973760ns, 0.267200}, + {269658079232ns, 0.267200}, {269674217472ns, 0.267200}, {269690683392ns, 0.367400}, + {269706133504ns, 0.551100}, {269722173440ns, 0.501000}, + }; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, {31.92}); +} + +TEST_F(VelocityTrackerTest, AxisScrollVelocity_ScrollDown_ThenUp_ThenDown) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = { + {2580534001664ns, -0.033400}, {2580549992448ns, -0.133600}, + {2580566769664ns, -0.250500}, {2580581974016ns, -0.183700}, + {2580597964800ns, -0.267200}, {2580613955584ns, -0.551100}, + {2580635189248ns, -0.601200}, {2580661927936ns, -0.450900}, + {2580683161600ns, -0.417500}, {2580705705984ns, -0.150300}, + {2580722745344ns, -0.016700}, {2580786446336ns, 0.050100}, + {2580801912832ns, 0.150300}, {2580822360064ns, 0.300600}, + {2580838088704ns, 0.300600}, {2580854341632ns, 0.400800}, + {2580869808128ns, 0.517700}, {2580886061056ns, 0.501000}, + {2580905984000ns, 0.350700}, {2580921974784ns, 0.350700}, + {2580937965568ns, 0.066800}, {2580974665728ns, 0.016700}, + {2581034434560ns, -0.066800}, {2581049901056ns, -0.116900}, + {2581070610432ns, -0.317300}, {2581086076928ns, -0.200400}, + {2581101805568ns, -0.233800}, {2581118058496ns, -0.417500}, + {2581134049280ns, -0.417500}, {2581150040064ns, -0.367400}, + {2581166030848ns, -0.267200}, {2581181759488ns, -0.150300}, + {2581199847424ns, -0.066800}, + }; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, {-9.73}); +} + +// ------------------------------- Hand generated test cases --------------------------------------- +TEST_F(VelocityTrackerTest, AxisScrollVelocity_SimilarDifferentialValues) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = {{1ns, 2.12}, {3ns, 2.12}, + {7ns, 2.12}, {8ns, 2.12}, + {15ns, 2.12}, {18ns, 2.12}}; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, {1690236059.86}); +} + +TEST_F(VelocityTrackerTest, AxisScrollVelocity_OnlyTwoValues) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = {{1ms, 5}, {2ms, 10}}; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, {10000}); +} + +TEST_F(VelocityTrackerTest, AxisScrollVelocity_ConstantVelocity) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = {{1ms, 20}, {2ms, 20}, + {3ms, 20}, {4ms, 20}, + {5ms, 20}, {6ms, 20}}; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, {20000}); +} + +TEST_F(VelocityTrackerTest, AxisScrollVelocity_NoMotion) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = {{1ns, 0}, {2ns, 0}, + {3ns, 0}, {4ns, 0}, + {5ns, 0}, {6ns, 0}}; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, {0}); +} + +TEST_F(VelocityTrackerTest, AxisScrollVelocity_NoData) { + std::vector<std::pair<std::chrono::nanoseconds, float>> motions = {}; + + computeAndCheckAxisScrollVelocity(VelocityTracker::Strategy::IMPULSE, motions, std::nullopt); +} + } // namespace android diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 8240b08085..539cbaa341 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -18,8 +18,8 @@ //#define LOG_NDEBUG 0 #include <android-base/thread_annotations.h> +#include <android/gui/ISurfaceComposer.h> #include <gui/DisplayEventDispatcher.h> -#include <gui/ISurfaceComposer.h> #include <jni.h> #include <private/android/choreographer.h> #include <utils/Looper.h> @@ -198,7 +198,7 @@ Choreographer* Choreographer::getForThread() { } Choreographer::Choreographer(const sp<Looper>& looper) - : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp), + : DisplayEventDispatcher(looper, gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp), mLooper(looper), mThreadId(std::this_thread::get_id()) { std::lock_guard<std::mutex> _l(gChoreographers.lock); diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp index 4659b96b11..8d8a2bc244 100644 --- a/libs/nativedisplay/Android.bp +++ b/libs/nativedisplay/Android.bp @@ -53,6 +53,7 @@ cc_library_shared { version_script: "libnativedisplay.map.txt", srcs: [ + ":libgui_frame_event_aidl", "AChoreographer.cpp", "ADisplay.cpp", "surfacetexture/surface_texture.cpp", diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt index 969d9379f0..9172d5ed13 100644 --- a/libs/nativedisplay/libnativedisplay.map.txt +++ b/libs/nativedisplay/libnativedisplay.map.txt @@ -1,25 +1,25 @@ LIBNATIVEDISPLAY { global: - AChoreographer_getInstance; # apex # introduced=30 - AChoreographer_postFrameCallback; # apex # introduced=30 - AChoreographer_postFrameCallbackDelayed; # apex # introduced=30 - AChoreographer_postFrameCallback64; # apex # introduced=30 - AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30 - AChoreographer_registerRefreshRateCallback; # apex # introduced=30 - AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30 - AChoreographer_postVsyncCallback; # apex # introduced=33 - AChoreographerFrameCallbackData_getFrameTimeNanos; # apex # introduced=33 - AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33 - AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33 - AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33 - AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos; # apex # introduced=33 - AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos; # apex # introduced=33 - AChoreographer_create; # apex # introduced=30 - AChoreographer_destroy; # apex # introduced=30 - AChoreographer_getFd; # apex # introduced=30 - AChoreographer_handlePendingEvents; # apex # introduced=30 - ASurfaceTexture_fromSurfaceTexture; # apex # introduced=30 - ASurfaceTexture_release; # apex # introduced=30 + AChoreographer_getInstance; # systemapi # introduced=30 + AChoreographer_postFrameCallback; # systemapi # introduced=30 + AChoreographer_postFrameCallbackDelayed; # systemapi # introduced=30 + AChoreographer_postFrameCallback64; # systemapi # introduced=30 + AChoreographer_postFrameCallbackDelayed64; # systemapi # introduced=30 + AChoreographer_registerRefreshRateCallback; # systemapi # introduced=30 + AChoreographer_unregisterRefreshRateCallback; # systemapi # introduced=30 + AChoreographer_postVsyncCallback; # systemapi # introduced=33 + AChoreographerFrameCallbackData_getFrameTimeNanos; # systemapi # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelinesLength; # systemapi # introduced=33 + AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # systemapi # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # systemapi # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos; # systemapi # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos; # systemapi # introduced=33 + AChoreographer_create; # systemapi # introduced=30 + AChoreographer_destroy; # systemapi # introduced=30 + AChoreographer_getFd; # systemapi # introduced=30 + AChoreographer_handlePendingEvents; # systemapi # introduced=30 + ASurfaceTexture_fromSurfaceTexture; # systemapi # introduced=30 + ASurfaceTexture_release; # systemapi # introduced=30 local: *; }; diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 4a1784ea0b..180dce9ed7 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "AHardwareBuffer" +#include <android/hardware_buffer.h> +#include <android/hardware_buffer_aidl.h> #include <vndk/hardware_buffer.h> #include <errno.h> @@ -32,6 +34,9 @@ #include <android/hardware/graphics/common/1.1/types.h> #include <aidl/android/hardware/graphics/common/PixelFormat.h> +// TODO: Better way to handle this +#include "../binder/ndk/parcel_internal.h" + static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints using namespace android; @@ -357,12 +362,12 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out return INVALID_OPERATION; } - GraphicBuffer* gBuffer = new GraphicBuffer(); + sp<GraphicBuffer> gBuffer(new GraphicBuffer()); status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount); if (err != NO_ERROR) { return err; } - *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer); + *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer.get()); // Ensure the buffer has a positive ref-count. AHardwareBuffer_acquire(*outBuffer); @@ -412,6 +417,25 @@ int AHardwareBuffer_getId(const AHardwareBuffer* buffer, uint64_t* outId) { return OK; } +binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel, + AHardwareBuffer* _Nullable* _Nonnull outBuffer) { + if (!parcel || !outBuffer) return STATUS_BAD_VALUE; + auto buffer = sp<GraphicBuffer>::make(); + status_t status = parcel->get()->read(*buffer); + if (status != STATUS_OK) return status; + *outBuffer = AHardwareBuffer_from_GraphicBuffer(buffer.get()); + AHardwareBuffer_acquire(*outBuffer); + return STATUS_OK; +} + +binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer, + AParcel* _Nonnull parcel) { + const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer); + if (!gb) return STATUS_BAD_VALUE; + if (!parcel) return STATUS_BAD_VALUE; + return parcel->get()->write(*gb); +} + // ---------------------------------------------------------------------------- // VNDK functions // ---------------------------------------------------------------------------- diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 18a4b2d3e8..b0750809f8 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -176,8 +176,8 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa static_cast<int>(HAL_DATASPACE_BT2020_HLG)); static_assert(static_cast<int>(ADATASPACE_BT2020_ITU_HLG) == static_cast<int>(HAL_DATASPACE_BT2020_ITU_HLG)); - static_assert(static_cast<int>(DEPTH) == static_cast<int>(HAL_DATASPACE_DEPTH)); - static_assert(static_cast<int>(DYNAMIC_DEPTH) == static_cast<int>(HAL_DATASPACE_DYNAMIC_DEPTH)); + static_assert(static_cast<int>(ADATASPACE_DEPTH) == static_cast<int>(HAL_DATASPACE_DEPTH)); + static_assert(static_cast<int>(ADATASPACE_DYNAMIC_DEPTH) == static_cast<int>(HAL_DATASPACE_DYNAMIC_DEPTH)); if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || !isDataSpaceValid(window, dataSpace)) { @@ -193,6 +193,13 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { return query(window, NATIVE_WINDOW_DATASPACE); } +int32_t ANativeWindow_getBuffersDefaultDataSpace(ANativeWindow* window) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { + return -EINVAL; + } + return query(window, NATIVE_WINDOW_DEFAULT_DATASPACE); +} + int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { return ANativeWindow_setFrameRateWithChangeStrategy(window, frameRate, compatibility, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); @@ -213,6 +220,15 @@ int32_t ANativeWindow_setFrameRateWithChangeStrategy(ANativeWindow* window, floa return native_window_set_frame_rate(window, frameRate, compatibility, changeFrameRateStrategy); } +int32_t ANativeWindow_clearFrameRate(ANativeWindow* window) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { + return -EINVAL; + } + return native_window_set_frame_rate(window, 0, + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); +} + /************************************************************************************************** * vndk-stable **************************************************************************************************/ diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index d7db6bd174..3503a9eee7 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -99,6 +99,8 @@ cc_library { "liblog", "libutils", "libui", + "libbinder", + "libbinder_ndk", "android.hardware.graphics.common@1.1", ], diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index 771844f4fe..ad4cc4a229 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -548,14 +548,14 @@ enum ADataSpace { * * This value is valid with formats HAL_PIXEL_FORMAT_Y16 and HAL_PIXEL_FORMAT_BLOB. */ - DEPTH = 4096, + ADATASPACE_DEPTH = 4096, /** * ISO 16684-1:2011(E) Dynamic Depth: * * Embedded depth metadata following the dynamic depth specification. */ - DYNAMIC_DEPTH = 4098 + ADATASPACE_DYNAMIC_DEPTH = 4098 }; __END_DECLS diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h new file mode 100644 index 0000000000..906d9c6f6b --- /dev/null +++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h @@ -0,0 +1,151 @@ +/* + * 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. + */ + +/** + * @file hardware_buffer_aidl.h + * @brief HardwareBuffer NDK AIDL glue code + */ + +/** + * @addtogroup AHardwareBuffer + * + * Parcelable support for AHardwareBuffer. Can be used with libbinder_ndk + * + * @{ + */ + +#ifndef ANDROID_HARDWARE_BUFFER_AIDL_H +#define ANDROID_HARDWARE_BUFFER_AIDL_H + +#include <android/binder_parcel.h> +#include <android/hardware_buffer.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * Read an AHardwareBuffer from a AParcel. The output buffer will have an + * initial reference acquired and will need to be released with + * AHardwareBuffer_release. + * + * Available since API level 34. + * + * \return STATUS_OK on success + * STATUS_BAD_VALUE if the parcel or outBuffer is null, or if there's an + * issue deserializing (eg, corrupted parcel) + * STATUS_BAD_TYPE if the parcel's current data position is not that of + * an AHardwareBuffer type + * STATUS_NO_MEMORY if an allocation fails + */ +binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel, + AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(34); + +/** + * Write an AHardwareBuffer to an AParcel. + * + * Available since API level 34. + * + * \return STATUS_OK on success. + * STATUS_BAD_VALUE if either buffer or parcel is null, or if the AHardwareBuffer* + * fails to serialize (eg, internally corrupted) + * STATUS_NO_MEMORY if the parcel runs out of space to store the buffer & is + * unable to allocate more + * STATUS_FDS_NOT_ALLOWED if the parcel does not allow storing FDs + */ +binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer, + AParcel* _Nonnull parcel) __INTRODUCED_IN(34); + +__END_DECLS + +// Only enable the AIDL glue helper if this is C++ +#ifdef __cplusplus + +namespace aidl::android::hardware { + +/** + * Wrapper class that enables interop with AIDL NDK generation + * Takes ownership of the AHardwareBuffer* given to it in reset() and will automatically + * destroy it in the destructor, similar to a smart pointer container + */ +class HardwareBuffer { +public: + HardwareBuffer() noexcept {} + explicit HardwareBuffer(HardwareBuffer&& other) noexcept : mBuffer(other.release()) {} + + ~HardwareBuffer() { + reset(); + } + + binder_status_t readFromParcel(const AParcel* _Nonnull parcel) { + reset(); + return AHardwareBuffer_readFromParcel(parcel, &mBuffer); + } + + binder_status_t writeToParcel(AParcel* _Nonnull parcel) const { + if (!mBuffer) { + return STATUS_BAD_VALUE; + } + return AHardwareBuffer_writeToParcel(mBuffer, parcel); + } + + /** + * Destroys any currently owned AHardwareBuffer* and takes ownership of the given + * AHardwareBuffer* + * + * @param buffer The buffer to take ownership of + */ + void reset(AHardwareBuffer* _Nullable buffer = nullptr) noexcept { + if (mBuffer) { + AHardwareBuffer_release(mBuffer); + mBuffer = nullptr; + } + mBuffer = buffer; + } + + inline AHardwareBuffer* _Nullable operator-> () const { return mBuffer; } + inline AHardwareBuffer* _Nullable get() const { return mBuffer; } + inline explicit operator bool () const { return mBuffer != nullptr; } + + HardwareBuffer& operator=(HardwareBuffer&& other) noexcept { + reset(other.release()); + return *this; + } + + /** + * Stops managing any contained AHardwareBuffer*, returning it to the caller. Ownership + * is released. + * @return AHardwareBuffer* or null if this was empty + */ + [[nodiscard]] AHardwareBuffer* _Nullable release() noexcept { + AHardwareBuffer* _Nullable ret = mBuffer; + mBuffer = nullptr; + return ret; + } + +private: + HardwareBuffer(const HardwareBuffer& other) = delete; + HardwareBuffer& operator=(const HardwareBuffer& other) = delete; + + AHardwareBuffer* _Nullable mBuffer = nullptr; +}; + +} // aidl::android::hardware + +#endif // __cplusplus + +#endif // ANDROID_HARDWARE_BUFFER_AIDL_H + +/** @} */ diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index f0e1c4d749..281ec52528 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -227,6 +227,16 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa */ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN(28); +/** + * Get the default dataspace of the buffers in window as set by the consumer. + * + * Available since API level 34. + * + * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if + * dataspace is unknown, or -EINVAL if window is invalid. + */ +int32_t ANativeWindow_getBuffersDefaultDataSpace(ANativeWindow* window) __INTRODUCED_IN(34); + /** Compatibility value for ANativeWindow_setFrameRate. */ enum ANativeWindow_FrameRateCompatibility { /** @@ -303,6 +313,8 @@ enum ANativeWindow_ChangeFrameRateStrategy { * You can register for changes in the refresh rate using * \a AChoreographer_registerRefreshRateCallback. * + * See ANativeWindow_clearFrameRate(). + * * Available since API level 31. * * \param window pointer to an ANativeWindow object. @@ -332,6 +344,37 @@ int32_t ANativeWindow_setFrameRateWithChangeStrategy(ANativeWindow* window, floa int8_t compatibility, int8_t changeFrameRateStrategy) __INTRODUCED_IN(31); +/** + * Clears the frame rate which is set for this window. + * + * This is equivalent to calling + * ANativeWindow_setFrameRateWithChangeStrategy(window, 0, compatibility, changeFrameRateStrategy). + * + * Usage of this API won't introduce frame rate throttling, + * or affect other aspects of the application's frame production + * pipeline. However, because the system may change the display refresh rate, + * calls to this function may result in changes to Choreographer callback + * timings, and changes to the time interval at which the system releases + * buffers back to the application. + * + * Note that this only has an effect for windows presented on the display. If + * this ANativeWindow is consumed by something other than the system compositor, + * e.g. a media codec, this call has no effect. + * + * You can register for changes in the refresh rate using + * \a AChoreographer_registerRefreshRateCallback. + * + * See ANativeWindow_setFrameRateWithChangeStrategy(). + * + * Available since API level 34. + * + * \param window pointer to an ANativeWindow object. + * + * \return 0 for success, -EINVAL if the window value is invalid. + */ +int32_t ANativeWindow_clearFrameRate(ANativeWindow* window) + __INTRODUCED_IN(__ANDROID_API_U__); + #ifdef __cplusplus }; #endif diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index a54af1fa62..79f49e1786 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1034,6 +1034,11 @@ enum { * This surface is ignored while choosing the refresh rate. */ ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + + /** + * This surface will vote for the minimum refresh rate. + */ + ANATIVEWINDOW_FRAME_RATE_MIN }; static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index da42a96df7..ce108b6096 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -14,6 +14,8 @@ LIBNATIVEWINDOW { AHardwareBuffer_release; AHardwareBuffer_sendHandleToUnixSocket; AHardwareBuffer_unlock; + AHardwareBuffer_readFromParcel; # introduced=34 + AHardwareBuffer_writeToParcel; # introduced=34 ANativeWindowBuffer_getHardwareBuffer; # llndk ANativeWindow_OemStorageGet; # llndk ANativeWindow_OemStorageSet; # llndk @@ -21,6 +23,7 @@ LIBNATIVEWINDOW { ANativeWindow_cancelBuffer; # llndk ANativeWindow_dequeueBuffer; # llndk ANativeWindow_getBuffersDataSpace; # introduced=28 + ANativeWindow_getBuffersDefaultDataSpace; # introduced=34 ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getLastDequeueDuration; # systemapi # introduced=30 @@ -48,6 +51,7 @@ LIBNATIVEWINDOW { ANativeWindow_setDequeueTimeout; # systemapi # introduced=30 ANativeWindow_setFrameRate; # introduced=30 ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31 + ANativeWindow_clearFrameRate; # introduced=UpsideDownCake ANativeWindow_setSharedBufferMode; # llndk ANativeWindow_setSwapInterval; # llndk ANativeWindow_setUsage; # llndk diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index f6f57dde7d..054053898c 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -21,13 +21,15 @@ cc_defaults { cc_defaults { name: "librenderengine_defaults", - defaults: ["renderengine_defaults"], + defaults: [ + "android.hardware.graphics.composer3-ndk_shared", + "renderengine_defaults", + ], cflags: [ "-DGL_GLEXT_PROTOTYPES", "-DEGL_EGLEXT_PROTOTYPES", ], shared_libs: [ - "android.hardware.graphics.composer3-V1-ndk", "libbase", "libcutils", "libEGL", diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index c7ad058ab9..9d9cb6b2bc 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -63,12 +63,13 @@ void RenderEngine::validateOutputBufferUsage(const sp<GraphicBuffer>& buffer) { "output buffer not gpu writeable"); } -std::future<RenderEngineResult> RenderEngine::drawLayers( - const DisplaySettings& display, const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence) { - const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>(); - std::future<RenderEngineResult> resultFuture = resultPromise->get_future(); +ftl::Future<FenceResult> RenderEngine::drawLayers(const DisplaySettings& display, + const std::vector<LayerSettings>& layers, + const std::shared_ptr<ExternalTexture>& buffer, + const bool useFramebufferCache, + base::unique_fd&& bufferFence) { + const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); + std::future<FenceResult> resultFuture = resultPromise->get_future(); drawLayersInternal(std::move(resultPromise), display, layers, buffer, useFramebufferCache, std::move(bufferFence)); return resultFuture; diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp index 249fec5866..afbe6cfa4d 100644 --- a/libs/renderengine/benchmark/Android.bp +++ b/libs/renderengine/benchmark/Android.bp @@ -24,6 +24,7 @@ package { cc_benchmark { name: "librenderengine_bench", defaults: [ + "android.hardware.graphics.composer3-ndk_shared", "skia_deps", "surfaceflinger_defaults", ], @@ -43,7 +44,6 @@ cc_benchmark { ], shared_libs: [ - "android.hardware.graphics.composer3-V1-ndk", "libbase", "libcutils", "libjnigraphics", diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp index ead97cf5df..739f3fa327 100644 --- a/libs/renderengine/benchmark/RenderEngineBench.cpp +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -117,11 +117,12 @@ static std::shared_ptr<ExternalTexture> allocateBuffer(RenderEngine& re, uint32_ uint64_t extraUsageFlags = 0, std::string name = "output") { return std::make_shared< - impl::ExternalTexture>(new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE | - extraUsageFlags, - std::move(name)), + impl::ExternalTexture>(sp<GraphicBuffer>::make(width, height, + HAL_PIXEL_FORMAT_RGBA_8888, 1u, + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE | + extraUsageFlags, + std::move(name)), re, impl::ExternalTexture::Usage::READABLE | impl::ExternalTexture::Usage::WRITEABLE); @@ -158,9 +159,10 @@ static std::shared_ptr<ExternalTexture> copyBuffer(RenderEngine& re, }; auto layers = std::vector<LayerSettings>{layer}; - auto [status, drawFence] = - re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd()).get(); - sp<Fence> waitFence = sp<Fence>::make(std::move(drawFence)); + sp<Fence> waitFence = + re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd()) + .get() + .value(); waitFence->waitForever(LOG_TAG); return texture; } @@ -189,10 +191,10 @@ static void benchDrawLayers(RenderEngine& re, const std::vector<LayerSettings>& // This loop starts and stops the timer. for (auto _ : benchState) { - auto [status, drawFence] = re.drawLayers(display, layers, outputBuffer, - kUseFrameBufferCache, base::unique_fd()) - .get(); - sp<Fence> waitFence = sp<Fence>::make(std::move(drawFence)); + sp<Fence> waitFence = re.drawLayers(display, layers, outputBuffer, kUseFrameBufferCache, + base::unique_fd()) + .get() + .value(); waitFence->waitForever(LOG_TAG); } diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 22dd86698b..13f766c3e1 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -454,8 +454,9 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp mImageManager->initThread(); mDrawingBuffer = createFramebuffer(); sp<GraphicBuffer> buf = - new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, "placeholder"); + sp<GraphicBuffer>::make(1, 1, PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, + "placeholder"); const status_t err = buf->initCheck(); if (err != OK) { @@ -921,7 +922,8 @@ void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners // and the middle part without rounded corners. - const int32_t radius = ceil(layer.geometry.roundedCornersRadius); + const int32_t radius = ceil( + (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / 2.0); const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius); setScissor(topRect); drawMesh(mesh); @@ -1079,14 +1081,14 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer } void GLESRenderEngine::drawLayersInternal( - const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise, + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { ATRACE_CALL(); if (layers.empty()) { ALOGV("Drawing empty layer stack"); - resultPromise->set_value({NO_ERROR, base::unique_fd()}); + resultPromise->set_value(Fence::NO_FENCE); return; } @@ -1101,7 +1103,7 @@ void GLESRenderEngine::drawLayersInternal( if (buffer == nullptr) { ALOGE("No output buffer provided. Aborting GPU composition."); - resultPromise->set_value({BAD_VALUE, base::unique_fd()}); + resultPromise->set_value(base::unexpected(BAD_VALUE)); return; } @@ -1130,7 +1132,7 @@ void GLESRenderEngine::drawLayersInternal( ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", buffer->getBuffer()->handle); checkErrors(); - resultPromise->set_value({fbo->getStatus(), base::unique_fd()}); + resultPromise->set_value(base::unexpected(fbo->getStatus())); return; } setViewportAndProjection(display.physicalDisplay, display.clip); @@ -1142,7 +1144,7 @@ void GLESRenderEngine::drawLayersInternal( ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", buffer->getBuffer()->handle); checkErrors(); - resultPromise->set_value({status, base::unique_fd()}); + resultPromise->set_value(base::unexpected(status)); return; } } @@ -1176,7 +1178,7 @@ void GLESRenderEngine::drawLayersInternal( ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", buffer->getBuffer()->handle); checkErrors("Can't render first blur pass"); - resultPromise->set_value({status, base::unique_fd()}); + resultPromise->set_value(base::unexpected(status)); return; } @@ -1199,7 +1201,7 @@ void GLESRenderEngine::drawLayersInternal( ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", buffer->getBuffer()->handle); checkErrors("Can't bind native framebuffer"); - resultPromise->set_value({status, base::unique_fd()}); + resultPromise->set_value(base::unexpected(status)); return; } @@ -1208,7 +1210,7 @@ void GLESRenderEngine::drawLayersInternal( ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", buffer->getBuffer()->handle); checkErrors("Can't render blur filter"); - resultPromise->set_value({status, base::unique_fd()}); + resultPromise->set_value(base::unexpected(status)); return; } } @@ -1266,23 +1268,24 @@ void GLESRenderEngine::drawLayersInternal( const half3 solidColor = layer.source.solidColor; const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); + const float radius = + (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / + 2.0f; // Buffer sources will have a black solid color ignored in the shader, // so in that scenario the solid color passed here is arbitrary. - setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, - layer.geometry.roundedCornersRadius); + setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, radius); if (layer.disableBlending) { glDisable(GL_BLEND); } setSourceDataSpace(layer.sourceDataspace); if (layer.shadow.length > 0.0f) { - handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius, - layer.shadow); + handleShadow(layer.geometry.boundaries, radius, layer.shadow); } // We only want to do a special handling for rounded corners when having rounded corners // is the only reason it needs to turn on blending, otherwise, we handle it like the // usual way since it needs to turn on blending anyway. - else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { + else if (radius > 0.0 && color.a >= 1.0f && isOpaque) { handleRoundedCorners(display, layer, mesh); } else { drawMesh(mesh); @@ -1307,7 +1310,7 @@ void GLESRenderEngine::drawLayersInternal( checkErrors(); // Chances are, something illegal happened (either the caller passed // us bad parameters, or we messed up our shader generation). - resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)}); + resultPromise->set_value(base::unexpected(INVALID_OPERATION)); return; } mLastDrawFence = nullptr; @@ -1319,8 +1322,7 @@ void GLESRenderEngine::drawLayersInternal( mPriorResourcesCleaned = false; checkErrors(); - resultPromise->set_value({NO_ERROR, std::move(drawFence)}); - return; + resultPromise->set_value(sp<Fence>::make(std::move(drawFence))); } void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 1d7c2cafb5..1ee5cbaa3d 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -31,6 +31,7 @@ #include <renderengine/RenderEngine.h> #include <renderengine/private/Description.h> #include <sys/types.h> +#include <ui/FenceResult.h> #include "GLShadowTexture.h" #include "ImageManager.h" @@ -102,7 +103,7 @@ protected: EXCLUDES(mRenderingMutex); void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex); bool canSkipPostRenderCleanup() const override; - void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise, + void drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, diff --git a/libs/renderengine/include/renderengine/BorderRenderInfo.h b/libs/renderengine/include/renderengine/BorderRenderInfo.h new file mode 100644 index 0000000000..0ee6661f33 --- /dev/null +++ b/libs/renderengine/include/renderengine/BorderRenderInfo.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#pragma once +#include <math/mat4.h> +#include <ui/Region.h> + +namespace android { +namespace renderengine { + +struct BorderRenderInfo { + float width = 0; + half4 color; + Region combinedRegion; + + bool operator==(const BorderRenderInfo& rhs) const { + return (width == rhs.width && color == rhs.color && + combinedRegion.hasSameRects(rhs.combinedRegion)); + } +}; + +} // namespace renderengine +} // namespace android
\ No newline at end of file diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index 59ef991eec..25fe9f2d8e 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -22,6 +22,7 @@ #include <math/mat4.h> #include <renderengine/PrintMatrix.h> +#include <renderengine/BorderRenderInfo.h> #include <ui/GraphicTypes.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -79,6 +80,8 @@ struct DisplaySettings { // Configures the rendering intent of the output display. This is used for tonemapping. aidl::android::hardware::graphics::composer3::RenderIntent renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC; + + std::vector<renderengine::BorderRenderInfo> borderInfoList; }; static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) { @@ -90,7 +93,8 @@ static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& lhs.deviceHandlesColorTransform == rhs.deviceHandlesColorTransform && lhs.orientation == rhs.orientation && lhs.targetLuminanceNits == rhs.targetLuminanceNits && - lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent; + lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent && + lhs.borderInfoList == rhs.borderInfoList; } static const char* orientation_to_string(uint32_t orientation) { diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 154e5269f0..b3a617c04b 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -87,7 +87,7 @@ struct Geometry { // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be // in local layer coordinate space, so we have to take the layer transform into account when // walking up the tree. - float roundedCornersRadius = 0.0; + vec2 roundedCornersRadius = vec2(0.0f, 0.0f); // Rectangle within which corners will be rounded. FloatRect roundedCornersCrop = FloatRect(); @@ -258,7 +258,8 @@ static inline void PrintTo(const Geometry& settings, ::std::ostream* os) { PrintTo(settings.boundaries, os); *os << "\n .positionTransform = "; PrintMatrix(settings.positionTransform, os); - *os << "\n .roundedCornersRadius = " << settings.roundedCornersRadius; + *os << "\n .roundedCornersRadiusX = " << settings.roundedCornersRadius.x; + *os << "\n .roundedCornersRadiusY = " << settings.roundedCornersRadius.y; *os << "\n .roundedCornersCrop = "; PrintTo(settings.roundedCornersCrop, os); *os << "\n}"; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 3e7f69ce02..199392c160 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -18,6 +18,7 @@ #define SF_RENDERENGINE_H_ #include <android-base/unique_fd.h> +#include <ftl/future.h> #include <math/mat4.h> #include <renderengine/DisplaySettings.h> #include <renderengine/ExternalTexture.h> @@ -26,6 +27,7 @@ #include <renderengine/LayerSettings.h> #include <stdint.h> #include <sys/types.h> +#include <ui/FenceResult.h> #include <ui/GraphicTypes.h> #include <ui/Transform.h> @@ -68,7 +70,6 @@ class Image; class Mesh; class Texture; struct RenderEngineCreationArgs; -struct RenderEngineResult; namespace threaded { class RenderEngineThreaded; @@ -158,12 +159,13 @@ public: // parameter does nothing. // @param bufferFence Fence signalling that the buffer is ready to be drawn // to. - // @return A future object of RenderEngineResult struct indicating whether - // drawing was successful in async mode. - virtual std::future<RenderEngineResult> drawLayers( - const DisplaySettings& display, const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence); + // @return A future object of FenceResult indicating whether drawing was + // successful in async mode. + virtual ftl::Future<FenceResult> drawLayers(const DisplaySettings& display, + const std::vector<LayerSettings>& layers, + const std::shared_ptr<ExternalTexture>& buffer, + const bool useFramebufferCache, + base::unique_fd&& bufferFence); // Clean-up method that should be called on the main thread after the // drawFence returned by drawLayers fires. This method will free up @@ -237,7 +239,7 @@ protected: const RenderEngineType mRenderEngineType; virtual void drawLayersInternal( - const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise, + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) = 0; @@ -327,13 +329,6 @@ private: RenderEngine::RenderEngineType::SKIA_GL_THREADED; }; -struct RenderEngineResult { - // status indicates if drawing is successful - status_t status; - // drawFence will fire when the buffer has been drawn to and is ready to be examined. - base::unique_fd drawFence; -}; - } // namespace renderengine } // namespace android diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 248bd652c0..e3ce85dd07 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -48,14 +48,13 @@ public: MOCK_METHOD0(cleanupPostRender, void()); MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool()); MOCK_METHOD5(drawLayers, - std::future<RenderEngineResult>(const DisplaySettings&, - const std::vector<LayerSettings>&, - const std::shared_ptr<ExternalTexture>&, - const bool, base::unique_fd&&)); + ftl::Future<FenceResult>(const DisplaySettings&, const std::vector<LayerSettings>&, + const std::shared_ptr<ExternalTexture>&, const bool, + base::unique_fd&&)); MOCK_METHOD6(drawLayersInternal, - void(const std::shared_ptr<std::promise<RenderEngineResult>>&&, - const DisplaySettings&, const std::vector<LayerSettings>&, - const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&)); + void(const std::shared_ptr<std::promise<FenceResult>>&&, const DisplaySettings&, + const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, + const bool, base::unique_fd&&)); MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index f3064f3c69..f6b91839a3 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -66,7 +66,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin Geometry{ .boundaries = rect, .roundedCornersCrop = rect, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, }, // drawShadow ignores alpha .shadow = @@ -87,7 +87,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin Geometry{ .boundaries = smallerRect, .roundedCornersCrop = rect, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, }, .source = PixelSource{ @@ -148,7 +148,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting // In reduced shader mode, all non-zero round rect radii get the same code path. for (float roundedCornersRadius : {0.0f, 50.0f}) { // roundedCornersCrop is always set, but the radius triggers the behavior - layer.geometry.roundedCornersRadius = roundedCornersRadius; + layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius}; for (bool isOpaque : {true, false}) { layer.source.buffer.isOpaque = isOpaque; for (auto alpha : {half(.2f), half(1.0f)}) { @@ -181,7 +181,7 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting for (auto transform : {mat4(), kScaleAndTranslate}) { layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 50.f}) { - layer.geometry.roundedCornersRadius = roundedCornersRadius; + layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius}; auto layers = std::vector<LayerSettings>{layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); @@ -238,7 +238,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti .geometry = Geometry{ .boundaries = rect, - .roundedCornersRadius = 27, // larger than the 20 above. + .roundedCornersRadius = {27.f, 27.f}, .roundedCornersCrop = FloatRect(0, 0, displayRect.width(), displayRect.height()), }, @@ -275,9 +275,9 @@ static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySetti // larger than the layer bounds. .positionTransform = kFlip, .boundaries = rect, - .roundedCornersRadius = 94.2551, - .roundedCornersCrop = FloatRect( - -93.75, 0, displayRect.width() + 93.75, displayRect.height()), + .roundedCornersRadius = {94.2551f, 94.2551f}, + .roundedCornersCrop = FloatRect(-93.75, 0, displayRect.width() + 93.75, + displayRect.height()), }, .source = PixelSource{.buffer = Buffer{ @@ -307,10 +307,11 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett // the boundaries have to be smaller than the rounded crop so that // clipRRect is used instead of drawRRect .boundaries = small, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, .roundedCornersCrop = rect, }, - .source = PixelSource{ + .source = + PixelSource{ .solidColor = half3(0.f, 0.f, 0.f), }, .sourceDataspace = kDestDataSpace, @@ -363,8 +364,8 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; sp<GraphicBuffer> dstBuffer = - new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, - 1, usage, "primeShaderCache_dst"); + sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(), + PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst"); const auto dstTexture = std::make_shared<impl::ExternalTexture>(dstBuffer, *renderengine, @@ -374,8 +375,8 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { // something, but the details are not important. Make use of the shadow layer drawing step // to populate it. sp<GraphicBuffer> srcBuffer = - new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, - 1, usage, "drawImageLayer_src"); + sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(), + PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src"); const auto srcTexture = std::make_shared< impl::ExternalTexture>(srcBuffer, *renderengine, @@ -397,8 +398,9 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { // GRALLOC_USAGE_HW_TEXTURE should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE. const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; sp<GraphicBuffer> externalBuffer = - new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, - 1, usageExternal, "primeShaderCache_external"); + sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(), + PIXEL_FORMAT_RGBA_8888, 1, usageExternal, + "primeShaderCache_external"); const auto externalTexture = std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine, impl::ExternalTexture::Usage::READABLE); @@ -408,8 +410,9 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { // Another external texture with a different pixel format triggers useIsOpaqueWorkaround. // It doesn't have to be f16, but it can't be the usual 8888. sp<GraphicBuffer> f16ExternalBuffer = - new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_FP16, - 1, usageExternal, "primeShaderCache_external_f16"); + sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(), + PIXEL_FORMAT_RGBA_FP16, 1, usageExternal, + "primeShaderCache_external_f16"); // The F16 texture may not be usable on all devices, so check first that it was created. status_t error = f16ExternalBuffer->initCheck(); if (!error) { diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 97271cb32d..347b8b7856 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -24,24 +24,11 @@ #include <EGL/egl.h> #include <EGL/eglext.h> #include <GrContextOptions.h> -#include <SkCanvas.h> -#include <SkColorFilter.h> -#include <SkColorMatrix.h> -#include <SkColorSpace.h> -#include <SkGraphics.h> -#include <SkImage.h> -#include <SkImageFilters.h> -#include <SkRegion.h> -#include <SkShadowUtils.h> -#include <SkSurface.h> #include <android-base/stringprintf.h> #include <gl/GrGLInterface.h> #include <gui/TraceUtils.h> #include <sync/sync.h> -#include <ui/BlurRegion.h> -#include <ui/DataspaceUtils.h> #include <ui/DebugUtils.h> -#include <ui/GraphicBuffer.h> #include <utils/Trace.h> #include <cmath> @@ -50,25 +37,7 @@ #include <numeric> #include "../gl/GLExtensions.h" -#include "Cache.h" -#include "ColorSpaces.h" -#include "SkBlendMode.h" -#include "SkImageInfo.h" -#include "filters/BlurFilter.h" -#include "filters/GaussianBlurFilter.h" -#include "filters/KawaseBlurFilter.h" -#include "filters/LinearEffect.h" #include "log/log_main.h" -#include "skia/debug/SkiaCapture.h" -#include "skia/debug/SkiaMemoryReporter.h" -#include "skia/filters/StretchShaderFactory.h" -#include "system/graphics-base-v1.0.h" - -namespace { -// Debugging settings -static const bool kPrintLayerSettings = false; -static const bool kFlushAfterEveryLayer = kPrintLayerSettings; -} // namespace bool checkGlError(const char* op, int lineNumber); @@ -227,6 +196,7 @@ std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create( std::unique_ptr<SkiaGLRenderEngine> engine = std::make_unique<SkiaGLRenderEngine>(args, display, ctxt, placeholder, protectedContext, protectedPlaceholder); + engine->ensureGrContextsCreated(); ALOGI("OpenGL ES informations:"); ALOGI("vendor : %s", extensions.getVendor()); @@ -239,11 +209,6 @@ std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create( return engine; } -std::future<void> SkiaGLRenderEngine::primeCache() { - Cache::primeShaderCache(this); - return {}; -} - EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) { status_t err; EGLConfig config; @@ -283,72 +248,20 @@ EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bo return config; } -sk_sp<SkData> SkiaGLRenderEngine::SkSLCacheMonitor::load(const SkData& key) { - // This "cache" does not actually cache anything. It just allows us to - // monitor Skia's internal cache. So this method always returns null. - return nullptr; -} - -void SkiaGLRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data, - const SkString& description) { - mShadersCachedSinceLastCall++; - mTotalShadersCompiled++; - ATRACE_FORMAT("SF cache: %i shaders", mTotalShadersCompiled); -} - -int SkiaGLRenderEngine::reportShadersCompiled() { - return mSkSLCacheMonitor.totalShadersCompiled(); -} - SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, EGLSurface protectedPlaceholder) - : SkiaRenderEngine(args.renderEngineType), + : SkiaRenderEngine(args.renderEngineType, + static_cast<PixelFormat>(args.pixelFormat), + args.useColorManagement, args.supportsBackgroundBlur), mEGLDisplay(display), mEGLContext(ctxt), mPlaceholderSurface(placeholder), mProtectedEGLContext(protectedContext), - mProtectedPlaceholderSurface(protectedPlaceholder), - mDefaultPixelFormat(static_cast<PixelFormat>(args.pixelFormat)), - mUseColorManagement(args.useColorManagement) { - sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface()); - LOG_ALWAYS_FATAL_IF(!glInterface.get()); - - GrContextOptions options; - options.fDisableDriverCorrectnessWorkarounds = true; - options.fDisableDistanceFieldPaths = true; - options.fReducedShaderVariations = true; - options.fPersistentCache = &mSkSLCacheMonitor; - mGrContext = GrDirectContext::MakeGL(glInterface, options); - if (supportsProtectedContent()) { - useProtectedContext(true); - mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options); - useProtectedContext(false); - } - - if (args.supportsBackgroundBlur) { - ALOGD("Background Blurs Enabled"); - mBlurFilter = new KawaseBlurFilter(); - } - mCapture = std::make_unique<SkiaCapture>(); -} + mProtectedPlaceholderSurface(protectedPlaceholder) { } SkiaGLRenderEngine::~SkiaGLRenderEngine() { - std::lock_guard<std::mutex> lock(mRenderingMutex); - if (mBlurFilter) { - delete mBlurFilter; - } - - mCapture = nullptr; - - mGrContext->flushAndSubmit(true); - mGrContext->abandonContext(); - - if (mProtectedGrContext) { - mProtectedGrContext->flushAndSubmit(true); - mProtectedGrContext->abandonContext(); - } - + finishRenderingAndAbandonContext(); if (mPlaceholderSurface != EGL_NO_SURFACE) { eglDestroySurface(mEGLDisplay, mPlaceholderSurface); } @@ -366,71 +279,69 @@ SkiaGLRenderEngine::~SkiaGLRenderEngine() { eglReleaseThread(); } -bool SkiaGLRenderEngine::supportsProtectedContent() const { - return mProtectedEGLContext != EGL_NO_CONTEXT; -} +SkiaRenderEngine::Contexts SkiaGLRenderEngine::createDirectContexts( + const GrContextOptions& options) { -GrDirectContext* SkiaGLRenderEngine::getActiveGrContext() const { - return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get(); -} + LOG_ALWAYS_FATAL_IF(isProtected(), + "Cannot setup contexts while already in protected mode"); -void SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) { - if (useProtectedContext == mInProtectedContext || - (useProtectedContext && !supportsProtectedContent())) { - return; - } + sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface(); - // release any scratch resources before switching into a new mode - if (getActiveGrContext()) { - getActiveGrContext()->purgeUnlockedResources(true); - } + LOG_ALWAYS_FATAL_IF(!glInterface.get(), "GrGLMakeNativeInterface() failed"); - const EGLSurface surface = - useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface; - const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext; - - if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) { - mInProtectedContext = useProtectedContext; - // given that we are sharing the same thread between two GrContexts we need to - // make sure that the thread state is reset when switching between the two. - if (getActiveGrContext()) { - getActiveGrContext()->resetContext(); - } + SkiaRenderEngine::Contexts contexts; + contexts.first = GrDirectContext::MakeGL(glInterface, options); + if (supportsProtectedContentImpl()) { + useProtectedContextImpl(GrProtected::kYes); + contexts.second = GrDirectContext::MakeGL(glInterface, options); + useProtectedContextImpl(GrProtected::kNo); } -} -base::unique_fd SkiaGLRenderEngine::flush() { - ATRACE_CALL(); - if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) { - return base::unique_fd(); - } - - EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); - if (sync == EGL_NO_SYNC_KHR) { - ALOGW("failed to create EGL native fence sync: %#x", eglGetError()); - return base::unique_fd(); - } + return contexts; +} - // native fence fd will not be populated until flush() is done. - glFlush(); +bool SkiaGLRenderEngine::supportsProtectedContentImpl() const { + return mProtectedEGLContext != EGL_NO_CONTEXT; +} - // get the fence fd - base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync)); - eglDestroySyncKHR(mEGLDisplay, sync); - if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - ALOGW("failed to dup EGL native fence sync: %#x", eglGetError()); - } +bool SkiaGLRenderEngine::useProtectedContextImpl(GrProtected isProtected) { + const EGLSurface surface = + (isProtected == GrProtected::kYes) ? + mProtectedPlaceholderSurface : mPlaceholderSurface; + const EGLContext context = (isProtected == GrProtected::kYes) ? + mProtectedEGLContext : mEGLContext; - return fenceFd; + return eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE; } -void SkiaGLRenderEngine::waitFence(base::borrowed_fd fenceFd) { +void SkiaGLRenderEngine::waitFence(GrDirectContext*, base::borrowed_fd fenceFd) { if (fenceFd.get() >= 0 && !waitGpuFence(fenceFd)) { ATRACE_NAME("SkiaGLRenderEngine::waitFence"); sync_wait(fenceFd.get(), -1); } } +base::unique_fd SkiaGLRenderEngine::flushAndSubmit(GrDirectContext* grContext) { + base::unique_fd drawFence = flush(); + + bool requireSync = drawFence.get() < 0; + if (requireSync) { + ATRACE_BEGIN("Submit(sync=true)"); + } else { + ATRACE_BEGIN("Submit(sync=false)"); + } + bool success = grContext->submit(requireSync); + ATRACE_END(); + if (!success) { + ALOGE("Failed to flush RenderEngine commands"); + // Chances are, something illegal happened (Skia's internal GPU object + // doesn't exist, or the context was abandoned). + return drawFence; + } + + return drawFence; +} + bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) { if (!gl::GLExtensions::getInstance().hasNativeFenceSync() || !gl::GLExtensions::getInstance().hasWaitSync()) { @@ -466,960 +377,29 @@ bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) { return true; } -static float toDegrees(uint32_t transform) { - switch (transform) { - case ui::Transform::ROT_90: - return 90.0; - case ui::Transform::ROT_180: - return 180.0; - case ui::Transform::ROT_270: - return 270.0; - default: - return 0.0; - } -} - -static SkColorMatrix toSkColorMatrix(const mat4& matrix) { - return SkColorMatrix(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], 0, matrix[0][1], - matrix[1][1], matrix[2][1], matrix[3][1], 0, matrix[0][2], matrix[1][2], - matrix[2][2], matrix[3][2], 0, matrix[0][3], matrix[1][3], matrix[2][3], - matrix[3][3], 0); -} - -static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destinationDataspace) { - int64_t sourceTransfer = sourceDataspace & HAL_DATASPACE_TRANSFER_MASK; - int64_t destTransfer = destinationDataspace & HAL_DATASPACE_TRANSFER_MASK; - - // Treat unsupported dataspaces as srgb - if (destTransfer != HAL_DATASPACE_TRANSFER_LINEAR && - destTransfer != HAL_DATASPACE_TRANSFER_HLG && - destTransfer != HAL_DATASPACE_TRANSFER_ST2084) { - destTransfer = HAL_DATASPACE_TRANSFER_SRGB; - } - - if (sourceTransfer != HAL_DATASPACE_TRANSFER_LINEAR && - sourceTransfer != HAL_DATASPACE_TRANSFER_HLG && - sourceTransfer != HAL_DATASPACE_TRANSFER_ST2084) { - sourceTransfer = HAL_DATASPACE_TRANSFER_SRGB; - } - - const bool isSourceLinear = sourceTransfer == HAL_DATASPACE_TRANSFER_LINEAR; - const bool isSourceSRGB = sourceTransfer == HAL_DATASPACE_TRANSFER_SRGB; - const bool isDestLinear = destTransfer == HAL_DATASPACE_TRANSFER_LINEAR; - const bool isDestSRGB = destTransfer == HAL_DATASPACE_TRANSFER_SRGB; - - return !(isSourceLinear && isDestSRGB) && !(isSourceSRGB && isDestLinear) && - sourceTransfer != destTransfer; -} - -void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, - bool isRenderable) { - // Only run this if RE is running on its own thread. This way the access to GL - // operations is guaranteed to be happening on the same thread. - if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) { - return; - } - // We currently don't attempt to map a buffer if the buffer contains protected content - // because GPU resources for protected buffers is much more limited. - const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; - if (isProtectedBuffer) { - return; - } - ATRACE_CALL(); - - // If we were to support caching protected buffers then we will need to switch the - // currently bound context if we are not already using the protected context (and subsequently - // switch back after the buffer is cached). However, for non-protected content we can bind - // the texture in either GL context because they are initialized with the same share_context - // which allows the texture state to be shared between them. - auto grContext = getActiveGrContext(); - auto& cache = mTextureCache; - - std::lock_guard<std::mutex> lock(mRenderingMutex); - mGraphicBufferExternalRefs[buffer->getId()]++; - - if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) { - std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = - std::make_shared<AutoBackendTexture::LocalRef>(grContext, - buffer->toAHardwareBuffer(), - isRenderable, mTextureCleanupMgr); - cache.insert({buffer->getId(), imageTextureRef}); - } -} - -void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { - ATRACE_CALL(); - std::lock_guard<std::mutex> lock(mRenderingMutex); - if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId()); - iter != mGraphicBufferExternalRefs.end()) { - if (iter->second == 0) { - ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64 - "> from RenderEngine texture, but the " - "ref count was already zero!", - buffer->getId()); - mGraphicBufferExternalRefs.erase(buffer->getId()); - return; - } - - iter->second--; - - // Swap contexts if needed prior to deleting this buffer - // See Issue 1 of - // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_protected_content.txt: even - // when a protected context and an unprotected context are part of the same share group, - // protected surfaces may not be accessed by an unprotected context, implying that protected - // surfaces may only be freed when a protected context is active. - const bool inProtected = mInProtectedContext; - useProtectedContext(buffer->getUsage() & GRALLOC_USAGE_PROTECTED); - - if (iter->second == 0) { - mTextureCache.erase(buffer->getId()); - mGraphicBufferExternalRefs.erase(buffer->getId()); - } - - // Swap back to the previous context so that cached values of isProtected in SurfaceFlinger - // are up-to-date. - if (inProtected != mInProtectedContext) { - useProtectedContext(inProtected); - } - } -} - -bool SkiaGLRenderEngine::canSkipPostRenderCleanup() const { - std::lock_guard<std::mutex> lock(mRenderingMutex); - return mTextureCleanupMgr.isEmpty(); -} - -void SkiaGLRenderEngine::cleanupPostRender() { +base::unique_fd SkiaGLRenderEngine::flush() { ATRACE_CALL(); - std::lock_guard<std::mutex> lock(mRenderingMutex); - mTextureCleanupMgr.cleanup(); -} - -// Helper class intended to be used on the stack to ensure that texture cleanup -// is deferred until after this class goes out of scope. -class DeferTextureCleanup final { -public: - DeferTextureCleanup(AutoBackendTexture::CleanupManager& mgr) : mMgr(mgr) { - mMgr.setDeferredStatus(true); - } - ~DeferTextureCleanup() { mMgr.setDeferredStatus(false); } - -private: - DISALLOW_COPY_AND_ASSIGN(DeferTextureCleanup); - AutoBackendTexture::CleanupManager& mMgr; -}; - -sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader( - const RuntimeEffectShaderParameters& parameters) { - // The given surface will be stretched by HWUI via matrix transformation - // which gets similar results for most surfaces - // Determine later on if we need to leverage the stertch shader within - // surface flinger - const auto& stretchEffect = parameters.layer.stretchEffect; - auto shader = parameters.shader; - if (stretchEffect.hasEffect()) { - const auto targetBuffer = parameters.layer.source.buffer.buffer; - const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; - if (graphicBuffer && parameters.shader) { - shader = mStretchShaderFactory.createSkShader(shader, stretchEffect); - } - } - - if (parameters.requiresLinearEffect) { - const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace - : ui::Dataspace::V0_SRGB_LINEAR; - const ui::Dataspace outputDataspace = mUseColorManagement - ? parameters.display.outputDataspace - : ui::Dataspace::V0_SRGB_LINEAR; - - auto effect = - shaders::LinearEffect{.inputDataspace = inputDataspace, - .outputDataspace = outputDataspace, - .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha}; - - auto effectIter = mRuntimeEffects.find(effect); - sk_sp<SkRuntimeEffect> runtimeEffect = nullptr; - if (effectIter == mRuntimeEffects.end()) { - runtimeEffect = buildRuntimeEffect(effect); - mRuntimeEffects.insert({effect, runtimeEffect}); - } else { - runtimeEffect = effectIter->second; - } - mat4 colorTransform = parameters.layer.colorTransform; - - colorTransform *= - mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio, - parameters.layerDimmingRatio, 1.f)); - const auto targetBuffer = parameters.layer.source.buffer.buffer; - const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; - const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr; - return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform, - parameters.display.maxLuminance, - parameters.display.currentLuminanceNits, - parameters.layer.source.buffer.maxLuminanceNits, - hardwareBuffer, parameters.display.renderIntent); - } - return parameters.shader; -} - -void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) { - if (CC_UNLIKELY(mCapture->isCaptureRunning())) { - // Record display settings when capture is running. - std::stringstream displaySettings; - PrintTo(display, &displaySettings); - // Store the DisplaySettings in additional information. - canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings", - SkData::MakeWithCString(displaySettings.str().c_str())); - } - - // Before doing any drawing, let's make sure that we'll start at the origin of the display. - // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual - // displays might have different scaling when compared to the physical screen. - - canvas->clipRect(getSkRect(display.physicalDisplay)); - canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top); - - const auto clipWidth = display.clip.width(); - const auto clipHeight = display.clip.height(); - auto rotatedClipWidth = clipWidth; - auto rotatedClipHeight = clipHeight; - // Scale is contingent on the rotation result. - if (display.orientation & ui::Transform::ROT_90) { - std::swap(rotatedClipWidth, rotatedClipHeight); - } - const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) / - static_cast<SkScalar>(rotatedClipWidth); - const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) / - static_cast<SkScalar>(rotatedClipHeight); - canvas->scale(scaleX, scaleY); - - // Canvas rotation is done by centering the clip window at the origin, rotating, translating - // back so that the top left corner of the clip is at (0, 0). - canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2); - canvas->rotate(toDegrees(display.orientation)); - canvas->translate(-clipWidth / 2, -clipHeight / 2); - canvas->translate(-display.clip.left, -display.clip.top); -} - -class AutoSaveRestore { -public: - AutoSaveRestore(SkCanvas* canvas) : mCanvas(canvas) { mSaveCount = canvas->save(); } - ~AutoSaveRestore() { restore(); } - void replace(SkCanvas* canvas) { - mCanvas = canvas; - mSaveCount = canvas->save(); - } - void restore() { - if (mCanvas) { - mCanvas->restoreToCount(mSaveCount); - mCanvas = nullptr; - } - } - -private: - SkCanvas* mCanvas; - int mSaveCount; -}; - -static SkRRect getBlurRRect(const BlurRegion& region) { - const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom); - const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL), - SkVector::Make(region.cornerRadiusTR, region.cornerRadiusTR), - SkVector::Make(region.cornerRadiusBR, region.cornerRadiusBR), - SkVector::Make(region.cornerRadiusBL, region.cornerRadiusBL)}; - SkRRect roundedRect; - roundedRect.setRectRadii(rect, radii); - return roundedRect; -} - -// Arbitrary default margin which should be close enough to zero. -constexpr float kDefaultMargin = 0.0001f; -static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) { - LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!"); - return std::abs(expected - value) < margin; -} - -namespace { -template <typename T> -void logSettings(const T& t) { - std::stringstream stream; - PrintTo(t, &stream); - auto string = stream.str(); - size_t pos = 0; - // Perfetto ignores \n, so split up manually into separate ALOGD statements. - const size_t size = string.size(); - while (pos < size) { - const size_t end = std::min(string.find("\n", pos), size); - ALOGD("%s", string.substr(pos, end - pos).c_str()); - pos = end + 1; - } -} -} // namespace - -void SkiaGLRenderEngine::drawLayersInternal( - const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise, - const DisplaySettings& display, const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/, - base::unique_fd&& bufferFence) { - ATRACE_NAME("SkiaGL::drawLayers"); - - std::lock_guard<std::mutex> lock(mRenderingMutex); - if (layers.empty()) { - ALOGV("Drawing empty layer stack"); - resultPromise->set_value({NO_ERROR, base::unique_fd()}); - return; - } - - if (buffer == nullptr) { - ALOGE("No output buffer provided. Aborting GPU composition."); - resultPromise->set_value({BAD_VALUE, base::unique_fd()}); - return; - } - - validateOutputBufferUsage(buffer->getBuffer()); - - auto grContext = getActiveGrContext(); - auto& cache = mTextureCache; - - // any AutoBackendTexture deletions will now be deferred until cleanupPostRender is called - DeferTextureCleanup dtc(mTextureCleanupMgr); - - std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef; - if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) { - surfaceTextureRef = it->second; - } else { - surfaceTextureRef = - std::make_shared<AutoBackendTexture::LocalRef>(grContext, - buffer->getBuffer() - ->toAHardwareBuffer(), - true, mTextureCleanupMgr); - } - - // wait on the buffer to be ready to use prior to using it - waitFence(bufferFence); - - const ui::Dataspace dstDataspace = - mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR; - sk_sp<SkSurface> dstSurface = surfaceTextureRef->getOrCreateSurface(dstDataspace, grContext); - - SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get()); - if (dstCanvas == nullptr) { - ALOGE("Cannot acquire canvas from Skia."); - resultPromise->set_value({BAD_VALUE, base::unique_fd()}); - return; - } - - // setup color filter if necessary - sk_sp<SkColorFilter> displayColorTransform; - if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) { - displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)); - } - const bool ctModifiesAlpha = - displayColorTransform && !displayColorTransform->isAlphaUnchanged(); - - // Find the max layer white point to determine the max luminance of the scene... - const float maxLayerWhitePoint = std::transform_reduce( - layers.cbegin(), layers.cend(), 0.f, - [](float left, float right) { return std::max(left, right); }, - [&](const auto& l) { return l.whitePointNits; }); - - // ...and compute the dimming ratio if dimming is requested - const float displayDimmingRatio = display.targetLuminanceNits > 0.f && - maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint - ? maxLayerWhitePoint / display.targetLuminanceNits - : 1.f; - - // Find if any layers have requested blur, we'll use that info to decide when to render to an - // offscreen buffer and when to render to the native buffer. - sk_sp<SkSurface> activeSurface(dstSurface); - SkCanvas* canvas = dstCanvas; - SkiaCapture::OffscreenState offscreenCaptureState; - const LayerSettings* blurCompositionLayer = nullptr; - if (mBlurFilter) { - bool requiresCompositionLayer = false; - for (const auto& layer : layers) { - // if the layer doesn't have blur or it is not visible then continue - if (!layerHasBlur(layer, ctModifiesAlpha)) { - continue; - } - if (layer.backgroundBlurRadius > 0 && - layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) { - requiresCompositionLayer = true; - } - for (auto region : layer.blurRegions) { - if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) { - requiresCompositionLayer = true; - } - } - if (requiresCompositionLayer) { - activeSurface = dstSurface->makeSurface(dstSurface->imageInfo()); - canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState); - blurCompositionLayer = &layer; - break; - } - } - } - - AutoSaveRestore surfaceAutoSaveRestore(canvas); - // Clear the entire canvas with a transparent black to prevent ghost images. - canvas->clear(SK_ColorTRANSPARENT); - initCanvas(canvas, display); - - if (kPrintLayerSettings) { - logSettings(display); - } - for (const auto& layer : layers) { - ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str()); - - if (kPrintLayerSettings) { - logSettings(layer); - } - - sk_sp<SkImage> blurInput; - if (blurCompositionLayer == &layer) { - LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface); - LOG_ALWAYS_FATAL_IF(canvas == dstCanvas); - - // save a snapshot of the activeSurface to use as input to the blur shaders - blurInput = activeSurface->makeImageSnapshot(); - - // blit the offscreen framebuffer into the destination AHB, but only - // if there are blur regions. backgroundBlurRadius blurs the entire - // image below, so it can skip this step. - if (layer.blurRegions.size()) { - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); - if (CC_UNLIKELY(mCapture->isCaptureRunning())) { - uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState); - dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()), - String8::format("SurfaceID|%" PRId64, id).c_str(), - nullptr); - dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint); - } else { - activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint); - } - } - - // assign dstCanvas to canvas and ensure that the canvas state is up to date - canvas = dstCanvas; - surfaceAutoSaveRestore.replace(canvas); - initCanvas(canvas, display); - - LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() != - dstSurface->getCanvas()->getSaveCount()); - LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() != - dstSurface->getCanvas()->getTotalMatrix()); - - // assign dstSurface to activeSurface - activeSurface = dstSurface; - } - - SkAutoCanvasRestore layerAutoSaveRestore(canvas, true); - if (CC_UNLIKELY(mCapture->isCaptureRunning())) { - // Record the name of the layer if the capture is running. - std::stringstream layerSettings; - PrintTo(layer, &layerSettings); - // Store the LayerSettings in additional information. - canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(), - SkData::MakeWithCString(layerSettings.str().c_str())); - } - // Layers have a local transform that should be applied to them - canvas->concat(getSkM44(layer.geometry.positionTransform).asM33()); - - const auto [bounds, roundRectClip] = - getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop, - layer.geometry.roundedCornersRadius); - if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) { - std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs; - - // if multiple layers have blur, then we need to take a snapshot now because - // only the lowest layer will have blurImage populated earlier - if (!blurInput) { - blurInput = activeSurface->makeImageSnapshot(); - } - // rect to be blurred in the coordinate space of blurInput - const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect()); - - // if the clip needs to be applied then apply it now and make sure - // it is restored before we attempt to draw any shadows. - SkAutoCanvasRestore acr(canvas, true); - if (!roundRectClip.isEmpty()) { - canvas->clipRRect(roundRectClip, true); - } - - // TODO(b/182216890): Filter out empty layers earlier - if (blurRect.width() > 0 && blurRect.height() > 0) { - if (layer.backgroundBlurRadius > 0) { - ATRACE_NAME("BackgroundBlur"); - auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius, - blurInput, blurRect); - - cachedBlurs[layer.backgroundBlurRadius] = blurredImage; - - mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f, - blurRect, blurredImage, blurInput); - } - - canvas->concat(getSkM44(layer.blurRegionTransform).asM33()); - for (auto region : layer.blurRegions) { - if (cachedBlurs[region.blurRadius] == nullptr) { - ATRACE_NAME("BlurRegion"); - cachedBlurs[region.blurRadius] = - mBlurFilter->generate(grContext, region.blurRadius, blurInput, - blurRect); - } - - mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius, - region.alpha, blurRect, - cachedBlurs[region.blurRadius], blurInput); - } - } - } - - if (layer.shadow.length > 0) { - // This would require a new parameter/flag to SkShadowUtils::DrawShadow - LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow"); - - SkRRect shadowBounds, shadowClip; - if (layer.geometry.boundaries == layer.shadow.boundaries) { - shadowBounds = bounds; - shadowClip = roundRectClip; - } else { - std::tie(shadowBounds, shadowClip) = - getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop, - layer.geometry.roundedCornersRadius); - } - - // Technically, if bounds is a rect and roundRectClip is not empty, - // it means that the bounds and roundedCornersCrop were different - // enough that we should intersect them to find the proper shadow. - // In practice, this often happens when the two rectangles appear to - // not match due to rounding errors. Draw the rounded version, which - // looks more like the intent. - const auto& rrect = - shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds; - drawShadow(canvas, rrect, layer.shadow); - } - - const float layerDimmingRatio = layer.whitePointNits <= 0.f - ? displayDimmingRatio - : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio; - - const bool dimInLinearSpace = display.dimmingStage != - aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF; - - const bool requiresLinearEffect = layer.colorTransform != mat4() || - (mUseColorManagement && - needsToneMapping(layer.sourceDataspace, display.outputDataspace)) || - (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio)); - - // quick abort from drawing the remaining portion of the layer - if (layer.skipContentDraw || - (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending && - (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) { - continue; - } - - // If we need to map to linear space or color management is disabled, then mark the source - // image with the same colorspace as the destination surface so that Skia's color - // management is a no-op. - const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect) - ? dstDataspace - : layer.sourceDataspace; - - SkPaint paint; - if (layer.source.buffer.buffer) { - ATRACE_NAME("DrawImage"); - validateInputBufferUsage(layer.source.buffer.buffer->getBuffer()); - const auto& item = layer.source.buffer; - std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr; - - if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); - iter != cache.end()) { - imageTextureRef = iter->second; - } else { - // If we didn't find the image in the cache, then create a local ref but don't cache - // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if - // we didn't find anything in the cache then we intentionally did not cache this - // buffer's resources. - imageTextureRef = std::make_shared< - AutoBackendTexture::LocalRef>(grContext, - item.buffer->getBuffer()->toAHardwareBuffer(), - false, mTextureCleanupMgr); - } - - // if the layer's buffer has a fence, then we must must respect the fence prior to using - // the buffer. - if (layer.source.buffer.fence != nullptr) { - waitFence(layer.source.buffer.fence->get()); - } - - // isOpaque means we need to ignore the alpha in the image, - // replacing it with the alpha specified by the LayerSettings. See - // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean) - // The proper way to do this is to use an SkColorType that ignores - // alpha, like kRGB_888x_SkColorType, and that is used if the - // incoming image is kRGBA_8888_SkColorType. However, the incoming - // image may be kRGBA_F16_SkColorType, for which there is no RGBX - // SkColorType, or kRGBA_1010102_SkColorType, for which we have - // kRGB_101010x_SkColorType, but it is not yet supported as a source - // on the GPU. (Adding both is tracked in skbug.com/12048.) In the - // meantime, we'll use a workaround that works unless we need to do - // any color conversion. The workaround requires that we pretend the - // image is already premultiplied, so that we do not premultiply it - // before applying SkBlendMode::kPlus. - const bool useIsOpaqueWorkaround = item.isOpaque && - (imageTextureRef->colorType() == kRGBA_1010102_SkColorType || - imageTextureRef->colorType() == kRGBA_F16_SkColorType); - const auto alphaType = useIsOpaqueWorkaround ? kPremul_SkAlphaType - : item.isOpaque ? kOpaque_SkAlphaType - : item.usePremultipliedAlpha ? kPremul_SkAlphaType - : kUnpremul_SkAlphaType; - sk_sp<SkImage> image = imageTextureRef->makeImage(layerDataspace, alphaType, grContext); - - auto texMatrix = getSkM44(item.textureTransform).asM33(); - // textureTansform was intended to be passed directly into a shader, so when - // building the total matrix with the textureTransform we need to first - // normalize it, then apply the textureTransform, then scale back up. - texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height()); - texMatrix.postScale(image->width(), image->height()); - - SkMatrix matrix; - if (!texMatrix.invert(&matrix)) { - matrix = texMatrix; - } - // The shader does not respect the translation, so we add it to the texture - // transform for the SkImage. This will make sure that the correct layer contents - // are drawn in the correct part of the screen. - matrix.postTranslate(bounds.rect().fLeft, bounds.rect().fTop); - - sk_sp<SkShader> shader; - - if (layer.source.buffer.useTextureFiltering) { - shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, - SkSamplingOptions( - {SkFilterMode::kLinear, SkMipmapMode::kNone}), - &matrix); - } else { - shader = image->makeShader(SkSamplingOptions(), matrix); - } - - if (useIsOpaqueWorkaround) { - shader = SkShaders::Blend(SkBlendMode::kPlus, shader, - SkShaders::Color(SkColors::kBlack, - toSkColorSpace(layerDataspace))); - } - - paint.setShader(createRuntimeEffectShader( - RuntimeEffectShaderParameters{.shader = shader, - .layer = layer, - .display = display, - .undoPremultipliedAlpha = !item.isOpaque && - item.usePremultipliedAlpha, - .requiresLinearEffect = requiresLinearEffect, - .layerDimmingRatio = dimInLinearSpace - ? layerDimmingRatio - : 1.f})); - - // Turn on dithering when dimming beyond this (arbitrary) threshold... - static constexpr float kDimmingThreshold = 0.2f; - // ...or we're rendering an HDR layer down to an 8-bit target - // Most HDR standards require at least 10-bits of color depth for source content, so we - // can just extract the transfer function rather than dig into precise gralloc layout. - // Furthermore, we can assume that the only 8-bit target we support is RGBA8888. - const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) && - buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888; - if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) { - paint.setDither(true); - } - paint.setAlphaf(layer.alpha); - - if (imageTextureRef->colorType() == kAlpha_8_SkColorType) { - LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8"); - - // SysUI creates the alpha layer as a coverage layer, which is - // appropriate for the DPU. Use a color matrix to convert it to - // a mask. - // TODO (b/219525258): Handle input as a mask. - // - // The color matrix will convert A8 pixels with no alpha to - // black, as described by this vector. If the display handles - // the color transform, we need to invert it to find the color - // that will result in black after the DPU applies the transform. - SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a - if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) { - SkM44 colorSpaceMatrix = getSkM44(display.colorTransform); - if (colorSpaceMatrix.invert(&colorSpaceMatrix)) { - black = colorSpaceMatrix * black; - } else { - // We'll just have to use 0,0,0 as black, which should - // be close to correct. - ALOGI("Could not invert colorTransform!"); - } - } - SkColorMatrix colorMatrix(0, 0, 0, 0, black[0], - 0, 0, 0, 0, black[1], - 0, 0, 0, 0, black[2], - 0, 0, 0, -1, 1); - if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) { - // On the other hand, if the device doesn't handle it, we - // have to apply it ourselves. - colorMatrix.postConcat(toSkColorMatrix(display.colorTransform)); - } - paint.setColorFilter(SkColorFilters::Matrix(colorMatrix)); - } - } else { - ATRACE_NAME("DrawColor"); - const auto color = layer.source.solidColor; - sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r, - .fG = color.g, - .fB = color.b, - .fA = layer.alpha}, - toSkColorSpace(layerDataspace)); - paint.setShader(createRuntimeEffectShader( - RuntimeEffectShaderParameters{.shader = shader, - .layer = layer, - .display = display, - .undoPremultipliedAlpha = false, - .requiresLinearEffect = requiresLinearEffect, - .layerDimmingRatio = layerDimmingRatio})); - } - - if (layer.disableBlending) { - paint.setBlendMode(SkBlendMode::kSrc); - } - - // An A8 buffer will already have the proper color filter attached to - // its paint, including the displayColorTransform as needed. - if (!paint.getColorFilter()) { - if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) { - // If we don't dim in linear space, then when we gamma correct the dimming ratio we - // can assume a gamma 2.2 transfer function. - static constexpr float kInverseGamma22 = 1.f / 2.2f; - const auto gammaCorrectedDimmingRatio = - std::pow(layerDimmingRatio, kInverseGamma22); - auto dimmingMatrix = - mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio, - gammaCorrectedDimmingRatio, 1.f)); - - const auto colorFilter = - SkColorFilters::Matrix(toSkColorMatrix(std::move(dimmingMatrix))); - paint.setColorFilter(displayColorTransform - ? displayColorTransform->makeComposed(colorFilter) - : colorFilter); - } else { - paint.setColorFilter(displayColorTransform); - } - } - - if (!roundRectClip.isEmpty()) { - canvas->clipRRect(roundRectClip, true); - } - - if (!bounds.isRect()) { - paint.setAntiAlias(true); - canvas->drawRRect(bounds, paint); - } else { - canvas->drawRect(bounds.rect(), paint); - } - if (kFlushAfterEveryLayer) { - ATRACE_NAME("flush surface"); - activeSurface->flush(); - } - } - surfaceAutoSaveRestore.restore(); - mCapture->endCapture(); - { - ATRACE_NAME("flush surface"); - LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface); - activeSurface->flush(); - } - - base::unique_fd drawFence = flush(); - - // If flush failed or we don't support native fences, we need to force the - // gl command stream to be executed. - bool requireSync = drawFence.get() < 0; - if (requireSync) { - ATRACE_BEGIN("Submit(sync=true)"); - } else { - ATRACE_BEGIN("Submit(sync=false)"); - } - bool success = grContext->submit(requireSync); - ATRACE_END(); - if (!success) { - ALOGE("Failed to flush RenderEngine commands"); - // Chances are, something illegal happened (either the caller passed - // us bad parameters, or we messed up our shader generation). - resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)}); - return; - } - - // checkErrors(); - resultPromise->set_value({NO_ERROR, std::move(drawFence)}); - return; -} - -inline SkRect SkiaGLRenderEngine::getSkRect(const FloatRect& rect) { - return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom); -} - -inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) { - return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom); -} - -/** - * Verifies that common, simple bounds + clip combinations can be converted into - * a single RRect draw call returning true if possible. If true the radii parameter - * will be filled with the correct radii values that combined with bounds param will - * produce the insected roundRect. If false, the returned state of the radii param is undefined. - */ -static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, - const SkRect& insetCrop, float cornerRadius, - SkVector radii[4]) { - const bool leftEqual = bounds.fLeft == crop.fLeft; - const bool topEqual = bounds.fTop == crop.fTop; - const bool rightEqual = bounds.fRight == crop.fRight; - const bool bottomEqual = bounds.fBottom == crop.fBottom; - - // In the event that the corners of the bounds only partially align with the crop we - // need to ensure that the resulting shape can still be represented as a round rect. - // In particular the round rect implementation will scale the value of all corner radii - // if the sum of the radius along any edge is greater than the length of that edge. - // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap - const bool requiredWidth = bounds.width() > (cornerRadius * 2); - const bool requiredHeight = bounds.height() > (cornerRadius * 2); - if (!requiredWidth || !requiredHeight) { - return false; - } - - // Check each cropped corner to ensure that it exactly matches the crop or its corner is - // contained within the cropped shape and does not need rounded. - // compute the UpperLeft corner radius - if (leftEqual && topEqual) { - radii[0].set(cornerRadius, cornerRadius); - } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) || - (topEqual && bounds.fLeft >= insetCrop.fLeft)) { - radii[0].set(0, 0); - } else { - return false; - } - // compute the UpperRight corner radius - if (rightEqual && topEqual) { - radii[1].set(cornerRadius, cornerRadius); - } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) || - (topEqual && bounds.fRight <= insetCrop.fRight)) { - radii[1].set(0, 0); - } else { - return false; - } - // compute the BottomRight corner radius - if (rightEqual && bottomEqual) { - radii[2].set(cornerRadius, cornerRadius); - } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) || - (bottomEqual && bounds.fRight <= insetCrop.fRight)) { - radii[2].set(0, 0); - } else { - return false; - } - // compute the BottomLeft corner radius - if (leftEqual && bottomEqual) { - radii[3].set(cornerRadius, cornerRadius); - } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) || - (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) { - radii[3].set(0, 0); - } else { - return false; + if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) { + return base::unique_fd(); } - return true; -} - -inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const FloatRect& boundsRect, - const FloatRect& cropRect, - const float cornerRadius) { - const SkRect bounds = getSkRect(boundsRect); - const SkRect crop = getSkRect(cropRect); - - SkRRect clip; - if (cornerRadius > 0) { - // it the crop and the bounds are equivalent or there is no crop then we don't need a clip - if (bounds == crop || crop.isEmpty()) { - return {SkRRect::MakeRectXY(bounds, cornerRadius, cornerRadius), clip}; - } - - // This makes an effort to speed up common, simple bounds + clip combinations by - // converting them to a single RRect draw. It is possible there are other cases - // that can be converted. - if (crop.contains(bounds)) { - const auto insetCrop = crop.makeInset(cornerRadius, cornerRadius); - if (insetCrop.contains(bounds)) { - return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required - } - - SkVector radii[4]; - if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) { - SkRRect intersectionBounds; - intersectionBounds.setRectRadii(bounds, radii); - return {intersectionBounds, clip}; - } - } - - // we didn't hit any of our fast paths so set the clip to the cropRect - clip.setRectXY(crop, cornerRadius, cornerRadius); + EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + if (sync == EGL_NO_SYNC_KHR) { + ALOGW("failed to create EGL native fence sync: %#x", eglGetError()); + return base::unique_fd(); } - // if we hit this point then we either don't have rounded corners or we are going to rely - // on the clip to round the corners for us - return {SkRRect::MakeRect(bounds), clip}; -} + // native fence fd will not be populated until flush() is done. + glFlush(); -inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings& layer, - bool colorTransformModifiesAlpha) { - if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) { - // return false if the content is opaque and would therefore occlude the blur - const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque; - const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha; - return layer.skipContentDraw || !(opaqueContent && opaqueAlpha); + // get the fence fd + base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync)); + eglDestroySyncKHR(mEGLDisplay, sync); + if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + ALOGW("failed to dup EGL native fence sync: %#x", eglGetError()); } - return false; -} - -inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) { - return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255); -} - -inline SkM44 SkiaGLRenderEngine::getSkM44(const mat4& matrix) { - return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], - matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1], - matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2], - matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]); -} -inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) { - return SkPoint3::Make(vector.x, vector.y, vector.z); -} - -size_t SkiaGLRenderEngine::getMaxTextureSize() const { - return mGrContext->maxTextureSize(); -} - -size_t SkiaGLRenderEngine::getMaxViewportDims() const { - return mGrContext->maxRenderTargetSize(); -} - -void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRRect& casterRRect, - const ShadowSettings& settings) { - ATRACE_CALL(); - const float casterZ = settings.length / 2.0f; - const auto flags = - settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag; - - SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ), - getSkPoint3(settings.lightPos), settings.lightRadius, - getSkColor(settings.ambientColor), getSkColor(settings.spotColor), - flags); + return fenceFd; } EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config, @@ -1539,114 +519,14 @@ int SkiaGLRenderEngine::getContextPriority() { return value; } -void SkiaGLRenderEngine::onActiveDisplaySizeChanged(ui::Size size) { - // This cache multiplier was selected based on review of cache sizes relative - // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x), - // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a - // conservative default based on that analysis. - const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat); - const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER; - - // start by resizing the current context - getActiveGrContext()->setResourceCacheLimit(maxResourceBytes); - - // if it is possible to switch contexts then we will resize the other context - const bool originalProtectedState = mInProtectedContext; - useProtectedContext(!mInProtectedContext); - if (mInProtectedContext != originalProtectedState) { - getActiveGrContext()->setResourceCacheLimit(maxResourceBytes); - // reset back to the initial context that was active when this method was called - useProtectedContext(originalProtectedState); - } -} - -void SkiaGLRenderEngine::dump(std::string& result) { +void SkiaGLRenderEngine::appendBackendSpecificInfoToDump(std::string& result) { const gl::GLExtensions& extensions = gl::GLExtensions::getInstance(); - - StringAppendF(&result, "\n ------------RE-----------------\n"); + StringAppendF(&result, "\n ------------RE GLES------------\n"); StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion()); StringAppendF(&result, "%s\n", extensions.getEGLExtensions()); StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), extensions.getVersion()); StringAppendF(&result, "%s\n", extensions.getExtensions()); - StringAppendF(&result, "RenderEngine supports protected context: %d\n", - supportsProtectedContent()); - StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext); - StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n", - mSkSLCacheMonitor.shadersCachedSinceLastCall()); - - std::vector<ResourcePair> cpuResourceMap = { - {"skia/sk_resource_cache/bitmap_", "Bitmaps"}, - {"skia/sk_resource_cache/rrect-blur_", "Masks"}, - {"skia/sk_resource_cache/rects-blur_", "Masks"}, - {"skia/sk_resource_cache/tessellated", "Shadows"}, - {"skia", "Other"}, - }; - SkiaMemoryReporter cpuReporter(cpuResourceMap, false); - SkGraphics::DumpMemoryStatistics(&cpuReporter); - StringAppendF(&result, "Skia CPU Caches: "); - cpuReporter.logTotals(result); - cpuReporter.logOutput(result); - - { - std::lock_guard<std::mutex> lock(mRenderingMutex); - - std::vector<ResourcePair> gpuResourceMap = { - {"texture_renderbuffer", "Texture/RenderBuffer"}, - {"texture", "Texture"}, - {"gr_text_blob_cache", "Text"}, - {"skia", "Other"}, - }; - SkiaMemoryReporter gpuReporter(gpuResourceMap, true); - mGrContext->dumpMemoryStatistics(&gpuReporter); - StringAppendF(&result, "Skia's GPU Caches: "); - gpuReporter.logTotals(result); - gpuReporter.logOutput(result); - StringAppendF(&result, "Skia's Wrapped Objects:\n"); - gpuReporter.logOutput(result, true); - - StringAppendF(&result, "RenderEngine tracked buffers: %zu\n", - mGraphicBufferExternalRefs.size()); - StringAppendF(&result, "Dumping buffer ids...\n"); - for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) { - StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts); - } - StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n", - mTextureCache.size()); - StringAppendF(&result, "Dumping buffer ids...\n"); - // TODO(178539829): It would be nice to know which layer these are coming from and what - // the texture sizes are. - for (const auto& [id, unused] : mTextureCache) { - StringAppendF(&result, "- 0x%" PRIx64 "\n", id); - } - StringAppendF(&result, "\n"); - - SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true); - if (mProtectedGrContext) { - mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter); - } - StringAppendF(&result, "Skia's GPU Protected Caches: "); - gpuProtectedReporter.logTotals(result); - gpuProtectedReporter.logOutput(result); - StringAppendF(&result, "Skia's Protected Wrapped Objects:\n"); - gpuProtectedReporter.logOutput(result, true); - - StringAppendF(&result, "\n"); - StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size()); - for (const auto& [linearEffect, unused] : mRuntimeEffects) { - StringAppendF(&result, "- inputDataspace: %s\n", - dataspaceDetails( - static_cast<android_dataspace>(linearEffect.inputDataspace)) - .c_str()); - StringAppendF(&result, "- outputDataspace: %s\n", - dataspaceDetails( - static_cast<android_dataspace>(linearEffect.outputDataspace)) - .c_str()); - StringAppendF(&result, "undoPremultipliedAlpha: %s\n", - linearEffect.undoPremultipliedAlpha ? "true" : "false"); - } - } - StringAppendF(&result, "\n"); } } // namespace skia diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 5ef9944b14..4a37ffee83 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -41,6 +41,10 @@ #include "filters/LinearEffect.h" #include "filters/StretchShaderFactory.h" +class SkData; + +struct SkPoint3; + namespace android { namespace renderengine { namespace skia { @@ -51,33 +55,23 @@ public: SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, EGLSurface protectedPlaceholder); - ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex); + ~SkiaGLRenderEngine() override; - std::future<void> primeCache() override; - void cleanupPostRender() override; - void cleanFramebufferCache() override{}; int getContextPriority() override; - bool isProtected() const override { return mInProtectedContext; } - bool supportsProtectedContent() const override; - void useProtectedContext(bool useProtectedContext) override; - bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } - void onActiveDisplaySizeChanged(ui::Size size) override; - int reportShadersCompiled() override; protected: - void dump(std::string& result) override; - size_t getMaxTextureSize() const override; - size_t getMaxViewportDims() const override; - void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override; - void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override; - bool canSkipPostRenderCleanup() const override; - void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise, - const DisplaySettings& display, - const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer, - const bool useFramebufferCache, base::unique_fd&& bufferFence) override; + // Implementations of abstract SkiaRenderEngine functions specific to + // rendering backend + virtual SkiaRenderEngine::Contexts createDirectContexts(const GrContextOptions& options); + bool supportsProtectedContentImpl() const override; + bool useProtectedContextImpl(GrProtected isProtected) override; + void waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) override; + base::unique_fd flushAndSubmit(GrDirectContext* context) override; + void appendBackendSpecificInfoToDump(std::string& result) override; private: + bool waitGpuFence(base::borrowed_fd fenceFd); + base::unique_fd flush(); static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); static EGLContext createEglContext(EGLDisplay display, EGLConfig config, EGLContext shareContext, @@ -85,106 +79,14 @@ private: Protection protection); static std::optional<RenderEngine::ContextPriority> createContextPriority( const RenderEngineCreationArgs& args); - static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config, - int hwcFormat, Protection protection); - inline SkRect getSkRect(const FloatRect& layer); - inline SkRect getSkRect(const Rect& layer); - inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds, - const FloatRect& crop, float cornerRadius); - inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha); - inline SkColor getSkColor(const vec4& color); - inline SkM44 getSkM44(const mat4& matrix); - inline SkPoint3 getSkPoint3(const vec3& vector); - inline GrDirectContext* getActiveGrContext() const; - - base::unique_fd flush(); - // waitFence attempts to wait in the GPU, and if unable to waits on the CPU instead. - void waitFence(base::borrowed_fd fenceFd); - bool waitGpuFence(base::borrowed_fd fenceFd); - - void initCanvas(SkCanvas* canvas, const DisplaySettings& display); - void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect, - const ShadowSettings& shadowSettings); - - // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned. - // Otherwise it returns the input shader. - struct RuntimeEffectShaderParameters { - sk_sp<SkShader> shader; - const LayerSettings& layer; - const DisplaySettings& display; - bool undoPremultipliedAlpha; - bool requiresLinearEffect; - float layerDimmingRatio; - }; - sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&); + static EGLSurface createPlaceholderEglPbufferSurface( + EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection); EGLDisplay mEGLDisplay; EGLContext mEGLContext; EGLSurface mPlaceholderSurface; EGLContext mProtectedEGLContext; EGLSurface mProtectedPlaceholderSurface; - BlurFilter* mBlurFilter = nullptr; - - const PixelFormat mDefaultPixelFormat; - const bool mUseColorManagement; - - // Identifier used or various mappings of layers to various - // textures or shaders - using GraphicBufferId = uint64_t; - - // Number of external holders of ExternalTexture references, per GraphicBuffer ID. - std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs - GUARDED_BY(mRenderingMutex); - // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts. - std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache - GUARDED_BY(mRenderingMutex); - std::unordered_map<shaders::LinearEffect, sk_sp<SkRuntimeEffect>, shaders::LinearEffectHasher> - mRuntimeEffects; - AutoBackendTexture::CleanupManager mTextureCleanupMgr GUARDED_BY(mRenderingMutex); - - StretchShaderFactory mStretchShaderFactory; - // Mutex guarding rendering operations, so that: - // 1. GL operations aren't interleaved, and - // 2. Internal state related to rendering that is potentially modified by - // multiple threads is guaranteed thread-safe. - mutable std::mutex mRenderingMutex; - - sp<Fence> mLastDrawFence; - - // Graphics context used for creating surfaces and submitting commands - sk_sp<GrDirectContext> mGrContext; - // Same as above, but for protected content (eg. DRM) - sk_sp<GrDirectContext> mProtectedGrContext; - - bool mInProtectedContext = false; - // Object to capture commands send to Skia. - std::unique_ptr<SkiaCapture> mCapture; - - // Implements PersistentCache as a way to monitor what SkSL shaders Skia has - // cached. - class SkSLCacheMonitor : public GrContextOptions::PersistentCache { - public: - SkSLCacheMonitor() = default; - ~SkSLCacheMonitor() override = default; - - sk_sp<SkData> load(const SkData& key) override; - - void store(const SkData& key, const SkData& data, const SkString& description) override; - - int shadersCachedSinceLastCall() { - const int shadersCachedSinceLastCall = mShadersCachedSinceLastCall; - mShadersCachedSinceLastCall = 0; - return shadersCachedSinceLastCall; - } - - int totalShadersCompiled() const { return mTotalShadersCompiled; } - - private: - int mShadersCachedSinceLastCall = 0; - int mTotalShadersCompiled = 0; - }; - - SkSLCacheMonitor mSkSLCacheMonitor; }; } // namespace skia diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 1fb24f5041..b9aa5acd30 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -20,16 +20,1243 @@ #include "SkiaRenderEngine.h" +#include <GrBackendSemaphore.h> +#include <GrContextOptions.h> +#include <SkBlendMode.h> +#include <SkCanvas.h> +#include <SkColor.h> +#include <SkColorFilter.h> +#include <SkColorMatrix.h> +#include <SkColorSpace.h> +#include <SkData.h> +#include <SkGraphics.h> +#include <SkImage.h> +#include <SkImageFilters.h> +#include <SkImageInfo.h> +#include <SkM44.h> +#include <SkMatrix.h> +#include <SkPaint.h> +#include <SkPath.h> +#include <SkPoint.h> +#include <SkPoint3.h> +#include <SkRect.h> +#include <SkRefCnt.h> +#include <SkRegion.h> +#include <SkRRect.h> +#include <SkRuntimeEffect.h> +#include <SkSamplingOptions.h> +#include <SkScalar.h> +#include <SkShader.h> +#include <SkShadowUtils.h> +#include <SkString.h> +#include <SkSurface.h> +#include <SkTileMode.h> #include <src/core/SkTraceEventCommon.h> +#include <android-base/stringprintf.h> +#include <gui/TraceUtils.h> +#include <sync/sync.h> +#include <ui/BlurRegion.h> +#include <ui/DataspaceUtils.h> +#include <ui/DebugUtils.h> +#include <ui/GraphicBuffer.h> +#include <utils/Trace.h> + +#include <cmath> +#include <cstdint> +#include <memory> +#include <numeric> + +#include "Cache.h" +#include "ColorSpaces.h" +#include "filters/BlurFilter.h" +#include "filters/GaussianBlurFilter.h" +#include "filters/KawaseBlurFilter.h" +#include "filters/LinearEffect.h" +#include "log/log_main.h" +#include "skia/debug/SkiaCapture.h" +#include "skia/debug/SkiaMemoryReporter.h" +#include "skia/filters/StretchShaderFactory.h" +#include "system/graphics-base-v1.0.h" + +namespace { + +// Debugging settings +static const bool kPrintLayerSettings = false; +static const bool kFlushAfterEveryLayer = kPrintLayerSettings; + +} // namespace + +// Utility functions related to SkRect + +namespace { + +static inline SkRect getSkRect(const android::FloatRect& rect) { + return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom); +} + +static inline SkRect getSkRect(const android::Rect& rect) { + return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom); +} + +/** + * Verifies that common, simple bounds + clip combinations can be converted into + * a single RRect draw call returning true if possible. If true the radii parameter + * will be filled with the correct radii values that combined with bounds param will + * produce the insected roundRect. If false, the returned state of the radii param is undefined. + */ +static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, + const SkRect& insetCrop, const android::vec2& cornerRadius, + SkVector radii[4]) { + const bool leftEqual = bounds.fLeft == crop.fLeft; + const bool topEqual = bounds.fTop == crop.fTop; + const bool rightEqual = bounds.fRight == crop.fRight; + const bool bottomEqual = bounds.fBottom == crop.fBottom; + + // In the event that the corners of the bounds only partially align with the crop we + // need to ensure that the resulting shape can still be represented as a round rect. + // In particular the round rect implementation will scale the value of all corner radii + // if the sum of the radius along any edge is greater than the length of that edge. + // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap + const bool requiredWidth = bounds.width() > (cornerRadius.x * 2); + const bool requiredHeight = bounds.height() > (cornerRadius.y * 2); + if (!requiredWidth || !requiredHeight) { + return false; + } + + // Check each cropped corner to ensure that it exactly matches the crop or its corner is + // contained within the cropped shape and does not need rounded. + // compute the UpperLeft corner radius + if (leftEqual && topEqual) { + radii[0].set(cornerRadius.x, cornerRadius.y); + } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) || + (topEqual && bounds.fLeft >= insetCrop.fLeft)) { + radii[0].set(0, 0); + } else { + return false; + } + // compute the UpperRight corner radius + if (rightEqual && topEqual) { + radii[1].set(cornerRadius.x, cornerRadius.y); + } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) || + (topEqual && bounds.fRight <= insetCrop.fRight)) { + radii[1].set(0, 0); + } else { + return false; + } + // compute the BottomRight corner radius + if (rightEqual && bottomEqual) { + radii[2].set(cornerRadius.x, cornerRadius.y); + } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) || + (bottomEqual && bounds.fRight <= insetCrop.fRight)) { + radii[2].set(0, 0); + } else { + return false; + } + // compute the BottomLeft corner radius + if (leftEqual && bottomEqual) { + radii[3].set(cornerRadius.x, cornerRadius.y); + } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) || + (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) { + radii[3].set(0, 0); + } else { + return false; + } + + return true; +} + +static inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const android::FloatRect& boundsRect, + const android::FloatRect& cropRect, + const android::vec2& cornerRadius) { + const SkRect bounds = getSkRect(boundsRect); + const SkRect crop = getSkRect(cropRect); + + SkRRect clip; + if (cornerRadius.x > 0 && cornerRadius.y > 0) { + // it the crop and the bounds are equivalent or there is no crop then we don't need a clip + if (bounds == crop || crop.isEmpty()) { + return {SkRRect::MakeRectXY(bounds, cornerRadius.x, cornerRadius.y), clip}; + } + + // This makes an effort to speed up common, simple bounds + clip combinations by + // converting them to a single RRect draw. It is possible there are other cases + // that can be converted. + if (crop.contains(bounds)) { + const auto insetCrop = crop.makeInset(cornerRadius.x, cornerRadius.y); + if (insetCrop.contains(bounds)) { + return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required + } + + SkVector radii[4]; + if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) { + SkRRect intersectionBounds; + intersectionBounds.setRectRadii(bounds, radii); + return {intersectionBounds, clip}; + } + } + + // we didn't hit any of our fast paths so set the clip to the cropRect + clip.setRectXY(crop, cornerRadius.x, cornerRadius.y); + } + + // if we hit this point then we either don't have rounded corners or we are going to rely + // on the clip to round the corners for us + return {SkRRect::MakeRect(bounds), clip}; +} + +static inline bool layerHasBlur(const android::renderengine::LayerSettings& layer, + bool colorTransformModifiesAlpha) { + if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) { + // return false if the content is opaque and would therefore occlude the blur + const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque; + const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha; + return layer.skipContentDraw || !(opaqueContent && opaqueAlpha); + } + return false; +} + +static inline SkColor getSkColor(const android::vec4& color) { + return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255); +} + +static inline SkM44 getSkM44(const android::mat4& matrix) { + return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], + matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1], + matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2], + matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]); +} + +static inline SkPoint3 getSkPoint3(const android::vec3& vector) { + return SkPoint3::Make(vector.x, vector.y, vector.z); +} + +} // namespace namespace android { namespace renderengine { namespace skia { -SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {} + +using base::StringAppendF; + +std::future<void> SkiaRenderEngine::primeCache() { + Cache::primeShaderCache(this); + return {}; +} + +sk_sp<SkData> SkiaRenderEngine::SkSLCacheMonitor::load(const SkData& key) { + // This "cache" does not actually cache anything. It just allows us to + // monitor Skia's internal cache. So this method always returns null. + return nullptr; +} + +void SkiaRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data, + const SkString& description) { + mShadersCachedSinceLastCall++; + mTotalShadersCompiled++; + ATRACE_FORMAT("SF cache: %i shaders", mTotalShadersCompiled); +} + +int SkiaRenderEngine::reportShadersCompiled() { + return mSkSLCacheMonitor.totalShadersCompiled(); +} void SkiaRenderEngine::setEnableTracing(bool tracingEnabled) { SkAndroidFrameworkTraceUtil::setEnableTracing(tracingEnabled); } + +SkiaRenderEngine::SkiaRenderEngine( + RenderEngineType type, + PixelFormat pixelFormat, + bool useColorManagement, + bool supportsBackgroundBlur) : + RenderEngine(type), + mDefaultPixelFormat(pixelFormat), + mUseColorManagement(useColorManagement) { + if (supportsBackgroundBlur) { + ALOGD("Background Blurs Enabled"); + mBlurFilter = new KawaseBlurFilter(); + } + mCapture = std::make_unique<SkiaCapture>(); +} + +SkiaRenderEngine::~SkiaRenderEngine() { } + +// To be called from backend dtors. +void SkiaRenderEngine::finishRenderingAndAbandonContext() { + std::lock_guard<std::mutex> lock(mRenderingMutex); + + if (mBlurFilter) { + delete mBlurFilter; + } + + if (mGrContext) { + mGrContext->flushAndSubmit(true); + mGrContext->abandonContext(); + } + + if (mProtectedGrContext) { + mProtectedGrContext->flushAndSubmit(true); + mProtectedGrContext->abandonContext(); + } +} + +void SkiaRenderEngine::useProtectedContext(bool useProtectedContext) { + if (useProtectedContext == mInProtectedContext || + (useProtectedContext && !supportsProtectedContent())) { + return; + } + + // release any scratch resources before switching into a new mode + if (getActiveGrContext()) { + getActiveGrContext()->purgeUnlockedResources(true); + } + + // Backend-specific way to switch to protected context + if (useProtectedContextImpl( + useProtectedContext ? GrProtected::kYes : GrProtected::kNo)) { + mInProtectedContext = useProtectedContext; + // given that we are sharing the same thread between two GrContexts we need to + // make sure that the thread state is reset when switching between the two. + if (getActiveGrContext()) { + getActiveGrContext()->resetContext(); + } + } +} + +GrDirectContext* SkiaRenderEngine::getActiveGrContext() { + return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get(); +} + +static float toDegrees(uint32_t transform) { + switch (transform) { + case ui::Transform::ROT_90: + return 90.0; + case ui::Transform::ROT_180: + return 180.0; + case ui::Transform::ROT_270: + return 270.0; + default: + return 0.0; + } +} + +static SkColorMatrix toSkColorMatrix(const android::mat4& matrix) { + return SkColorMatrix(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], 0, matrix[0][1], + matrix[1][1], matrix[2][1], matrix[3][1], 0, matrix[0][2], matrix[1][2], + matrix[2][2], matrix[3][2], 0, matrix[0][3], matrix[1][3], matrix[2][3], + matrix[3][3], 0); +} + +static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destinationDataspace) { + int64_t sourceTransfer = sourceDataspace & HAL_DATASPACE_TRANSFER_MASK; + int64_t destTransfer = destinationDataspace & HAL_DATASPACE_TRANSFER_MASK; + + // Treat unsupported dataspaces as srgb + if (destTransfer != HAL_DATASPACE_TRANSFER_LINEAR && + destTransfer != HAL_DATASPACE_TRANSFER_HLG && + destTransfer != HAL_DATASPACE_TRANSFER_ST2084) { + destTransfer = HAL_DATASPACE_TRANSFER_SRGB; + } + + if (sourceTransfer != HAL_DATASPACE_TRANSFER_LINEAR && + sourceTransfer != HAL_DATASPACE_TRANSFER_HLG && + sourceTransfer != HAL_DATASPACE_TRANSFER_ST2084) { + sourceTransfer = HAL_DATASPACE_TRANSFER_SRGB; + } + + const bool isSourceLinear = sourceTransfer == HAL_DATASPACE_TRANSFER_LINEAR; + const bool isSourceSRGB = sourceTransfer == HAL_DATASPACE_TRANSFER_SRGB; + const bool isDestLinear = destTransfer == HAL_DATASPACE_TRANSFER_LINEAR; + const bool isDestSRGB = destTransfer == HAL_DATASPACE_TRANSFER_SRGB; + + return !(isSourceLinear && isDestSRGB) && !(isSourceSRGB && isDestLinear) && + sourceTransfer != destTransfer; +} + +void SkiaRenderEngine::ensureGrContextsCreated() { + if (mGrContext) { + return; + } + + GrContextOptions options; + options.fDisableDriverCorrectnessWorkarounds = true; + options.fDisableDistanceFieldPaths = true; + options.fReducedShaderVariations = true; + options.fPersistentCache = &mSkSLCacheMonitor; + std::tie(mGrContext, mProtectedGrContext) = createDirectContexts(options); +} + +void SkiaRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, + bool isRenderable) { + // Only run this if RE is running on its own thread. This way the access to GL + // operations is guaranteed to be happening on the same thread. + if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) { + return; + } + // We currently don't attempt to map a buffer if the buffer contains protected content + // because GPU resources for protected buffers is much more limited. + const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; + if (isProtectedBuffer) { + return; + } + ATRACE_CALL(); + + // If we were to support caching protected buffers then we will need to switch the + // currently bound context if we are not already using the protected context (and subsequently + // switch back after the buffer is cached). However, for non-protected content we can bind + // the texture in either GL context because they are initialized with the same share_context + // which allows the texture state to be shared between them. + auto grContext = getActiveGrContext(); + auto& cache = mTextureCache; + + std::lock_guard<std::mutex> lock(mRenderingMutex); + mGraphicBufferExternalRefs[buffer->getId()]++; + + if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) { + std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = + std::make_shared<AutoBackendTexture::LocalRef>(grContext, + buffer->toAHardwareBuffer(), + isRenderable, mTextureCleanupMgr); + cache.insert({buffer->getId(), imageTextureRef}); + } +} + +void SkiaRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { + ATRACE_CALL(); + std::lock_guard<std::mutex> lock(mRenderingMutex); + if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId()); + iter != mGraphicBufferExternalRefs.end()) { + if (iter->second == 0) { + ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64 + "> from RenderEngine texture, but the " + "ref count was already zero!", + buffer->getId()); + mGraphicBufferExternalRefs.erase(buffer->getId()); + return; + } + + iter->second--; + + // Swap contexts if needed prior to deleting this buffer + // See Issue 1 of + // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_protected_content.txt: even + // when a protected context and an unprotected context are part of the same share group, + // protected surfaces may not be accessed by an unprotected context, implying that protected + // surfaces may only be freed when a protected context is active. + const bool inProtected = mInProtectedContext; + useProtectedContext(buffer->getUsage() & GRALLOC_USAGE_PROTECTED); + + if (iter->second == 0) { + mTextureCache.erase(buffer->getId()); + mGraphicBufferExternalRefs.erase(buffer->getId()); + } + + // Swap back to the previous context so that cached values of isProtected in SurfaceFlinger + // are up-to-date. + if (inProtected != mInProtectedContext) { + useProtectedContext(inProtected); + } + } +} + +bool SkiaRenderEngine::canSkipPostRenderCleanup() const { + std::lock_guard<std::mutex> lock(mRenderingMutex); + return mTextureCleanupMgr.isEmpty(); +} + +void SkiaRenderEngine::cleanupPostRender() { + ATRACE_CALL(); + std::lock_guard<std::mutex> lock(mRenderingMutex); + mTextureCleanupMgr.cleanup(); +} + +sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( + const RuntimeEffectShaderParameters& parameters) { + // The given surface will be stretched by HWUI via matrix transformation + // which gets similar results for most surfaces + // Determine later on if we need to leverage the stertch shader within + // surface flinger + const auto& stretchEffect = parameters.layer.stretchEffect; + auto shader = parameters.shader; + if (stretchEffect.hasEffect()) { + const auto targetBuffer = parameters.layer.source.buffer.buffer; + const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; + if (graphicBuffer && parameters.shader) { + shader = mStretchShaderFactory.createSkShader(shader, stretchEffect); + } + } + + if (parameters.requiresLinearEffect) { + const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace + : ui::Dataspace::V0_SRGB_LINEAR; + const ui::Dataspace outputDataspace = mUseColorManagement + ? parameters.display.outputDataspace + : ui::Dataspace::V0_SRGB_LINEAR; + + auto effect = + shaders::LinearEffect{.inputDataspace = inputDataspace, + .outputDataspace = outputDataspace, + .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha}; + + auto effectIter = mRuntimeEffects.find(effect); + sk_sp<SkRuntimeEffect> runtimeEffect = nullptr; + if (effectIter == mRuntimeEffects.end()) { + runtimeEffect = buildRuntimeEffect(effect); + mRuntimeEffects.insert({effect, runtimeEffect}); + } else { + runtimeEffect = effectIter->second; + } + mat4 colorTransform = parameters.layer.colorTransform; + + colorTransform *= + mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio, + parameters.layerDimmingRatio, 1.f)); + const auto targetBuffer = parameters.layer.source.buffer.buffer; + const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; + const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr; + return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform, + parameters.display.maxLuminance, + parameters.display.currentLuminanceNits, + parameters.layer.source.buffer.maxLuminanceNits, + hardwareBuffer, parameters.display.renderIntent); + } + return parameters.shader; +} + +void SkiaRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) { + if (CC_UNLIKELY(mCapture->isCaptureRunning())) { + // Record display settings when capture is running. + std::stringstream displaySettings; + PrintTo(display, &displaySettings); + // Store the DisplaySettings in additional information. + canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings", + SkData::MakeWithCString(displaySettings.str().c_str())); + } + + // Before doing any drawing, let's make sure that we'll start at the origin of the display. + // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual + // displays might have different scaling when compared to the physical screen. + + canvas->clipRect(getSkRect(display.physicalDisplay)); + canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top); + + const auto clipWidth = display.clip.width(); + const auto clipHeight = display.clip.height(); + auto rotatedClipWidth = clipWidth; + auto rotatedClipHeight = clipHeight; + // Scale is contingent on the rotation result. + if (display.orientation & ui::Transform::ROT_90) { + std::swap(rotatedClipWidth, rotatedClipHeight); + } + const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) / + static_cast<SkScalar>(rotatedClipWidth); + const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) / + static_cast<SkScalar>(rotatedClipHeight); + canvas->scale(scaleX, scaleY); + + // Canvas rotation is done by centering the clip window at the origin, rotating, translating + // back so that the top left corner of the clip is at (0, 0). + canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2); + canvas->rotate(toDegrees(display.orientation)); + canvas->translate(-clipWidth / 2, -clipHeight / 2); + canvas->translate(-display.clip.left, -display.clip.top); +} + +class AutoSaveRestore { +public: + AutoSaveRestore(SkCanvas* canvas) : mCanvas(canvas) { mSaveCount = canvas->save(); } + ~AutoSaveRestore() { restore(); } + void replace(SkCanvas* canvas) { + mCanvas = canvas; + mSaveCount = canvas->save(); + } + void restore() { + if (mCanvas) { + mCanvas->restoreToCount(mSaveCount); + mCanvas = nullptr; + } + } + +private: + SkCanvas* mCanvas; + int mSaveCount; +}; + +static SkRRect getBlurRRect(const BlurRegion& region) { + const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom); + const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL), + SkVector::Make(region.cornerRadiusTR, region.cornerRadiusTR), + SkVector::Make(region.cornerRadiusBR, region.cornerRadiusBR), + SkVector::Make(region.cornerRadiusBL, region.cornerRadiusBL)}; + SkRRect roundedRect; + roundedRect.setRectRadii(rect, radii); + return roundedRect; +} + +// Arbitrary default margin which should be close enough to zero. +constexpr float kDefaultMargin = 0.0001f; +static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) { + LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!"); + return std::abs(expected - value) < margin; +} + +namespace { +template <typename T> +void logSettings(const T& t) { + std::stringstream stream; + PrintTo(t, &stream); + auto string = stream.str(); + size_t pos = 0; + // Perfetto ignores \n, so split up manually into separate ALOGD statements. + const size_t size = string.size(); + while (pos < size) { + const size_t end = std::min(string.find("\n", pos), size); + ALOGD("%s", string.substr(pos, end - pos).c_str()); + pos = end + 1; + } +} +} // namespace + +// Helper class intended to be used on the stack to ensure that texture cleanup +// is deferred until after this class goes out of scope. +class DeferTextureCleanup final { +public: + DeferTextureCleanup(AutoBackendTexture::CleanupManager& mgr) : mMgr(mgr) { + mMgr.setDeferredStatus(true); + } + ~DeferTextureCleanup() { mMgr.setDeferredStatus(false); } + +private: + DISALLOW_COPY_AND_ASSIGN(DeferTextureCleanup); + AutoBackendTexture::CleanupManager& mMgr; +}; + +void SkiaRenderEngine::drawLayersInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const DisplaySettings& display, const std::vector<LayerSettings>& layers, + const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/, + base::unique_fd&& bufferFence) { + ATRACE_NAME("SkiaGL::drawLayersInternal"); + + std::lock_guard<std::mutex> lock(mRenderingMutex); + + if (buffer == nullptr) { + ALOGE("No output buffer provided. Aborting GPU composition."); + resultPromise->set_value(base::unexpected(BAD_VALUE)); + return; + } + + validateOutputBufferUsage(buffer->getBuffer()); + + auto grContext = getActiveGrContext(); + auto& cache = mTextureCache; + + // any AutoBackendTexture deletions will now be deferred until cleanupPostRender is called + DeferTextureCleanup dtc(mTextureCleanupMgr); + + std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef; + if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) { + surfaceTextureRef = it->second; + } else { + surfaceTextureRef = + std::make_shared<AutoBackendTexture::LocalRef>(grContext, + buffer->getBuffer() + ->toAHardwareBuffer(), + true, mTextureCleanupMgr); + } + + // wait on the buffer to be ready to use prior to using it + waitFence(grContext, bufferFence); + + const ui::Dataspace dstDataspace = + mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR; + sk_sp<SkSurface> dstSurface = surfaceTextureRef->getOrCreateSurface(dstDataspace, grContext); + + SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get()); + if (dstCanvas == nullptr) { + ALOGE("Cannot acquire canvas from Skia."); + resultPromise->set_value(base::unexpected(BAD_VALUE)); + return; + } + + // setup color filter if necessary + sk_sp<SkColorFilter> displayColorTransform; + if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) { + displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)); + } + const bool ctModifiesAlpha = + displayColorTransform && !displayColorTransform->isAlphaUnchanged(); + + // Find the max layer white point to determine the max luminance of the scene... + const float maxLayerWhitePoint = std::transform_reduce( + layers.cbegin(), layers.cend(), 0.f, + [](float left, float right) { return std::max(left, right); }, + [&](const auto& l) { return l.whitePointNits; }); + + // ...and compute the dimming ratio if dimming is requested + const float displayDimmingRatio = display.targetLuminanceNits > 0.f && + maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint + ? maxLayerWhitePoint / display.targetLuminanceNits + : 1.f; + + // Find if any layers have requested blur, we'll use that info to decide when to render to an + // offscreen buffer and when to render to the native buffer. + sk_sp<SkSurface> activeSurface(dstSurface); + SkCanvas* canvas = dstCanvas; + SkiaCapture::OffscreenState offscreenCaptureState; + const LayerSettings* blurCompositionLayer = nullptr; + if (mBlurFilter) { + bool requiresCompositionLayer = false; + for (const auto& layer : layers) { + // if the layer doesn't have blur or it is not visible then continue + if (!layerHasBlur(layer, ctModifiesAlpha)) { + continue; + } + if (layer.backgroundBlurRadius > 0 && + layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) { + requiresCompositionLayer = true; + } + for (auto region : layer.blurRegions) { + if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) { + requiresCompositionLayer = true; + } + } + if (requiresCompositionLayer) { + activeSurface = dstSurface->makeSurface(dstSurface->imageInfo()); + canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState); + blurCompositionLayer = &layer; + break; + } + } + } + + AutoSaveRestore surfaceAutoSaveRestore(canvas); + // Clear the entire canvas with a transparent black to prevent ghost images. + canvas->clear(SK_ColorTRANSPARENT); + initCanvas(canvas, display); + + if (kPrintLayerSettings) { + logSettings(display); + } + for (const auto& layer : layers) { + ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str()); + + if (kPrintLayerSettings) { + logSettings(layer); + } + + sk_sp<SkImage> blurInput; + if (blurCompositionLayer == &layer) { + LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface); + LOG_ALWAYS_FATAL_IF(canvas == dstCanvas); + + // save a snapshot of the activeSurface to use as input to the blur shaders + blurInput = activeSurface->makeImageSnapshot(); + + // blit the offscreen framebuffer into the destination AHB, but only + // if there are blur regions. backgroundBlurRadius blurs the entire + // image below, so it can skip this step. + if (layer.blurRegions.size()) { + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); + if (CC_UNLIKELY(mCapture->isCaptureRunning())) { + uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState); + dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()), + String8::format("SurfaceID|%" PRId64, id).c_str(), + nullptr); + dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint); + } else { + activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint); + } + } + + // assign dstCanvas to canvas and ensure that the canvas state is up to date + canvas = dstCanvas; + surfaceAutoSaveRestore.replace(canvas); + initCanvas(canvas, display); + + LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() != + dstSurface->getCanvas()->getSaveCount()); + LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() != + dstSurface->getCanvas()->getTotalMatrix()); + + // assign dstSurface to activeSurface + activeSurface = dstSurface; + } + + SkAutoCanvasRestore layerAutoSaveRestore(canvas, true); + if (CC_UNLIKELY(mCapture->isCaptureRunning())) { + // Record the name of the layer if the capture is running. + std::stringstream layerSettings; + PrintTo(layer, &layerSettings); + // Store the LayerSettings in additional information. + canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(), + SkData::MakeWithCString(layerSettings.str().c_str())); + } + // Layers have a local transform that should be applied to them + canvas->concat(getSkM44(layer.geometry.positionTransform).asM33()); + + const auto [bounds, roundRectClip] = + getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop, + layer.geometry.roundedCornersRadius); + if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) { + std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs; + + // if multiple layers have blur, then we need to take a snapshot now because + // only the lowest layer will have blurImage populated earlier + if (!blurInput) { + blurInput = activeSurface->makeImageSnapshot(); + } + // rect to be blurred in the coordinate space of blurInput + const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect()); + + // if the clip needs to be applied then apply it now and make sure + // it is restored before we attempt to draw any shadows. + SkAutoCanvasRestore acr(canvas, true); + if (!roundRectClip.isEmpty()) { + canvas->clipRRect(roundRectClip, true); + } + + // TODO(b/182216890): Filter out empty layers earlier + if (blurRect.width() > 0 && blurRect.height() > 0) { + if (layer.backgroundBlurRadius > 0) { + ATRACE_NAME("BackgroundBlur"); + auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius, + blurInput, blurRect); + + cachedBlurs[layer.backgroundBlurRadius] = blurredImage; + + mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f, + blurRect, blurredImage, blurInput); + } + + canvas->concat(getSkM44(layer.blurRegionTransform).asM33()); + for (auto region : layer.blurRegions) { + if (cachedBlurs[region.blurRadius] == nullptr) { + ATRACE_NAME("BlurRegion"); + cachedBlurs[region.blurRadius] = + mBlurFilter->generate(grContext, region.blurRadius, blurInput, + blurRect); + } + + mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius, + region.alpha, blurRect, + cachedBlurs[region.blurRadius], blurInput); + } + } + } + + if (layer.shadow.length > 0) { + // This would require a new parameter/flag to SkShadowUtils::DrawShadow + LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow"); + + SkRRect shadowBounds, shadowClip; + if (layer.geometry.boundaries == layer.shadow.boundaries) { + shadowBounds = bounds; + shadowClip = roundRectClip; + } else { + std::tie(shadowBounds, shadowClip) = + getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop, + layer.geometry.roundedCornersRadius); + } + + // Technically, if bounds is a rect and roundRectClip is not empty, + // it means that the bounds and roundedCornersCrop were different + // enough that we should intersect them to find the proper shadow. + // In practice, this often happens when the two rectangles appear to + // not match due to rounding errors. Draw the rounded version, which + // looks more like the intent. + const auto& rrect = + shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds; + drawShadow(canvas, rrect, layer.shadow); + } + + const float layerDimmingRatio = layer.whitePointNits <= 0.f + ? displayDimmingRatio + : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio; + + const bool dimInLinearSpace = display.dimmingStage != + aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF; + + const bool requiresLinearEffect = layer.colorTransform != mat4() || + (mUseColorManagement && + needsToneMapping(layer.sourceDataspace, display.outputDataspace)) || + (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio)); + + // quick abort from drawing the remaining portion of the layer + if (layer.skipContentDraw || + (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending && + (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) { + continue; + } + + // If we need to map to linear space or color management is disabled, then mark the source + // image with the same colorspace as the destination surface so that Skia's color + // management is a no-op. + const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect) + ? dstDataspace + : layer.sourceDataspace; + + SkPaint paint; + if (layer.source.buffer.buffer) { + ATRACE_NAME("DrawImage"); + validateInputBufferUsage(layer.source.buffer.buffer->getBuffer()); + const auto& item = layer.source.buffer; + std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr; + + if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); + iter != cache.end()) { + imageTextureRef = iter->second; + } else { + // If we didn't find the image in the cache, then create a local ref but don't cache + // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if + // we didn't find anything in the cache then we intentionally did not cache this + // buffer's resources. + imageTextureRef = std::make_shared< + AutoBackendTexture::LocalRef>(grContext, + item.buffer->getBuffer()->toAHardwareBuffer(), + false, mTextureCleanupMgr); + } + + // if the layer's buffer has a fence, then we must must respect the fence prior to using + // the buffer. + if (layer.source.buffer.fence != nullptr) { + waitFence(grContext, layer.source.buffer.fence->get()); + } + + // isOpaque means we need to ignore the alpha in the image, + // replacing it with the alpha specified by the LayerSettings. See + // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean) + // The proper way to do this is to use an SkColorType that ignores + // alpha, like kRGB_888x_SkColorType, and that is used if the + // incoming image is kRGBA_8888_SkColorType. However, the incoming + // image may be kRGBA_F16_SkColorType, for which there is no RGBX + // SkColorType, or kRGBA_1010102_SkColorType, for which we have + // kRGB_101010x_SkColorType, but it is not yet supported as a source + // on the GPU. (Adding both is tracked in skbug.com/12048.) In the + // meantime, we'll use a workaround that works unless we need to do + // any color conversion. The workaround requires that we pretend the + // image is already premultiplied, so that we do not premultiply it + // before applying SkBlendMode::kPlus. + const bool useIsOpaqueWorkaround = item.isOpaque && + (imageTextureRef->colorType() == kRGBA_1010102_SkColorType || + imageTextureRef->colorType() == kRGBA_F16_SkColorType); + const auto alphaType = useIsOpaqueWorkaround ? kPremul_SkAlphaType + : item.isOpaque ? kOpaque_SkAlphaType + : item.usePremultipliedAlpha ? kPremul_SkAlphaType + : kUnpremul_SkAlphaType; + sk_sp<SkImage> image = imageTextureRef->makeImage(layerDataspace, alphaType, grContext); + + auto texMatrix = getSkM44(item.textureTransform).asM33(); + // textureTansform was intended to be passed directly into a shader, so when + // building the total matrix with the textureTransform we need to first + // normalize it, then apply the textureTransform, then scale back up. + texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height()); + texMatrix.postScale(image->width(), image->height()); + + SkMatrix matrix; + if (!texMatrix.invert(&matrix)) { + matrix = texMatrix; + } + // The shader does not respect the translation, so we add it to the texture + // transform for the SkImage. This will make sure that the correct layer contents + // are drawn in the correct part of the screen. + matrix.postTranslate(bounds.rect().fLeft, bounds.rect().fTop); + + sk_sp<SkShader> shader; + + if (layer.source.buffer.useTextureFiltering) { + shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, + SkSamplingOptions( + {SkFilterMode::kLinear, SkMipmapMode::kNone}), + &matrix); + } else { + shader = image->makeShader(SkSamplingOptions(), matrix); + } + + if (useIsOpaqueWorkaround) { + shader = SkShaders::Blend(SkBlendMode::kPlus, shader, + SkShaders::Color(SkColors::kBlack, + toSkColorSpace(layerDataspace))); + } + + paint.setShader(createRuntimeEffectShader( + RuntimeEffectShaderParameters{.shader = shader, + .layer = layer, + .display = display, + .undoPremultipliedAlpha = !item.isOpaque && + item.usePremultipliedAlpha, + .requiresLinearEffect = requiresLinearEffect, + .layerDimmingRatio = dimInLinearSpace + ? layerDimmingRatio + : 1.f})); + + // Turn on dithering when dimming beyond this (arbitrary) threshold... + static constexpr float kDimmingThreshold = 0.2f; + // ...or we're rendering an HDR layer down to an 8-bit target + // Most HDR standards require at least 10-bits of color depth for source content, so we + // can just extract the transfer function rather than dig into precise gralloc layout. + // Furthermore, we can assume that the only 8-bit target we support is RGBA8888. + const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) && + buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888; + if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) { + paint.setDither(true); + } + paint.setAlphaf(layer.alpha); + + if (imageTextureRef->colorType() == kAlpha_8_SkColorType) { + LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8"); + + // SysUI creates the alpha layer as a coverage layer, which is + // appropriate for the DPU. Use a color matrix to convert it to + // a mask. + // TODO (b/219525258): Handle input as a mask. + // + // The color matrix will convert A8 pixels with no alpha to + // black, as described by this vector. If the display handles + // the color transform, we need to invert it to find the color + // that will result in black after the DPU applies the transform. + SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a + if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) { + SkM44 colorSpaceMatrix = getSkM44(display.colorTransform); + if (colorSpaceMatrix.invert(&colorSpaceMatrix)) { + black = colorSpaceMatrix * black; + } else { + // We'll just have to use 0,0,0 as black, which should + // be close to correct. + ALOGI("Could not invert colorTransform!"); + } + } + SkColorMatrix colorMatrix(0, 0, 0, 0, black[0], + 0, 0, 0, 0, black[1], + 0, 0, 0, 0, black[2], + 0, 0, 0, -1, 1); + if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) { + // On the other hand, if the device doesn't handle it, we + // have to apply it ourselves. + colorMatrix.postConcat(toSkColorMatrix(display.colorTransform)); + } + paint.setColorFilter(SkColorFilters::Matrix(colorMatrix)); + } + } else { + ATRACE_NAME("DrawColor"); + const auto color = layer.source.solidColor; + sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r, + .fG = color.g, + .fB = color.b, + .fA = layer.alpha}, + toSkColorSpace(layerDataspace)); + paint.setShader(createRuntimeEffectShader( + RuntimeEffectShaderParameters{.shader = shader, + .layer = layer, + .display = display, + .undoPremultipliedAlpha = false, + .requiresLinearEffect = requiresLinearEffect, + .layerDimmingRatio = layerDimmingRatio})); + } + + if (layer.disableBlending) { + paint.setBlendMode(SkBlendMode::kSrc); + } + + // An A8 buffer will already have the proper color filter attached to + // its paint, including the displayColorTransform as needed. + if (!paint.getColorFilter()) { + if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) { + // If we don't dim in linear space, then when we gamma correct the dimming ratio we + // can assume a gamma 2.2 transfer function. + static constexpr float kInverseGamma22 = 1.f / 2.2f; + const auto gammaCorrectedDimmingRatio = + std::pow(layerDimmingRatio, kInverseGamma22); + auto dimmingMatrix = + mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio, + gammaCorrectedDimmingRatio, 1.f)); + + const auto colorFilter = + SkColorFilters::Matrix(toSkColorMatrix(std::move(dimmingMatrix))); + paint.setColorFilter(displayColorTransform + ? displayColorTransform->makeComposed(colorFilter) + : colorFilter); + } else { + paint.setColorFilter(displayColorTransform); + } + } + + if (!roundRectClip.isEmpty()) { + canvas->clipRRect(roundRectClip, true); + } + + if (!bounds.isRect()) { + paint.setAntiAlias(true); + canvas->drawRRect(bounds, paint); + } else { + canvas->drawRect(bounds.rect(), paint); + } + if (kFlushAfterEveryLayer) { + ATRACE_NAME("flush surface"); + activeSurface->flush(); + } + } + for (const auto& borderRenderInfo : display.borderInfoList) { + SkPaint p; + p.setColor(SkColor4f{borderRenderInfo.color.r, borderRenderInfo.color.g, + borderRenderInfo.color.b, borderRenderInfo.color.a}); + p.setAntiAlias(true); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(borderRenderInfo.width); + SkRegion sk_region; + SkPath path; + + // Construct a final SkRegion using Regions + for (const auto& r : borderRenderInfo.combinedRegion) { + sk_region.op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op); + } + + sk_region.getBoundaryPath(&path); + canvas->drawPath(path, p); + path.close(); + } + + surfaceAutoSaveRestore.restore(); + mCapture->endCapture(); + { + ATRACE_NAME("flush surface"); + LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface); + activeSurface->flush(); + } + + base::unique_fd drawFence = flushAndSubmit(grContext); + resultPromise->set_value(sp<Fence>::make(std::move(drawFence))); +} + +size_t SkiaRenderEngine::getMaxTextureSize() const { + return mGrContext->maxTextureSize(); +} + +size_t SkiaRenderEngine::getMaxViewportDims() const { + return mGrContext->maxRenderTargetSize(); +} + +void SkiaRenderEngine::drawShadow(SkCanvas* canvas, + const SkRRect& casterRRect, + const ShadowSettings& settings) { + ATRACE_CALL(); + const float casterZ = settings.length / 2.0f; + const auto flags = + settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag; + + SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ), + getSkPoint3(settings.lightPos), settings.lightRadius, + getSkColor(settings.ambientColor), getSkColor(settings.spotColor), + flags); +} + +void SkiaRenderEngine::onActiveDisplaySizeChanged(ui::Size size) { + // This cache multiplier was selected based on review of cache sizes relative + // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x), + // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a + // conservative default based on that analysis. + const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat); + const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER; + + // start by resizing the current context + getActiveGrContext()->setResourceCacheLimit(maxResourceBytes); + + // if it is possible to switch contexts then we will resize the other context + const bool originalProtectedState = mInProtectedContext; + useProtectedContext(!mInProtectedContext); + if (mInProtectedContext != originalProtectedState) { + getActiveGrContext()->setResourceCacheLimit(maxResourceBytes); + // reset back to the initial context that was active when this method was called + useProtectedContext(originalProtectedState); + } +} + +void SkiaRenderEngine::dump(std::string& result) { + // Dump for the specific backend (GLES or Vk) + appendBackendSpecificInfoToDump(result); + + // Info about protected content + StringAppendF(&result, "RenderEngine supports protected context: %d\n", + supportsProtectedContent()); + StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext); + StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n", + mSkSLCacheMonitor.shadersCachedSinceLastCall()); + + std::vector<ResourcePair> cpuResourceMap = { + {"skia/sk_resource_cache/bitmap_", "Bitmaps"}, + {"skia/sk_resource_cache/rrect-blur_", "Masks"}, + {"skia/sk_resource_cache/rects-blur_", "Masks"}, + {"skia/sk_resource_cache/tessellated", "Shadows"}, + {"skia", "Other"}, + }; + SkiaMemoryReporter cpuReporter(cpuResourceMap, false); + SkGraphics::DumpMemoryStatistics(&cpuReporter); + StringAppendF(&result, "Skia CPU Caches: "); + cpuReporter.logTotals(result); + cpuReporter.logOutput(result); + + { + std::lock_guard<std::mutex> lock(mRenderingMutex); + + std::vector<ResourcePair> gpuResourceMap = { + {"texture_renderbuffer", "Texture/RenderBuffer"}, + {"texture", "Texture"}, + {"gr_text_blob_cache", "Text"}, + {"skia", "Other"}, + }; + SkiaMemoryReporter gpuReporter(gpuResourceMap, true); + mGrContext->dumpMemoryStatistics(&gpuReporter); + StringAppendF(&result, "Skia's GPU Caches: "); + gpuReporter.logTotals(result); + gpuReporter.logOutput(result); + StringAppendF(&result, "Skia's Wrapped Objects:\n"); + gpuReporter.logOutput(result, true); + + StringAppendF(&result, "RenderEngine tracked buffers: %zu\n", + mGraphicBufferExternalRefs.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) { + StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts); + } + StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n", + mTextureCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + // TODO(178539829): It would be nice to know which layer these are coming from and what + // the texture sizes are. + for (const auto& [id, unused] : mTextureCache) { + StringAppendF(&result, "- 0x%" PRIx64 "\n", id); + } + StringAppendF(&result, "\n"); + + SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true); + if (mProtectedGrContext) { + mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter); + } + StringAppendF(&result, "Skia's GPU Protected Caches: "); + gpuProtectedReporter.logTotals(result); + gpuProtectedReporter.logOutput(result); + StringAppendF(&result, "Skia's Protected Wrapped Objects:\n"); + gpuProtectedReporter.logOutput(result, true); + + StringAppendF(&result, "\n"); + StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size()); + for (const auto& [linearEffect, unused] : mRuntimeEffects) { + StringAppendF(&result, "- inputDataspace: %s\n", + dataspaceDetails( + static_cast<android_dataspace>(linearEffect.inputDataspace)) + .c_str()); + StringAppendF(&result, "- outputDataspace: %s\n", + dataspaceDetails( + static_cast<android_dataspace>(linearEffect.outputDataspace)) + .c_str()); + StringAppendF(&result, "undoPremultipliedAlpha: %s\n", + linearEffect.undoPremultipliedAlpha ? "true" : "false"); + } + } + StringAppendF(&result, "\n"); +} + } // namespace skia } // namespace renderengine } // namespace android diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 160a18698e..e7c5b8f0ab 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -20,6 +20,31 @@ #include <renderengine/RenderEngine.h> #include <sys/types.h> +#include <GrBackendSemaphore.h> +#include <GrDirectContext.h> +#include <SkSurface.h> +#include <android-base/thread_annotations.h> +#include <renderengine/ExternalTexture.h> +#include <renderengine/RenderEngine.h> +#include <sys/types.h> + +#include <mutex> +#include <unordered_map> + +#include "AutoBackendTexture.h" +#include "GrContextOptions.h" +#include "SkImageInfo.h" +#include "SkiaRenderEngine.h" +#include "android-base/macros.h" +#include "debug/SkiaCapture.h" +#include "filters/BlurFilter.h" +#include "filters/LinearEffect.h" +#include "filters/StretchShaderFactory.h" + +class SkData; + +struct SkPoint3; + namespace android { namespace renderengine { @@ -31,35 +56,141 @@ namespace skia { class BlurFilter; -// TODO: Put common skia stuff here that can be shared between the GL & Vulkan backends -// Currently mostly just handles all the no-op / missing APIs class SkiaRenderEngine : public RenderEngine { public: static std::unique_ptr<SkiaRenderEngine> create(const RenderEngineCreationArgs& args); - SkiaRenderEngine(RenderEngineType type); - ~SkiaRenderEngine() override {} - - virtual std::future<void> primeCache() override { return {}; }; - virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{}; - virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{}; - virtual bool isProtected() const override { return false; } // mInProtectedContext; } - virtual bool supportsProtectedContent() const override { return false; }; - virtual int getContextPriority() override { return 0; } - virtual int reportShadersCompiled() { return 0; } - virtual void setEnableTracing(bool tracingEnabled) override; + SkiaRenderEngine(RenderEngineType type, + PixelFormat pixelFormat, + bool useColorManagement, + bool supportsBackgroundBlur); + ~SkiaRenderEngine() override; + + std::future<void> primeCache() override final; + void cleanupPostRender() override final; + void cleanFramebufferCache() override final{ } + bool isProtected() const override final{ return mInProtectedContext; } + bool supportsBackgroundBlur() override final { + return mBlurFilter != nullptr; + } + void onActiveDisplaySizeChanged(ui::Size size) override final; + int reportShadersCompiled(); + virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override final{}; + virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override final{}; + virtual void setEnableTracing(bool tracingEnabled) override final; + + void useProtectedContext(bool useProtectedContext) override; + bool supportsProtectedContent() const override { + return supportsProtectedContentImpl(); + } + void ensureGrContextsCreated(); protected: - virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/, - bool /*isRenderable*/) override = 0; - virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/) override = 0; - - virtual void drawLayersInternal( - const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise, - const DisplaySettings& display, const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence) override { - resultPromise->set_value({NO_ERROR, base::unique_fd()}); + // This is so backends can stop the generic rendering state first before + // cleaning up backend-specific state + void finishRenderingAndAbandonContext(); + + // Functions that a given backend (GLES, Vulkan) must implement + using Contexts = std::pair<sk_sp<GrDirectContext>, sk_sp<GrDirectContext>>; + virtual Contexts createDirectContexts(const GrContextOptions& options) = 0; + virtual bool supportsProtectedContentImpl() const = 0; + virtual bool useProtectedContextImpl(GrProtected isProtected) = 0; + virtual void waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) = 0; + virtual base::unique_fd flushAndSubmit(GrDirectContext* context) = 0; + virtual void appendBackendSpecificInfoToDump(std::string& result) = 0; + + size_t getMaxTextureSize() const override final; + size_t getMaxViewportDims() const override final; + GrDirectContext* getActiveGrContext(); + + // Implements PersistentCache as a way to monitor what SkSL shaders Skia has + // cached. + class SkSLCacheMonitor : public GrContextOptions::PersistentCache { + public: + SkSLCacheMonitor() = default; + ~SkSLCacheMonitor() override = default; + + sk_sp<SkData> load(const SkData& key) override; + + void store(const SkData& key, const SkData& data, const SkString& description) override; + + int shadersCachedSinceLastCall() { + const int shadersCachedSinceLastCall = mShadersCachedSinceLastCall; + mShadersCachedSinceLastCall = 0; + return shadersCachedSinceLastCall; + } + + int totalShadersCompiled() const { return mTotalShadersCompiled; } + + private: + int mShadersCachedSinceLastCall = 0; + int mTotalShadersCompiled = 0; + }; + +private: + void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, + bool isRenderable) override final; + void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override final; + bool canSkipPostRenderCleanup() const override final; + + void initCanvas(SkCanvas* canvas, const DisplaySettings& display); + void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect, + const ShadowSettings& shadowSettings); + void drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const DisplaySettings& display, + const std::vector<LayerSettings>& layers, + const std::shared_ptr<ExternalTexture>& buffer, + const bool useFramebufferCache, + base::unique_fd&& bufferFence) override final; + + void dump(std::string& result) override final; + + // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned. + // Otherwise it returns the input shader. + struct RuntimeEffectShaderParameters { + sk_sp<SkShader> shader; + const LayerSettings& layer; + const DisplaySettings& display; + bool undoPremultipliedAlpha; + bool requiresLinearEffect; + float layerDimmingRatio; }; + sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&); + + const PixelFormat mDefaultPixelFormat; + const bool mUseColorManagement; + + // Identifier used for various mappings of layers to various + // textures or shaders + using GraphicBufferId = uint64_t; + + // Number of external holders of ExternalTexture references, per GraphicBuffer ID. + std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs + GUARDED_BY(mRenderingMutex); + // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts. + std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache + GUARDED_BY(mRenderingMutex); + std::unordered_map<shaders::LinearEffect, sk_sp<SkRuntimeEffect>, shaders::LinearEffectHasher> + mRuntimeEffects; + AutoBackendTexture::CleanupManager mTextureCleanupMgr GUARDED_BY(mRenderingMutex); + + StretchShaderFactory mStretchShaderFactory; + + sp<Fence> mLastDrawFence; + BlurFilter* mBlurFilter = nullptr; + + // Object to capture commands send to Skia. + std::unique_ptr<SkiaCapture> mCapture; + + // Mutex guarding rendering operations, so that internal state related to + // rendering that is potentially modified by multiple threads is guaranteed thread-safe. + mutable std::mutex mRenderingMutex; + SkSLCacheMonitor mSkSLCacheMonitor; + + // Graphics context used for creating surfaces and submitting commands + sk_sp<GrDirectContext> mGrContext; + // Same as above, but for protected content (eg. DRM) + sk_sp<GrDirectContext> mProtectedGrContext; + bool mInProtectedContext = false; }; } // namespace skia diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp index 856fff4b01..b21b01cc1b 100644 --- a/libs/renderengine/skia/debug/SkiaCapture.cpp +++ b/libs/renderengine/skia/debug/SkiaCapture.cpp @@ -27,6 +27,9 @@ #include <utils/Trace.h> #include "CommonPool.h" +#include "SkCanvas.h" +#include "SkRect.h" +#include "SkTypeface.h" #include "src/utils/SkMultiPictureDocument.h" namespace android { diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h index f1946290ca..d65a579916 100644 --- a/libs/renderengine/skia/debug/SkiaCapture.h +++ b/libs/renderengine/skia/debug/SkiaCapture.h @@ -19,13 +19,15 @@ #include <SkDocument.h> #include <SkNWayCanvas.h> #include <SkPictureRecorder.h> +#include <SkRefCnt.h> +#include <SkStream.h> #include <SkSurface.h> +#include "tools/SkSharingProc.h" #include <chrono> #include <mutex> #include "CaptureTimer.h" -#include "tools/SkSharingProc.h" namespace android { namespace renderengine { diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp index 63cc02b7ea..2557ac9770 100644 --- a/libs/renderengine/skia/filters/BlurFilter.cpp +++ b/libs/renderengine/skia/filters/BlurFilter.cpp @@ -17,7 +17,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "BlurFilter.h" #include <SkCanvas.h> -#include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp index 55867a95cc..f3b6ab9885 100644 --- a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp +++ b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp @@ -18,7 +18,6 @@ #include "GaussianBlurFilter.h" #include <SkCanvas.h> -#include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index bfde06fd9a..e370c39a94 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -18,7 +18,6 @@ #include "KawaseBlurFilter.h" #include <SkCanvas.h> -#include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp index bbab792dba..6f328d738c 100644 --- a/libs/renderengine/tests/Android.bp +++ b/libs/renderengine/tests/Android.bp @@ -24,6 +24,7 @@ package { cc_test { name: "librenderengine_test", defaults: [ + "android.hardware.graphics.composer3-ndk_shared", "skia_deps", "surfaceflinger_defaults", ], @@ -49,7 +50,6 @@ cc_test { ], shared_libs: [ - "android.hardware.graphics.composer3-V1-ndk", "libbase", "libcutils", "libEGL", diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7c70a748b5..777d02f415 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -37,7 +37,6 @@ #include <condition_variable> #include <fstream> -#include "../gl/GLESRenderEngine.h" #include "../skia/SkiaGLRenderEngine.h" #include "../threaded/RenderEngineThreaded.h" @@ -108,73 +107,9 @@ public: virtual std::string name() = 0; virtual renderengine::RenderEngine::RenderEngineType type() = 0; virtual std::unique_ptr<renderengine::RenderEngine> createRenderEngine() = 0; - virtual std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() { - return nullptr; - } virtual bool useColorManagement() const = 0; }; -class GLESRenderEngineFactory : public RenderEngineFactory { -public: - std::string name() override { return "GLESRenderEngineFactory"; } - - renderengine::RenderEngine::RenderEngineType type() { - return renderengine::RenderEngine::RenderEngineType::GLES; - } - - std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override { - return createGLESRenderEngine(); - } - - std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() { - renderengine::RenderEngineCreationArgs reCreationArgs = - renderengine::RenderEngineCreationArgs::Builder() - .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888)) - .setImageCacheSize(1) - .setUseColorManagerment(false) - .setEnableProtectedContext(false) - .setPrecacheToneMapperShaderOnly(false) - .setSupportsBackgroundBlur(true) - .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) - .setRenderEngineType(type()) - .setUseColorManagerment(useColorManagement()) - .build(); - return renderengine::gl::GLESRenderEngine::create(reCreationArgs); - } - - bool useColorManagement() const override { return false; } -}; - -class GLESCMRenderEngineFactory : public RenderEngineFactory { -public: - std::string name() override { return "GLESCMRenderEngineFactory"; } - - renderengine::RenderEngine::RenderEngineType type() { - return renderengine::RenderEngine::RenderEngineType::GLES; - } - - std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override { - return createGLESRenderEngine(); - } - - std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() override { - renderengine::RenderEngineCreationArgs reCreationArgs = - renderengine::RenderEngineCreationArgs::Builder() - .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888)) - .setImageCacheSize(1) - .setEnableProtectedContext(false) - .setPrecacheToneMapperShaderOnly(false) - .setSupportsBackgroundBlur(true) - .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) - .setRenderEngineType(type()) - .setUseColorManagerment(useColorManagement()) - .build(); - return renderengine::gl::GLESRenderEngine::create(reCreationArgs); - } - - bool useColorManagement() const override { return true; } -}; - class SkiaGLESRenderEngineFactory : public RenderEngineFactory { public: std::string name() override { return "SkiaGLRenderEngineFactory"; } @@ -232,14 +167,14 @@ public: std::shared_ptr<renderengine::ExternalTexture> allocateDefaultBuffer() { return std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, - DEFAULT_DISPLAY_HEIGHT, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE, - "output"), + ExternalTexture>(sp<GraphicBuffer>:: + make(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "output"), *mRE, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage:: @@ -251,12 +186,12 @@ public: uint32_t height) { return std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(width, height, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_TEXTURE, - "input"), + ExternalTexture>(sp<GraphicBuffer>:: + make(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_TEXTURE, + "input"), *mRE, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage:: @@ -285,10 +220,12 @@ public: } std::shared_ptr<renderengine::ExternalTexture> allocateR8Buffer(int width, int height) { - auto buffer = new GraphicBuffer(width, height, android::PIXEL_FORMAT_R_8, 1, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_TEXTURE, - "r8"); + const auto kUsageFlags = + static_cast<uint64_t>(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_TEXTURE); + auto buffer = + sp<GraphicBuffer>::make(static_cast<uint32_t>(width), static_cast<uint32_t>(height), + android::PIXEL_FORMAT_R_8, 1u, kUsageFlags, "r8"); if (buffer->initCheck() != 0) { // Devices are not required to support R8. return nullptr; @@ -311,9 +248,6 @@ public: } for (uint32_t texName : mTexNames) { mRE->deleteTextures(1, &texName); - if (mGLESRE != nullptr) { - EXPECT_FALSE(mGLESRE->isTextureNameKnownForTesting(texName)); - } } const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); @@ -444,7 +378,9 @@ public: const ubyte4& backgroundColor) { const Rect casterRect(castingLayer.geometry.boundaries); Region casterRegion = Region(casterRect); - const float casterCornerRadius = castingLayer.geometry.roundedCornersRadius; + const float casterCornerRadius = (castingLayer.geometry.roundedCornersRadius.x + + castingLayer.geometry.roundedCornersRadius.y) / + 2.0; if (casterCornerRadius > 0.0f) { // ignore the corners if a corner radius is set Rect cornerRect(casterCornerRadius, casterCornerRadius); @@ -524,20 +460,15 @@ public: void invokeDraw(const renderengine::DisplaySettings& settings, const std::vector<renderengine::LayerSettings>& layers) { - std::future<renderengine::RenderEngineResult> result = + ftl::Future<FenceResult> future = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd()); + ASSERT_TRUE(future.valid()); - ASSERT_TRUE(result.valid()); - auto [status, fence] = result.get(); - - ASSERT_EQ(NO_ERROR, status); - if (fence.ok()) { - sync_wait(fence.get(), -1); - } + auto result = future.get(); + ASSERT_TRUE(result.ok()); - if (layers.size() > 0 && mGLESRE != nullptr) { - ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); - } + auto fence = result.value(); + fence->waitForever(LOG_TAG); } void drawEmptyLayers() { @@ -660,26 +591,13 @@ public: std::unique_ptr<renderengine::RenderEngine> mRE; std::shared_ptr<renderengine::ExternalTexture> mBuffer; - // GLESRenderEngine for testing GLES-specific behavior. - // Owened by mRE, but this is downcasted. - renderengine::gl::GLESRenderEngine* mGLESRE = nullptr; std::vector<uint32_t> mTexNames; }; void RenderEngineTest::initializeRenderEngine() { const auto& renderEngineFactory = GetParam(); - if (renderEngineFactory->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - // Only GLESRenderEngine exposes test-only methods. Provide a pointer to the - // GLESRenderEngine if we're using it so that we don't need to dynamic_cast - // every time. - std::unique_ptr<renderengine::gl::GLESRenderEngine> renderEngine = - renderEngineFactory->createGLESRenderEngine(); - mGLESRE = renderEngine.get(); - mRE = std::move(renderEngine); - } else { - mRE = renderEngineFactory->createRenderEngine(); - } + mRE = renderEngineFactory->createRenderEngine(); mBuffer = allocateDefaultBuffer(); } @@ -1000,9 +918,9 @@ void RenderEngineTest::fillBufferWithColorTransformAndSourceDataspace( std::vector<renderengine::LayerSettings> layers; renderengine::LayerSettings layer; - layer.sourceDataspace = sourceDataspace; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this); + layer.sourceDataspace = sourceDataspace; layer.alpha = 1.0f; // construct a fake color matrix @@ -1028,13 +946,13 @@ void RenderEngineTest::fillBufferColorTransform() { template <typename SourceVariant> void RenderEngineTest::fillBufferColorTransformAndSourceDataspace() { unordered_map<ui::Dataspace, ubyte4> dataspaceToColorMap; - dataspaceToColorMap[ui::Dataspace::V0_BT709] = {172, 0, 0, 255}; - dataspaceToColorMap[ui::Dataspace::BT2020] = {172, 0, 0, 255}; - dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {172, 0, 0, 255}; + dataspaceToColorMap[ui::Dataspace::V0_BT709] = {77, 0, 0, 255}; + dataspaceToColorMap[ui::Dataspace::BT2020] = {101, 0, 0, 255}; + dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {75, 0, 0, 255}; ui::Dataspace customizedDataspace = static_cast<ui::Dataspace>( ui::Dataspace::STANDARD_BT709 | ui::Dataspace::TRANSFER_GAMMA2_2 | ui::Dataspace::RANGE_FULL); - dataspaceToColorMap[customizedDataspace] = {172, 0, 0, 255}; + dataspaceToColorMap[customizedDataspace] = {61, 0, 0, 255}; for (const auto& [sourceDataspace, color] : dataspaceToColorMap) { fillBufferWithColorTransformAndSourceDataspace<SourceVariant>(sourceDataspace); expectBufferColor(fullscreenRect(), color.r, color.g, color.b, color.a, 1); @@ -1074,13 +992,13 @@ void RenderEngineTest::fillBufferWithColorTransformAndOutputDataspace( template <typename SourceVariant> void RenderEngineTest::fillBufferColorTransformAndOutputDataspace() { unordered_map<ui::Dataspace, ubyte4> dataspaceToColorMap; - dataspaceToColorMap[ui::Dataspace::V0_BT709] = {202, 0, 0, 255}; - dataspaceToColorMap[ui::Dataspace::BT2020] = {192, 0, 0, 255}; - dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {202, 0, 0, 255}; + dataspaceToColorMap[ui::Dataspace::V0_BT709] = {198, 0, 0, 255}; + dataspaceToColorMap[ui::Dataspace::BT2020] = {187, 0, 0, 255}; + dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {192, 0, 0, 255}; ui::Dataspace customizedDataspace = static_cast<ui::Dataspace>( ui::Dataspace::STANDARD_BT709 | ui::Dataspace::TRANSFER_GAMMA2_6 | ui::Dataspace::RANGE_FULL); - dataspaceToColorMap[customizedDataspace] = {202, 0, 0, 255}; + dataspaceToColorMap[customizedDataspace] = {205, 0, 0, 255}; for (const auto& [outputDataspace, color] : dataspaceToColorMap) { fillBufferWithColorTransformAndOutputDataspace<SourceVariant>(outputDataspace); expectBufferColor(fullscreenRect(), color.r, color.g, color.b, color.a, 1); @@ -1129,7 +1047,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; layer.geometry.boundaries = fullscreenRect().toFloatRect(); - layer.geometry.roundedCornersRadius = 5.0f; + layer.geometry.roundedCornersRadius = {5.0f, 5.0f}; layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; @@ -1494,13 +1412,13 @@ void RenderEngineTest::tonemap(ui::Dataspace sourceDataspace, std::function<vec3 auto buf = std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE, - "input"), + ExternalTexture>(sp<GraphicBuffer>::make(kGreyLevels, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "input"), *mRE, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage::WRITEABLE); @@ -1527,13 +1445,13 @@ void RenderEngineTest::tonemap(ui::Dataspace sourceDataspace, std::function<vec3 mBuffer = std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE, - "output"), + ExternalTexture>(sp<GraphicBuffer>::make(kGreyLevels, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "output"), *mRE, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage::WRITEABLE); @@ -1596,9 +1514,7 @@ void RenderEngineTest::tonemap(ui::Dataspace sourceDataspace, std::function<vec3 } INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest, - testing::Values(std::make_shared<GLESRenderEngineFactory>(), - std::make_shared<GLESCMRenderEngineFactory>(), - std::make_shared<SkiaGLESRenderEngineFactory>(), + testing::Values(std::make_shared<SkiaGLESRenderEngineFactory>(), std::make_shared<SkiaGLESCMRenderEngineFactory>())); TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { @@ -1606,6 +1522,30 @@ TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { drawEmptyLayers(); } +TEST_P(RenderEngineTest, drawLayers_fillRedBufferAndEmptyBuffer) { + initializeRenderEngine(); + renderengine::DisplaySettings settings; + settings.physicalDisplay = fullscreenRect(); + settings.clip = fullscreenRect(); + settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; + + // add a red layer + renderengine::LayerSettings layerOne{ + .geometry.boundaries = fullscreenRect().toFloatRect(), + .source.solidColor = half3(1.0f, 0.0f, 0.0f), + .alpha = 1.f, + }; + + std::vector<renderengine::LayerSettings> layersFirst{layerOne}; + invokeDraw(settings, layersFirst); + expectBufferColor(fullscreenRect(), 255, 0, 0, 255); + + // re-draw with an empty layer above it, and we get a transparent black one + std::vector<renderengine::LayerSettings> layersSecond; + invokeDraw(settings, layersSecond); + expectBufferColor(fullscreenRect(), 0, 0, 0, 0); +} + TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { initializeRenderEngine(); @@ -1647,49 +1587,13 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) { layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layers.push_back(layer); - std::future<renderengine::RenderEngineResult> result = + ftl::Future<FenceResult> future = mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd()); - ASSERT_TRUE(result.valid()); - auto [status, fence] = result.get(); - ASSERT_EQ(BAD_VALUE, status); - ASSERT_FALSE(fence.ok()); -} - -TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - renderengine::DisplaySettings settings; - settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - settings.physicalDisplay = fullscreenRect(); - settings.clip = fullscreenRect(); - - std::vector<renderengine::LayerSettings> layers; - renderengine::LayerSettings layer; - layer.geometry.boundaries = fullscreenRect().toFloatRect(); - BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this); - layer.alpha = 1.0; - layers.push_back(layer); - - std::future<renderengine::RenderEngineResult> result = - mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd()); - ASSERT_TRUE(result.valid()); - auto [status, fence] = result.get(); - - ASSERT_EQ(NO_ERROR, status); - if (fence.ok()) { - sync_wait(fence.get(), -1); - } - - ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); - expectBufferColor(fullscreenRect(), 255, 0, 0, 255); + ASSERT_TRUE(future.valid()); + auto result = future.get(); + ASSERT_FALSE(result.ok()); + ASSERT_EQ(BAD_VALUE, result.error()); } TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) { @@ -1751,11 +1655,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_sourceDataspace) { const auto& renderEngineFactory = GetParam(); // skip for non color management if (!renderEngineFactory->useColorManagement()) { - return; - } - // skip for GLESRenderEngine - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - return; + GTEST_SKIP(); } initializeRenderEngine(); @@ -1766,11 +1666,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_outputDataspace) { const auto& renderEngineFactory = GetParam(); // skip for non color management if (!renderEngineFactory->useColorManagement()) { - return; - } - // skip for GLESRenderEngine - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - return; + GTEST_SKIP(); } initializeRenderEngine(); @@ -1861,11 +1757,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_o const auto& renderEngineFactory = GetParam(); // skip for non color management if (!renderEngineFactory->useColorManagement()) { - return; - } - // skip for GLESRenderEngine - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - return; + GTEST_SKIP(); } initializeRenderEngine(); @@ -1876,11 +1768,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_o const auto& renderEngineFactory = GetParam(); // skip for non color management if (!renderEngineFactory->useColorManagement()) { - return; - } - // skip for GLESRenderEngine - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - return; + GTEST_SKIP(); } initializeRenderEngine(); @@ -1971,11 +1859,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_b const auto& renderEngineFactory = GetParam(); // skip for non color management if (!renderEngineFactory->useColorManagement()) { - return; - } - // skip for GLESRenderEngine - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - return; + GTEST_SKIP(); } initializeRenderEngine(); @@ -1986,11 +1870,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_b const auto& renderEngineFactory = GetParam(); // skip for non color management if (!renderEngineFactory->useColorManagement()) { - return; - } - // skip for GLESRenderEngine - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - return; + GTEST_SKIP(); } initializeRenderEngine(); @@ -2131,7 +2011,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) { casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::LayerSettings castingLayer; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); - castingLayer.geometry.roundedCornersRadius = 3.0f; + castingLayer.geometry.roundedCornersRadius = {3.0f, 3.0f}; castingLayer.geometry.roundedCornersCrop = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; renderengine::ShadowSettings settings = @@ -2185,20 +2065,20 @@ TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) { layer.alpha = 1.0; layers.push_back(layer); - std::future<renderengine::RenderEngineResult> resultOne = + ftl::Future<FenceResult> futureOne = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd()); - ASSERT_TRUE(resultOne.valid()); - auto [statusOne, fenceOne] = resultOne.get(); - ASSERT_EQ(NO_ERROR, statusOne); - - std::future<renderengine::RenderEngineResult> resultTwo = - mRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne)); - ASSERT_TRUE(resultTwo.valid()); - auto [statusTwo, fenceTwo] = resultTwo.get(); - ASSERT_EQ(NO_ERROR, statusTwo); - if (fenceTwo.ok()) { - sync_wait(fenceTwo.get(), -1); - } + ASSERT_TRUE(futureOne.valid()); + auto resultOne = futureOne.get(); + ASSERT_TRUE(resultOne.ok()); + auto fenceOne = resultOne.value(); + + ftl::Future<FenceResult> futureTwo = + mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(fenceOne->dup())); + ASSERT_TRUE(futureTwo.valid()); + auto resultTwo = futureTwo.get(); + ASSERT_TRUE(resultTwo.ok()); + auto fenceTwo = resultTwo.value(); + fenceTwo->waitForever(LOG_TAG); // Only cleanup the first time. EXPECT_FALSE(mRE->canSkipPostRenderCleanup()); @@ -2219,7 +2099,8 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - redLayer.geometry.roundedCornersRadius = 5.0f; + redLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; + redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2231,7 +2112,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { renderengine::LayerSettings greenLayer; greenLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; greenLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - greenLayer.geometry.roundedCornersRadius = 5.0f; + greenLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; // Bottom right corner is not going to be rounded. greenLayer.geometry.roundedCornersCrop = Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3, DEFAULT_DISPLAY_HEIGHT, @@ -2268,7 +2149,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - redLayer.geometry.roundedCornersRadius = 5.0f; + redLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2313,7 +2194,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 32); - redLayer.geometry.roundedCornersRadius = 64; + redLayer.geometry.roundedCornersRadius = {64.0f, 64.0f}; redLayer.geometry.roundedCornersCrop = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 128); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2334,6 +2215,49 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, 31), 255, 0, 0, 255); } +TEST_P(RenderEngineTest, testRoundedCornersXY) { + if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) { + GTEST_SKIP(); + } + + initializeRenderEngine(); + + renderengine::DisplaySettings settings; + settings.physicalDisplay = fullscreenRect(); + settings.clip = fullscreenRect(); + settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; + + std::vector<renderengine::LayerSettings> layers; + + renderengine::LayerSettings redLayer; + redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; + redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); + redLayer.geometry.roundedCornersRadius = {5.0f, 20.0f}; + redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); + // Red background. + redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); + redLayer.alpha = 1.0f; + + layers.push_back(redLayer); + + invokeDraw(settings, layers); + + // Due to roundedCornersRadius, the corners are untouched. + expectBufferColor(Point(0, 0), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 0), 0, 0, 0, 0); + expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0); + + // Y-axis draws a larger radius, check that its untouched as well + expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 5), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 5), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 5), 0, 0, 0, 0); + expectBufferColor(Point(0, 5), 0, 0, 0, 0); + + // middle should be red + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0, 255); +} + TEST_P(RenderEngineTest, testClear) { initializeRenderEngine(); @@ -2411,13 +2335,58 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { expectBufferColor(rect, 0, 128, 0, 128); } -TEST_P(RenderEngineTest, testDimming) { - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { +TEST_P(RenderEngineTest, testBorder) { + if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) { + GTEST_SKIP(); + } + + if (!GetParam()->useColorManagement()) { GTEST_SKIP(); } initializeRenderEngine(); + const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB; + + const auto displayRect = Rect(1080, 2280); + renderengine::DisplaySettings display{ + .physicalDisplay = displayRect, + .clip = displayRect, + .outputDataspace = dataspace, + }; + display.borderInfoList.clear(); + renderengine::BorderRenderInfo info; + info.combinedRegion = Region(Rect(99, 99, 199, 199)); + info.width = 20.0f; + info.color = half4{1.0f, 128.0f / 255.0f, 0.0f, 1.0f}; + display.borderInfoList.emplace_back(info); + + const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255)); + const renderengine::LayerSettings greenLayer{ + .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = greenBuffer, + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = dataspace, + .whitePointNits = 200.f, + }; + + std::vector<renderengine::LayerSettings> layers; + layers.emplace_back(greenLayer); + invokeDraw(display, layers); + + expectBufferColor(Rect(99, 99, 101, 101), 255, 128, 0, 255, 1); +} + +TEST_P(RenderEngineTest, testDimming) { + initializeRenderEngine(); + const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB_LINEAR; const auto displayRect = Rect(3, 1); @@ -2488,9 +2457,6 @@ TEST_P(RenderEngineTest, testDimming) { } TEST_P(RenderEngineTest, testDimming_inGammaSpace) { - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - GTEST_SKIP(); - } initializeRenderEngine(); const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 | @@ -2566,9 +2532,6 @@ TEST_P(RenderEngineTest, testDimming_inGammaSpace) { } TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform) { - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - GTEST_SKIP(); - } initializeRenderEngine(); const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 | @@ -2629,9 +2592,6 @@ TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform) { } TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform_deviceHandles) { - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - GTEST_SKIP(); - } initializeRenderEngine(); const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 | @@ -2694,9 +2654,6 @@ TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform_devi TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) { initializeRenderEngine(); - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - return; - } const auto displayRect = Rect(2, 1); const renderengine::DisplaySettings display{ @@ -2802,10 +2759,6 @@ TEST_P(RenderEngineTest, test_tonemapPQMatches) { GTEST_SKIP(); } - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - GTEST_SKIP(); - } - initializeRenderEngine(); tonemap( @@ -2823,10 +2776,6 @@ TEST_P(RenderEngineTest, test_tonemapHLGMatches) { GTEST_SKIP(); } - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - GTEST_SKIP(); - } - initializeRenderEngine(); tonemap( @@ -2840,10 +2789,6 @@ TEST_P(RenderEngineTest, test_tonemapHLGMatches) { } TEST_P(RenderEngineTest, r8_behaves_as_mask) { - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - return; - } - initializeRenderEngine(); const auto r8Buffer = allocateR8Buffer(2, 1); @@ -2901,10 +2846,6 @@ TEST_P(RenderEngineTest, r8_behaves_as_mask) { } TEST_P(RenderEngineTest, r8_respects_color_transform) { - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - return; - } - initializeRenderEngine(); const auto r8Buffer = allocateR8Buffer(2, 1); @@ -2967,10 +2908,6 @@ TEST_P(RenderEngineTest, r8_respects_color_transform) { } TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) { - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - return; - } - initializeRenderEngine(); const auto r8Buffer = allocateR8Buffer(2, 1); @@ -3036,10 +2973,6 @@ TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) { } TEST_P(RenderEngineTest, primeShaderCache) { - if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { - GTEST_SKIP(); - } - initializeRenderEngine(); auto fut = mRE->primeCache(); diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 96851892b4..1a96289bc0 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -176,27 +176,24 @@ TEST_F(RenderEngineThreadedTest, drawLayers) { std::vector<renderengine::LayerSettings> layers; std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(), *mRenderEngine, + ExternalTexture>(sp<GraphicBuffer>::make(), *mRenderEngine, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage::WRITEABLE); base::unique_fd bufferFence; EXPECT_CALL(*mRenderEngine, drawLayersInternal) - .WillOnce([&](const std::shared_ptr<std::promise<renderengine::RenderEngineResult>>&& - resultPromise, + .WillOnce([&](const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const renderengine::DisplaySettings&, const std::vector<renderengine::LayerSettings>&, const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> void { - resultPromise->set_value({NO_ERROR, base::unique_fd()}); - }); + base::unique_fd&&) { resultPromise->set_value(Fence::NO_FENCE); }); - std::future<renderengine::RenderEngineResult> result = + ftl::Future<FenceResult> future = mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence)); - ASSERT_TRUE(result.valid()); - auto [status, _] = result.get(); - ASSERT_EQ(NO_ERROR, status); + ASSERT_TRUE(future.valid()); + auto result = future.get(); + ASSERT_TRUE(result.ok()); } } // namespace android diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 203bb54701..b41e8432a9 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -313,21 +313,21 @@ bool RenderEngineThreaded::canSkipPostRenderCleanup() const { } void RenderEngineThreaded::drawLayersInternal( - const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise, + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { - resultPromise->set_value({NO_ERROR, base::unique_fd()}); + resultPromise->set_value(Fence::NO_FENCE); return; } -std::future<RenderEngineResult> RenderEngineThreaded::drawLayers( +ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { ATRACE_CALL(); - const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>(); - std::future<RenderEngineResult> resultFuture = resultPromise->get_future(); + const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); + std::future<FenceResult> resultFuture = resultPromise->get_future(); int fd = bufferFence.release(); { std::lock_guard lock(mThreadMutex); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 1340902126..bf2ebea2a0 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -56,11 +56,11 @@ public: void useProtectedContext(bool useProtectedContext) override; void cleanupPostRender() override; - std::future<RenderEngineResult> drawLayers(const DisplaySettings& display, - const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer, - const bool useFramebufferCache, - base::unique_fd&& bufferFence) override; + ftl::Future<FenceResult> drawLayers(const DisplaySettings& display, + const std::vector<LayerSettings>& layers, + const std::shared_ptr<ExternalTexture>& buffer, + const bool useFramebufferCache, + base::unique_fd&& bufferFence) override; void cleanFramebufferCache() override; int getContextPriority() override; @@ -73,7 +73,7 @@ protected: void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override; void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override; bool canSkipPostRenderCleanup() const override; - void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise, + void drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index a6cacad374..78f692bb0c 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -22,12 +22,12 @@ #include <cutils/native_handle.h> #include <utils/Errors.h> #include <utils/RefBase.h> -#include <utils/Vector.h> #include <utils/Timers.h> +#include <utils/Vector.h> -#include <binder/Parcel.h> #include <binder/IInterface.h> #include <binder/IResultReceiver.h> +#include <binder/Parcel.h> #include <sensor/Sensor.h> #include <sensor/ISensorEventConnection.h> @@ -205,9 +205,10 @@ status_t BnSensorServer::onTransact( if (resource == nullptr) { return BAD_VALUE; } + native_handle_set_fdsan_tag(resource); sp<ISensorEventConnection> ch = createSensorDirectConnection(opPackageName, size, type, format, resource); - native_handle_close(resource); + native_handle_close_with_tag(resource); native_handle_delete(resource); reply->writeStrongBinder(IInterface::asBinder(ch)); return NO_ERROR; diff --git a/libs/shaders/Android.bp b/libs/shaders/Android.bp index 6b936de0ec..960f845488 100644 --- a/libs/shaders/Android.bp +++ b/libs/shaders/Android.bp @@ -23,13 +23,14 @@ package { cc_library_static { name: "libshaders", - + defaults: [ + "android.hardware.graphics.common-ndk_shared", + "android.hardware.graphics.composer3-ndk_shared", + ], export_include_dirs: ["include"], local_include_dirs: ["include"], shared_libs: [ - "android.hardware.graphics.common-V3-ndk", - "android.hardware.graphics.composer3-V1-ndk", "android.hardware.graphics.common@1.2", "libnativewindow", ], diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp index cf671bcb7a..1e4f45ac45 100644 --- a/libs/shaders/tests/Android.bp +++ b/libs/shaders/tests/Android.bp @@ -23,6 +23,10 @@ package { cc_test { name: "libshaders_test", + defaults: [ + "android.hardware.graphics.common-ndk_shared", + "android.hardware.graphics.composer3-ndk_shared", + ], test_suites: ["device-tests"], srcs: [ "shaders_test.cpp", @@ -31,8 +35,6 @@ cc_test { "libtonemap_headers", ], shared_libs: [ - "android.hardware.graphics.common-V3-ndk", - "android.hardware.graphics.composer3-V1-ndk", "android.hardware.graphics.common@1.2", "libnativewindow", ], diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp index 37c98240c5..8c8815d0e4 100644 --- a/libs/tonemap/Android.bp +++ b/libs/tonemap/Android.bp @@ -23,13 +23,15 @@ package { cc_library_static { name: "libtonemap", + defaults: [ + "android.hardware.graphics.common-ndk_shared", + "android.hardware.graphics.composer3-ndk_shared", + ], vendor_available: true, local_include_dirs: ["include"], shared_libs: [ - "android.hardware.graphics.common-V3-ndk", - "android.hardware.graphics.composer3-V1-ndk", "liblog", "libnativewindow", ], diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp index 58851b41be..2abf51563c 100644 --- a/libs/tonemap/tests/Android.bp +++ b/libs/tonemap/tests/Android.bp @@ -23,6 +23,10 @@ package { cc_test { name: "libtonemap_test", + defaults: [ + "android.hardware.graphics.common-ndk_shared", + "android.hardware.graphics.composer3-ndk_shared", + ], test_suites: ["device-tests"], srcs: [ "tonemap_test.cpp", @@ -31,8 +35,6 @@ cc_test { "libtonemap_headers", ], shared_libs: [ - "android.hardware.graphics.common-V3-ndk", - "android.hardware.graphics.composer3-V1-ndk", "libnativewindow", ], static_libs: [ diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 0f771a9070..d33dd34d4e 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -127,7 +127,6 @@ cc_library_shared { "DebugUtils.cpp", "DeviceProductInfo.cpp", "DisplayIdentification.cpp", - "DisplayMode.cpp", "DynamicDisplayInfo.cpp", "Fence.cpp", "FenceTime.cpp", @@ -139,11 +138,9 @@ cc_library_shared { "GraphicBuffer.cpp", "GraphicBufferAllocator.cpp", "GraphicBufferMapper.cpp", - "HdrCapabilities.cpp", "PixelFormat.cpp", "PublicFormat.cpp", "StaticAsserts.cpp", - "StaticDisplayInfo.cpp", ], include_dirs: [ @@ -155,6 +152,8 @@ cc_library_shared { ], defaults: [ + "android.hardware.graphics.allocator-ndk_shared", + "android.hardware.graphics.common-ndk_shared", "libui-defaults", // Uncomment the following line to enable VALIDATE_REGIONS traces //defaults: ["libui-validate-regions-defaults"], @@ -164,8 +163,6 @@ cc_library_shared { "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.allocator@4.0", - "android.hardware.graphics.allocator-V1-ndk", - "android.hardware.graphics.common-V3-ndk", "android.hardware.graphics.common@1.2", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.1", @@ -183,7 +180,6 @@ cc_library_shared { export_shared_lib_headers: [ "android.hardware.graphics.common@1.2", - "android.hardware.graphics.common-V3-ndk", "android.hardware.graphics.mapper@4.0", "libgralloctypes", ], @@ -241,10 +237,6 @@ cc_library_shared { ], afdo: true, - - header_abi_checker: { - diff_flags: ["-allow-adding-removing-weak-symbols"], - }, } cc_library_headers { diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp index 04d9d3c989..33060126ff 100644 --- a/libs/ui/DeviceProductInfo.cpp +++ b/libs/ui/DeviceProductInfo.cpp @@ -17,7 +17,6 @@ #include <ui/DeviceProductInfo.h> #include <android-base/stringprintf.h> -#include <ui/FlattenableHelpers.h> #include <utils/Log.h> #define RETURN_IF_ERROR(op) \ @@ -27,35 +26,6 @@ namespace android { using base::StringAppendF; -size_t DeviceProductInfo::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(name) + - FlattenableHelpers::getFlattenedSize(manufacturerPnpId) + - FlattenableHelpers::getFlattenedSize(productId) + - FlattenableHelpers::getFlattenedSize(manufactureOrModelDate) + - FlattenableHelpers::getFlattenedSize(relativeAddress); -} - -status_t DeviceProductInfo::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, name)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufacturerPnpId)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, productId)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufactureOrModelDate)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, relativeAddress)); - return OK; -} - -status_t DeviceProductInfo::unflatten(void const* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &name)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufacturerPnpId)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &productId)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufactureOrModelDate)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &relativeAddress)); - return OK; -} - void DeviceProductInfo::dump(std::string& result) const { StringAppendF(&result, "{name=\"%s\", ", name.c_str()); StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data()); diff --git a/libs/ui/DisplayMode.cpp b/libs/ui/DisplayMode.cpp deleted file mode 100644 index cf05dbfb05..0000000000 --- a/libs/ui/DisplayMode.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2021 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 <ui/DisplayMode.h> - -#include <cstdint> - -#include <ui/FlattenableHelpers.h> - -#define RETURN_IF_ERROR(op) \ - if (const status_t status = (op); status != OK) return status; - -namespace android::ui { - -size_t DisplayMode::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(id) + - FlattenableHelpers::getFlattenedSize(resolution) + - FlattenableHelpers::getFlattenedSize(xDpi) + - FlattenableHelpers::getFlattenedSize(yDpi) + - FlattenableHelpers::getFlattenedSize(refreshRate) + - FlattenableHelpers::getFlattenedSize(appVsyncOffset) + - FlattenableHelpers::getFlattenedSize(sfVsyncOffset) + - FlattenableHelpers::getFlattenedSize(presentationDeadline) + - FlattenableHelpers::getFlattenedSize(group); -} - -status_t DisplayMode::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, id)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, resolution)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, xDpi)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, yDpi)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, refreshRate)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, appVsyncOffset)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, sfVsyncOffset)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, presentationDeadline)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, group)); - return OK; -} - -status_t DisplayMode::unflatten(const void* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &id)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &resolution)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &xDpi)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &yDpi)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &refreshRate)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &appVsyncOffset)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &sfVsyncOffset)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &presentationDeadline)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &group)); - return OK; -} - -} // namespace android::ui diff --git a/libs/ui/DynamicDisplayInfo.cpp b/libs/ui/DynamicDisplayInfo.cpp index 78ba9965b6..f5feea925d 100644 --- a/libs/ui/DynamicDisplayInfo.cpp +++ b/libs/ui/DynamicDisplayInfo.cpp @@ -18,11 +18,6 @@ #include <cstdint> -#include <ui/FlattenableHelpers.h> - -#define RETURN_IF_ERROR(op) \ - if (const status_t status = (op); status != OK) return status; - namespace android::ui { std::optional<ui::DisplayMode> DynamicDisplayInfo::getActiveDisplayMode() const { @@ -34,42 +29,4 @@ std::optional<ui::DisplayMode> DynamicDisplayInfo::getActiveDisplayMode() const return {}; } -size_t DynamicDisplayInfo::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(supportedDisplayModes) + - FlattenableHelpers::getFlattenedSize(activeDisplayModeId) + - FlattenableHelpers::getFlattenedSize(supportedColorModes) + - FlattenableHelpers::getFlattenedSize(activeColorMode) + - FlattenableHelpers::getFlattenedSize(hdrCapabilities) + - FlattenableHelpers::getFlattenedSize(autoLowLatencyModeSupported) + - FlattenableHelpers::getFlattenedSize(gameContentTypeSupported) + - FlattenableHelpers::getFlattenedSize(preferredBootDisplayMode); -} - -status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedDisplayModes)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeDisplayModeId)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedColorModes)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeColorMode)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, hdrCapabilities)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, autoLowLatencyModeSupported)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, gameContentTypeSupported)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, preferredBootDisplayMode)); - return OK; -} - -status_t DynamicDisplayInfo::unflatten(const void* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedDisplayModes)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeDisplayModeId)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedColorModes)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeColorMode)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &hdrCapabilities)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &autoLowLatencyModeSupported)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &gameContentTypeSupported)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &preferredBootDisplayMode)); - return OK; -} - } // namespace android::ui diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp deleted file mode 100644 index aec2fac780..0000000000 --- a/libs/ui/HdrCapabilities.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2016 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 <ui/HdrCapabilities.h> - -namespace android { - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast" -#endif - -size_t HdrCapabilities::getFlattenedSize() const { - return sizeof(mMaxLuminance) + - sizeof(mMaxAverageLuminance) + - sizeof(mMinLuminance) + - sizeof(int32_t) + - mSupportedHdrTypes.size() * sizeof(ui::Hdr); -} - -status_t HdrCapabilities::flatten(void* buffer, size_t size) const { - - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - - int32_t* const buf = static_cast<int32_t*>(buffer); - reinterpret_cast<float&>(buf[0]) = mMaxLuminance; - reinterpret_cast<float&>(buf[1]) = mMaxAverageLuminance; - reinterpret_cast<float&>(buf[2]) = mMinLuminance; - buf[3] = static_cast<int32_t>(mSupportedHdrTypes.size()); - for (size_t i = 0, c = mSupportedHdrTypes.size(); i < c; ++i) { - buf[4 + i] = static_cast<int32_t>(mSupportedHdrTypes[i]); - } - return NO_ERROR; -} - -status_t HdrCapabilities::unflatten(void const* buffer, size_t size) { - - size_t minSize = sizeof(mMaxLuminance) + - sizeof(mMaxAverageLuminance) + - sizeof(mMinLuminance) + - sizeof(int32_t); - - if (size < minSize) { - return NO_MEMORY; - } - - int32_t const * const buf = static_cast<int32_t const *>(buffer); - const size_t itemCount = size_t(buf[3]); - - // check the buffer is large enough - if (size < minSize + itemCount * sizeof(int32_t)) { - return BAD_VALUE; - } - - mMaxLuminance = reinterpret_cast<float const&>(buf[0]); - mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]); - mMinLuminance = reinterpret_cast<float const&>(buf[2]); - if (itemCount) { - mSupportedHdrTypes.resize(itemCount); - for (size_t i = 0; i < itemCount; ++i) { - mSupportedHdrTypes[i] = static_cast<ui::Hdr>(buf[4 + i]); - } - } - return NO_ERROR; -} - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - -} // namespace android diff --git a/libs/ui/StaticDisplayInfo.cpp b/libs/ui/StaticDisplayInfo.cpp deleted file mode 100644 index 03d15e4694..0000000000 --- a/libs/ui/StaticDisplayInfo.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <ui/StaticDisplayInfo.h> - -#include <cstdint> - -#include <ui/FlattenableHelpers.h> - -#define RETURN_IF_ERROR(op) \ - if (const status_t status = (op); status != OK) return status; - -namespace android::ui { - -size_t StaticDisplayInfo::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(connectionType) + - FlattenableHelpers::getFlattenedSize(density) + - FlattenableHelpers::getFlattenedSize(secure) + - FlattenableHelpers::getFlattenedSize(deviceProductInfo) + - FlattenableHelpers::getFlattenedSize(installOrientation); -} - -status_t StaticDisplayInfo::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, connectionType)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, density)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, secure)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, deviceProductInfo)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, installOrientation)); - return OK; -} - -status_t StaticDisplayInfo::unflatten(void const* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &deviceProductInfo)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &installOrientation)); - return OK; -} - -} // namespace android::ui diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h index 807a5d96a3..879e46fbdc 100644 --- a/libs/ui/include/ui/DeviceProductInfo.h +++ b/libs/ui/include/ui/DeviceProductInfo.h @@ -24,8 +24,6 @@ #include <variant> #include <vector> -#include <utils/Flattenable.h> - namespace android { // NUL-terminated plug and play ID. @@ -34,7 +32,7 @@ using PnpId = std::array<char, 4>; // Product-specific information about the display or the directly connected device on the // display chain. For example, if the display is transitively connected, this field may contain // product information about the intermediate device. -struct DeviceProductInfo : LightFlattenable<DeviceProductInfo> { +struct DeviceProductInfo { struct ModelYear { uint32_t year; }; @@ -64,11 +62,6 @@ struct DeviceProductInfo : LightFlattenable<DeviceProductInfo> { // For example, for HDMI connected device this will be the physical address. std::vector<uint8_t> relativeAddress; - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(void const* buffer, size_t size); - void dump(std::string& result) const; }; diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h index 9120972a42..d0c03fe39f 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -17,9 +17,10 @@ #pragma once #include <cstdint> -#include <optional> #include <string> +#include <ftl/optional.h> + namespace android { // ID of a physical or a virtual display. This class acts as a type safe wrapper around uint64_t. @@ -68,7 +69,7 @@ inline std::string to_string(DisplayId displayId) { // DisplayId of a physical display, such as the internal display or externally connected display. struct PhysicalDisplayId : DisplayId { - static constexpr std::optional<PhysicalDisplayId> tryCast(DisplayId id) { + static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) { if (id.value & FLAG_VIRTUAL) { return std::nullopt; } diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h index 56f68e7bb2..a2791a6d44 100644 --- a/libs/ui/include/ui/DisplayMode.h +++ b/libs/ui/include/ui/DisplayMode.h @@ -29,7 +29,7 @@ namespace android::ui { using DisplayModeId = int32_t; // Mode supported by physical display. -struct DisplayMode : LightFlattenable<DisplayMode> { +struct DisplayMode { DisplayModeId id; ui::Size resolution; float xDpi = 0; @@ -40,11 +40,6 @@ struct DisplayMode : LightFlattenable<DisplayMode> { nsecs_t sfVsyncOffset = 0; nsecs_t presentationDeadline = 0; int32_t group = -1; - - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(const void* buffer, size_t size); }; } // namespace android::ui diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h index ce75a65214..8c9fe4c311 100644 --- a/libs/ui/include/ui/DynamicDisplayInfo.h +++ b/libs/ui/include/ui/DynamicDisplayInfo.h @@ -24,12 +24,11 @@ #include <ui/GraphicTypes.h> #include <ui/HdrCapabilities.h> -#include <utils/Flattenable.h> namespace android::ui { // Information about a physical display which may change on hotplug reconnect. -struct DynamicDisplayInfo : LightFlattenable<DynamicDisplayInfo> { +struct DynamicDisplayInfo { std::vector<ui::DisplayMode> supportedDisplayModes; // This struct is going to be serialized over binder, so @@ -53,11 +52,6 @@ struct DynamicDisplayInfo : LightFlattenable<DynamicDisplayInfo> { ui::DisplayModeId preferredBootDisplayMode; std::optional<ui::DisplayMode> getActiveDisplayMode() const; - - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(const void* buffer, size_t size); }; } // namespace android::ui diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h b/libs/ui/include/ui/FenceResult.h index 0ce263b930..6d63fc9973 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h +++ b/libs/ui/include/ui/FenceResult.h @@ -20,30 +20,14 @@ #include <utils/Errors.h> #include <utils/StrongPointer.h> -// TODO(b/232535621): Pull this file to <ui/FenceResult.h> so that RenderEngine::drawLayers returns -// FenceResult rather than RenderEngineResult. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#include <renderengine/RenderEngine.h> -#pragma clang diagnostic pop - namespace android { class Fence; using FenceResult = base::expected<sp<Fence>, status_t>; -// TODO(b/232535621): Prevent base::unexpected(NO_ERROR) from being a valid FenceResult. inline status_t fenceStatus(const FenceResult& fenceResult) { return fenceResult.ok() ? NO_ERROR : fenceResult.error(); } -inline FenceResult toFenceResult(renderengine::RenderEngineResult&& result) { - if (auto [status, fence] = std::move(result); fence.ok()) { - return sp<Fence>::make(std::move(fence)); - } else { - return base::unexpected(status); - } -} - } // namespace android diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index 57be686592..dbe475b805 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -270,7 +270,7 @@ private: // Send a callback when a GraphicBuffer dies. // - // This is used for BufferStateLayer caching. GraphicBuffers are refcounted per process. When + // This is used for layer caching. GraphicBuffers are refcounted per process. When // A GraphicBuffer doesn't have any more sp<> in a process, it is destroyed. This causes // problems when trying to implicitcly cache across process boundaries. Ideally, both sides // of the cache would hold onto wp<> references. When an app dropped its sp<>, the GraphicBuffer diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h index 813addeca6..ae54223585 100644 --- a/libs/ui/include/ui/HdrCapabilities.h +++ b/libs/ui/include/ui/HdrCapabilities.h @@ -22,12 +22,10 @@ #include <vector> #include <ui/GraphicTypes.h> -#include <utils/Flattenable.h> namespace android { -class HdrCapabilities : public LightFlattenable<HdrCapabilities> -{ +class HdrCapabilities { public: HdrCapabilities(const std::vector<ui::Hdr>& types, float maxLuminance, float maxAverageLuminance, float minLuminance) @@ -49,12 +47,6 @@ public: float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; } float getDesiredMinLuminance() const { return mMinLuminance; } - // Flattenable protocol - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(void const* buffer, size_t size); - private: std::vector<ui::Hdr> mSupportedHdrTypes; float mMaxLuminance; diff --git a/libs/ui/include/ui/StaticDisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h index cc7c869b3b..83da821f37 100644 --- a/libs/ui/include/ui/StaticDisplayInfo.h +++ b/libs/ui/include/ui/StaticDisplayInfo.h @@ -20,24 +20,18 @@ #include <ui/DeviceProductInfo.h> #include <ui/Rotation.h> -#include <utils/Flattenable.h> namespace android::ui { -enum class DisplayConnectionType { Internal, External }; +enum class DisplayConnectionType { Internal, External, ftl_last = External }; // Immutable information about physical display. -struct StaticDisplayInfo : LightFlattenable<StaticDisplayInfo> { +struct StaticDisplayInfo { DisplayConnectionType connectionType = DisplayConnectionType::Internal; float density = 0.f; bool secure = false; std::optional<DeviceProductInfo> deviceProductInfo; Rotation installOrientation = ROTATION_0; - - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(void const* buffer, size_t size); }; } // namespace android::ui diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 76fd7f0f3f..dd14bcfb55 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -207,7 +207,8 @@ void* Loader::open(egl_connection_t* cnx) ATRACE_CALL(); const nsecs_t openTime = systemTime(); - if (should_unload_system_driver(cnx)) { + if (!android::GraphicsEnv::getInstance().angleIsSystemDriver() && + should_unload_system_driver(cnx)) { unload_system_driver(cnx); } @@ -216,8 +217,13 @@ void* Loader::open(egl_connection_t* cnx) return cnx->dso; } - // Firstly, try to load ANGLE driver. - driver_t* hnd = attempt_to_load_angle(cnx); + // Firstly, try to load ANGLE driver, unless we know that we shouldn't. + bool shouldForceLegacyDriver = android::GraphicsEnv::getInstance().shouldForceLegacyDriver(); + driver_t* hnd = nullptr; + if (!shouldForceLegacyDriver) { + hnd = attempt_to_load_angle(cnx); + } + if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); @@ -230,21 +236,29 @@ void* Loader::open(egl_connection_t* cnx) LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", android::GraphicsEnv::getInstance().getDriverPath().c_str()); } - // Finally, try to load system driver, start by searching for the library name appended by - // the system properties of the GLES userspace driver in both locations. - // i.e.: - // libGLES_${prop}.so, or: - // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so - for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { - auto prop = base::GetProperty(key, ""); - if (prop.empty()) { - continue; - } - hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true); - if (hnd) { - break; - } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) { - failToLoadFromDriverSuffixProperty = true; + // Finally, try to load system driver. If ANGLE is the system driver + // (i.e. we are forcing the legacy system driver instead of ANGLE), use + // the driver suffix that was passed down from above. + if (shouldForceLegacyDriver) { + std::string suffix = android::GraphicsEnv::getInstance().getLegacySuffix(); + hnd = attempt_to_load_system_driver(cnx, suffix.c_str(), true); + } else { + // Start by searching for the library name appended by the system + // properties of the GLES userspace driver in both locations. + // i.e.: + // libGLES_${prop}.so, or: + // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so + for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { + auto prop = base::GetProperty(key, ""); + if (prop.empty()) { + continue; + } + hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true); + if (hnd) { + break; + } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) { + failToLoadFromDriverSuffixProperty = true; + } } } } diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index efa67dbc1c..8348d6cb0a 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -28,7 +28,7 @@ // Cache size limits. static const size_t maxKeySize = 12 * 1024; static const size_t maxValueSize = 64 * 1024; -static const size_t maxTotalSize = 2 * 1024 * 1024; +static const size_t maxTotalSize = 32 * 1024 * 1024; // The time in seconds to wait before saving newly inserted cache entries. static const unsigned int deferredSaveDelay = 4; diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp index ae1bb1a0d0..3ef5049230 100644 --- a/services/audiomanager/IAudioManager.cpp +++ b/services/audiomanager/IAudioManager.cpp @@ -87,12 +87,12 @@ public: } virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event, - audio_port_handle_t deviceId) { + audio_port_handle_t eventId) { Parcel data, reply; data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor()); data.writeInt32((int32_t) piid); data.writeInt32((int32_t) event); - data.writeInt32((int32_t) deviceId); + data.writeInt32((int32_t) eventId); return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY); } @@ -141,6 +141,17 @@ public: data.writeInt32((int32_t) sessionId); return remote()->transact(PLAYER_SESSION_ID, data, &reply, IBinder::FLAG_ONEWAY); } + + virtual status_t portEvent(audio_port_handle_t portId, player_state_t event, + const std::unique_ptr<os::PersistableBundle>& extras) { + Parcel data, reply; + data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor()); + data.writeInt32((int32_t) portId); + data.writeInt32((int32_t) event); + // TODO: replace PersistableBundle with own struct + data.writeNullableParcelable(extras); + return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY); + } }; IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService"); diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 18d670ae38..ddcd51f357 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -38,6 +38,7 @@ cc_defaults { "-Wshadow", "-Wshadow-field-in-constructor-modified", "-Wshadow-uncaptured-local", + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", ], sanitize: { misc_undefined: ["bounds"], @@ -56,7 +57,7 @@ cc_defaults { filegroup { name: "libinputflinger_sources", srcs: [ - "InputClassifier.cpp", + "InputProcessor.cpp", "InputCommonConverter.cpp", "PreferStylusOverTouchBlocker.cpp", "UnwantedInteractionBlocker.cpp", @@ -84,12 +85,12 @@ cc_defaults { "libstatspull", "libstatssocket", "libutils", - "libui", "server_configurable_flags", ], static_libs: [ "libattestation", "libpalmrejection", + "libui-types", ], } @@ -138,6 +139,7 @@ filegroup { "InputListener.cpp", "InputReaderBase.cpp", "InputThread.cpp", + "NotifyArgs.cpp", "VibrationElement.cpp", ], } @@ -151,7 +153,6 @@ cc_defaults { "libcutils", "libinput", "liblog", - "libui", "libutils", ], header_libs: [ @@ -169,3 +170,48 @@ cc_library_shared { "libinputflinger_headers", ], } + +// This target will build everything 'input-related'. This could be useful for +// large refactorings of the input code. This is similar to 'm checkbuild', but +// just for input code. +// Use 'm checkinput' to build, and then (optionally) use 'm installclean' to +// remove any of the installed artifacts that you may not want on your actual +// build. +phony { + name: "checkinput", + required: [ + // native targets + "libinput", + "libinputflinger", + "inputflinger_tests", + "inputflinger_benchmarks", + "libinput_tests", + "libpalmrejection_test", + "libandroid_runtime", + "libinputservice_test", + "Bug-115739809", + "StructLayout_test", + + // native fuzzers + "inputflinger_latencytracker_fuzzer", + "inputflinger_cursor_input_fuzzer", + "inputflinger_keyboard_input_fuzzer", + "inputflinger_multitouch_input_fuzzer", + "inputflinger_switch_input_fuzzer", + "inputflinger_input_reader_fuzzer", + "inputflinger_blocking_queue_fuzzer", + "inputflinger_input_classifier_fuzzer", + + // Java/Kotlin targets + "CtsWindowManagerDeviceTestCases", + "InputTests", + "CtsHardwareTestCases", + "CtsInputTestCases", + "CtsViewTestCases", + "CtsWidgetTestCases", + "FrameworksCoreTests", + "FrameworksServicesTests", + "CtsSecurityTestCases", + "CtsSecurityBulletinHostTestCases", + ], +} diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h index 8300e8a3da..fe3728789d 100644 --- a/services/inputflinger/BlockingQueue.h +++ b/services/inputflinger/BlockingQueue.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_BLOCKING_QUEUE_H -#define _UI_INPUT_BLOCKING_QUEUE_H +#pragma once #include "android-base/thread_annotations.h" #include <condition_variable> @@ -106,6 +105,4 @@ private: std::vector<T> mQueue GUARDED_BY(mLock); }; - } // namespace android -#endif diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index dce327ed18..0972e224e9 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -31,308 +31,29 @@ using android::base::StringPrintf; namespace android { -// --- NotifyConfigurationChangedArgs --- - -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime) - : NotifyArgs(id, eventTime) {} - -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs( - const NotifyConfigurationChangedArgs& other) - : NotifyArgs(other.id, other.eventTime) {} - -bool NotifyConfigurationChangedArgs::operator==(const NotifyConfigurationChangedArgs& rhs) const { - return id == rhs.id && eventTime == rhs.eventTime; -} - -void NotifyConfigurationChangedArgs::notify(InputListenerInterface& listener) const { - listener.notifyConfigurationChanged(this); -} - -// --- NotifyKeyArgs --- - -NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId, - uint32_t source, int32_t displayId, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, - int32_t metaState, nsecs_t downTime) - : NotifyArgs(id, eventTime), - deviceId(deviceId), - source(source), - displayId(displayId), - policyFlags(policyFlags), - action(action), - flags(flags), - keyCode(keyCode), - scanCode(scanCode), - metaState(metaState), - downTime(downTime), - readTime(readTime) {} - -NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) - : NotifyArgs(other.id, other.eventTime), - deviceId(other.deviceId), - source(other.source), - displayId(other.displayId), - policyFlags(other.policyFlags), - action(other.action), - flags(other.flags), - keyCode(other.keyCode), - scanCode(other.scanCode), - metaState(other.metaState), - downTime(other.downTime), - readTime(other.readTime) {} - -bool NotifyKeyArgs::operator==(const NotifyKeyArgs& rhs) const { - return id == rhs.id && eventTime == rhs.eventTime && readTime == rhs.readTime && - deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId && - policyFlags == rhs.policyFlags && action == rhs.action && flags == rhs.flags && - keyCode == rhs.keyCode && scanCode == rhs.scanCode && metaState == rhs.metaState && - downTime == rhs.downTime; -} - -void NotifyKeyArgs::notify(InputListenerInterface& listener) const { - listener.notifyKey(this); -} - -// --- NotifyMotionArgs --- - -NotifyMotionArgs::NotifyMotionArgs( - int32_t id, nsecs_t eventTime, nsecs_t readTime, 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, MotionClassification classification, - int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xPrecision, float yPrecision, - float xCursorPosition, float yCursorPosition, nsecs_t downTime, - const std::vector<TouchVideoFrame>& videoFrames) - : NotifyArgs(id, eventTime), - deviceId(deviceId), - source(source), - displayId(displayId), - policyFlags(policyFlags), - action(action), - actionButton(actionButton), - flags(flags), - metaState(metaState), - buttonState(buttonState), - classification(classification), - edgeFlags(edgeFlags), - pointerCount(pointerCount), - xPrecision(xPrecision), - yPrecision(yPrecision), - xCursorPosition(xCursorPosition), - yCursorPosition(yCursorPosition), - downTime(downTime), - readTime(readTime), - videoFrames(videoFrames) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); - } -} - -NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) - : NotifyArgs(other.id, other.eventTime), - deviceId(other.deviceId), - source(other.source), - displayId(other.displayId), - policyFlags(other.policyFlags), - action(other.action), - actionButton(other.actionButton), - flags(other.flags), - metaState(other.metaState), - buttonState(other.buttonState), - classification(other.classification), - edgeFlags(other.edgeFlags), - pointerCount(other.pointerCount), - xPrecision(other.xPrecision), - yPrecision(other.yPrecision), - xCursorPosition(other.xCursorPosition), - yCursorPosition(other.yCursorPosition), - downTime(other.downTime), - readTime(other.readTime), - videoFrames(other.videoFrames) { - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - } -} - -static inline bool isCursorPositionEqual(float lhs, float rhs) { - return (isnan(lhs) && isnan(rhs)) || lhs == rhs; -} - -bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const { - bool equal = id == rhs.id && eventTime == rhs.eventTime && readTime == rhs.readTime && - deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId && - policyFlags == rhs.policyFlags && action == rhs.action && - actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState && - buttonState == rhs.buttonState && classification == rhs.classification && - edgeFlags == rhs.edgeFlags && - pointerCount == rhs.pointerCount - // PointerProperties and PointerCoords are compared separately below - && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision && - isCursorPositionEqual(xCursorPosition, rhs.xCursorPosition) && - isCursorPositionEqual(yCursorPosition, rhs.yCursorPosition) && - downTime == rhs.downTime && videoFrames == rhs.videoFrames; - if (!equal) { - return false; - } - - for (size_t i = 0; i < pointerCount; i++) { - equal = - pointerProperties[i] == rhs.pointerProperties[i] - && pointerCoords[i] == rhs.pointerCoords[i]; - if (!equal) { - return false; - } - } - return true; -} - -std::string NotifyMotionArgs::dump() const { - std::string coords; - for (uint32_t i = 0; i < pointerCount; i++) { - if (!coords.empty()) { - coords += ", "; - } - coords += StringPrintf("{%" PRIu32 ": ", i); - coords += - StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f pressure=%.1f", pointerProperties[i].id, - pointerCoords[i].getX(), pointerCoords[i].getY(), - pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - const int32_t toolType = pointerProperties[i].toolType; - if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) { - coords += StringPrintf(" toolType=%s", motionToolTypeToString(toolType)); - } - const float major = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR); - const float minor = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR); - const float orientation = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - if (major != 0 || minor != 0) { - coords += StringPrintf(" major=%.1f minor=%.1f orientation=%.1f", major, minor, - orientation); - } - coords += "}"; - } - return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32 - ", source=%s, action=%s, pointerCount=%" PRIu32 - " pointers=%s, flags=0x%08x)", - id, eventTime, deviceId, inputEventSourceToString(source).c_str(), - MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str(), - flags); -} - -void NotifyMotionArgs::notify(InputListenerInterface& listener) const { - listener.notifyMotion(this); -} - -// --- NotifySwitchArgs --- - -NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask) - : NotifyArgs(id, eventTime), - policyFlags(policyFlags), - switchValues(switchValues), - switchMask(switchMask) {} - -NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) - : NotifyArgs(other.id, other.eventTime), - policyFlags(other.policyFlags), - switchValues(other.switchValues), - switchMask(other.switchMask) {} - -bool NotifySwitchArgs::operator==(const NotifySwitchArgs rhs) const { - return id == rhs.id && eventTime == rhs.eventTime && policyFlags == rhs.policyFlags && - switchValues == rhs.switchValues && switchMask == rhs.switchMask; -} - -void NotifySwitchArgs::notify(InputListenerInterface& listener) const { - listener.notifySwitch(this); -} - -// --- NotifySensorArgs --- - -NotifySensorArgs::NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, - InputDeviceSensorType sensorType, - InputDeviceSensorAccuracy accuracy, bool accuracyChanged, - nsecs_t hwTimestamp, std::vector<float> values) - : NotifyArgs(id, eventTime), - deviceId(deviceId), - source(source), - sensorType(sensorType), - accuracy(accuracy), - accuracyChanged(accuracyChanged), - hwTimestamp(hwTimestamp), - values(std::move(values)) {} - -NotifySensorArgs::NotifySensorArgs(const NotifySensorArgs& other) - : NotifyArgs(other.id, other.eventTime), - deviceId(other.deviceId), - source(other.source), - sensorType(other.sensorType), - accuracy(other.accuracy), - accuracyChanged(other.accuracyChanged), - hwTimestamp(other.hwTimestamp), - values(other.values) {} - -bool NotifySensorArgs::operator==(const NotifySensorArgs rhs) const { - return id == rhs.id && eventTime == rhs.eventTime && sensorType == rhs.sensorType && - accuracy == rhs.accuracy && accuracyChanged == rhs.accuracyChanged && - hwTimestamp == rhs.hwTimestamp && values == rhs.values; -} - -void NotifySensorArgs::notify(InputListenerInterface& listener) const { - listener.notifySensor(this); -} - -// --- NotifyVibratorStateArgs --- - -NotifyVibratorStateArgs::NotifyVibratorStateArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, - bool isOn) - : NotifyArgs(id, eventTime), deviceId(deviceId), isOn(isOn) {} - -NotifyVibratorStateArgs::NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other) - : NotifyArgs(other.id, other.eventTime), deviceId(other.deviceId), isOn(other.isOn) {} - -bool NotifyVibratorStateArgs::operator==(const NotifyVibratorStateArgs rhs) const { - return id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId && - isOn == rhs.isOn; -} - -void NotifyVibratorStateArgs::notify(InputListenerInterface& listener) const { - listener.notifyVibratorState(this); -} - -// --- NotifyDeviceResetArgs --- - -NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId) - : NotifyArgs(id, eventTime), deviceId(deviceId) {} - -NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) - : NotifyArgs(other.id, other.eventTime), deviceId(other.deviceId) {} - -bool NotifyDeviceResetArgs::operator==(const NotifyDeviceResetArgs& rhs) const { - return id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId; -} - -void NotifyDeviceResetArgs::notify(InputListenerInterface& listener) const { - listener.notifyDeviceReset(this); -} - -// --- NotifyPointerCaptureChangedArgs --- - -NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs( - int32_t id, nsecs_t eventTime, const PointerCaptureRequest& request) - : NotifyArgs(id, eventTime), request(request) {} - -NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs( - const NotifyPointerCaptureChangedArgs& other) - : NotifyArgs(other.id, other.eventTime), request(other.request) {} - -bool NotifyPointerCaptureChangedArgs::operator==(const NotifyPointerCaptureChangedArgs& rhs) const { - return id == rhs.id && eventTime == rhs.eventTime && request == rhs.request; -} - -void NotifyPointerCaptureChangedArgs::notify(InputListenerInterface& listener) const { - listener.notifyPointerCaptureChanged(this); +// --- InputListenerInterface --- + +// Helper to std::visit with lambdas. +template <typename... V> +struct Visitor : V... {}; +// explicit deduction guide (not needed as of C++20) +template <typename... V> +Visitor(V...) -> Visitor<V...>; + +void InputListenerInterface::notify(const NotifyArgs& generalArgs) { + Visitor v{ + [&](const NotifyConfigurationChangedArgs& args) { notifyConfigurationChanged(&args); }, + [&](const NotifyKeyArgs& args) { notifyKey(&args); }, + [&](const NotifyMotionArgs& args) { notifyMotion(&args); }, + [&](const NotifySwitchArgs& args) { notifySwitch(&args); }, + [&](const NotifySensorArgs& args) { notifySensor(&args); }, + [&](const NotifyVibratorStateArgs& args) { notifyVibratorState(&args); }, + [&](const NotifyDeviceResetArgs& args) { notifyDeviceReset(&args); }, + [&](const NotifyPointerCaptureChangedArgs& args) { + notifyPointerCaptureChanged(&args); + }, + }; + std::visit(v, generalArgs); } // --- QueuedInputListener --- @@ -350,47 +71,47 @@ QueuedInputListener::QueuedInputListener(InputListenerInterface& innerListener) void QueuedInputListener::notifyConfigurationChanged( const NotifyConfigurationChangedArgs* args) { traceEvent(__func__, args->id); - mArgsQueue.emplace_back(std::make_unique<NotifyConfigurationChangedArgs>(*args)); + mArgsQueue.emplace_back(*args); } void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { traceEvent(__func__, args->id); - mArgsQueue.emplace_back(std::make_unique<NotifyKeyArgs>(*args)); + mArgsQueue.emplace_back(*args); } void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { traceEvent(__func__, args->id); - mArgsQueue.emplace_back(std::make_unique<NotifyMotionArgs>(*args)); + mArgsQueue.emplace_back(*args); } void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { traceEvent(__func__, args->id); - mArgsQueue.emplace_back(std::make_unique<NotifySwitchArgs>(*args)); + mArgsQueue.emplace_back(*args); } void QueuedInputListener::notifySensor(const NotifySensorArgs* args) { traceEvent(__func__, args->id); - mArgsQueue.emplace_back(std::make_unique<NotifySensorArgs>(*args)); + mArgsQueue.emplace_back(*args); } void QueuedInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) { traceEvent(__func__, args->id); - mArgsQueue.emplace_back(std::make_unique<NotifyVibratorStateArgs>(*args)); + mArgsQueue.emplace_back(*args); } void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { traceEvent(__func__, args->id); - mArgsQueue.emplace_back(std::make_unique<NotifyDeviceResetArgs>(*args)); + mArgsQueue.emplace_back(*args); } void QueuedInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { traceEvent(__func__, args->id); - mArgsQueue.emplace_back(std::make_unique<NotifyPointerCaptureChangedArgs>(*args)); + mArgsQueue.emplace_back(*args); } void QueuedInputListener::flush() { - for (const std::unique_ptr<NotifyArgs>& args : mArgsQueue) { - args->notify(mInnerListener); + for (const NotifyArgs& args : mArgsQueue) { + mInnerListener.notify(args); } mArgsQueue.clear(); } diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 9767cd9b71..9182503692 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -55,14 +55,14 @@ static int32_t exceptionCodeFromStatusT(status_t status) { /** * The event flow is via the "InputListener" interface, as follows: - * InputReader -> UnwantedInteractionBlocker -> InputClassifier -> InputDispatcher + * InputReader -> UnwantedInteractionBlocker -> InputProcessor -> InputDispatcher */ InputManager::InputManager( const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = createInputDispatcher(dispatcherPolicy); - mClassifier = std::make_unique<InputClassifier>(*mDispatcher); - mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier); + mProcessor = std::make_unique<InputProcessor>(*mDispatcher); + mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mProcessor); mReader = createInputReader(readerPolicy, *mBlocker); } @@ -110,12 +110,12 @@ InputReaderInterface& InputManager::getReader() { return *mReader; } -UnwantedInteractionBlockerInterface& InputManager::getUnwantedInteractionBlocker() { +UnwantedInteractionBlockerInterface& InputManager::getBlocker() { return *mBlocker; } -InputClassifierInterface& InputManager::getClassifier() { - return *mClassifier; +InputProcessorInterface& InputManager::getProcessor() { + return *mProcessor; } InputDispatcherInterface& InputManager::getDispatcher() { @@ -125,7 +125,7 @@ InputDispatcherInterface& InputManager::getDispatcher() { void InputManager::monitor() { mReader->monitor(); mBlocker->monitor(); - mClassifier->monitor(); + mProcessor->monitor(); mDispatcher->monitor(); } diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 8aad35bf1e..11371934c2 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -14,14 +14,13 @@ * limitations under the License. */ -#ifndef _UI_INPUT_MANAGER_H -#define _UI_INPUT_MANAGER_H +#pragma once /** * Native input manager. */ -#include "InputClassifier.h" +#include "InputProcessor.h" #include "InputReaderBase.h" #include "include/UnwantedInteractionBlockerInterface.h" @@ -52,10 +51,11 @@ class InputDispatcherThread; * this could be a palm on the screen. This stage would alter the event stream to remove either * partially (some of the pointers) or fully (all touches) the unwanted interaction. The events * are processed on the InputReader thread, without any additional queue. The events are then - * posted to the queue managed by the InputClassifier. - * 3. The InputClassifier class starts a thread to communicate with the device-specific - * classifiers. It then waits on the queue of events from UnwantedInteractionBlocker, applies - * a classification to them, and queues them for the InputDispatcher. + * posted to the queue managed by the InputProcessor. + * 3. The InputProcessor class starts a thread to communicate with the device-specific + * IInputProcessor HAL. It then waits on the queue of events from UnwantedInteractionBlocker, + * processes the events (for example, applies a classification to the events), and queues them + * for the InputDispatcher. * 4. The InputDispatcher class starts a thread that waits for new events on the * previous queue and asynchronously dispatches them to applications. * @@ -83,10 +83,10 @@ public: virtual InputReaderInterface& getReader() = 0; /* Gets the unwanted interaction blocker. */ - virtual UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() = 0; + virtual UnwantedInteractionBlockerInterface& getBlocker() = 0; - /* Gets the input classifier */ - virtual InputClassifierInterface& getClassifier() = 0; + /* Gets the input processor */ + virtual InputProcessorInterface& getProcessor() = 0; /* Gets the input dispatcher. */ virtual InputDispatcherInterface& getDispatcher() = 0; @@ -108,8 +108,8 @@ public: status_t stop() override; InputReaderInterface& getReader() override; - UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() override; - InputClassifierInterface& getClassifier() override; + UnwantedInteractionBlockerInterface& getBlocker() override; + InputProcessorInterface& getProcessor() override; InputDispatcherInterface& getDispatcher() override; void monitor() override; @@ -123,11 +123,9 @@ private: std::unique_ptr<UnwantedInteractionBlockerInterface> mBlocker; - std::unique_ptr<InputClassifierInterface> mClassifier; + std::unique_ptr<InputProcessorInterface> mProcessor; std::unique_ptr<InputDispatcherInterface> mDispatcher; }; } // namespace android - -#endif // _UI_INPUT_MANAGER_H diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputProcessor.cpp index 8ce2f35d7b..02d62bffb2 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputProcessor.cpp @@ -14,20 +14,21 @@ * limitations under the License. */ -#define LOG_TAG "InputClassifier" +#define LOG_TAG "InputProcessor" -#include "InputClassifier.h" +#include "InputProcessor.h" #include "InputCommonConverter.h" #include <android-base/stringprintf.h> #include <android/binder_manager.h> #include <android/binder_process.h> +#include <input/Input.h> #include <inttypes.h> #include <log/log.h> #include <algorithm> #include <cmath> #if defined(__linux__) - #include <pthread.h> +#include <pthread.h> #endif #include <unordered_set> @@ -44,10 +45,10 @@ using aidl::android::hardware::input::processor::IInputProcessor; namespace android { -//Max number of elements to store in mEvents. +// Max number of elements to store in mEvents. static constexpr size_t MAX_EVENTS = 5; -template<class K, class V> +template <class K, class V> static V getValueForKey(const std::unordered_map<K, V>& map, K key, V defaultValue) { auto it = map.find(key); if (it == map.end()) { @@ -123,40 +124,38 @@ ScopedDeathRecipient::~ScopedDeathRecipient() { // --- ClassifierEvent --- -ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) : - type(ClassifierEventType::MOTION), args(std::move(args)) { }; -ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args) : - type(ClassifierEventType::DEVICE_RESET), args(std::move(args)) { }; -ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args) : - type(type), args(std::move(args)) { }; +ClassifierEvent::ClassifierEvent(const NotifyMotionArgs& args) + : type(ClassifierEventType::MOTION), args(args){}; -ClassifierEvent::ClassifierEvent(ClassifierEvent&& other) : - type(other.type), args(std::move(other.args)) { }; +ClassifierEvent::ClassifierEvent(const NotifyDeviceResetArgs& args) + : type(ClassifierEventType::DEVICE_RESET), args(args){}; + +ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::optional<NotifyArgs> args) + : type(type), args(args){}; ClassifierEvent& ClassifierEvent::operator=(ClassifierEvent&& other) { type = other.type; - args = std::move(other.args); + args = other.args; return *this; } ClassifierEvent ClassifierEvent::createHalResetEvent() { - return ClassifierEvent(ClassifierEventType::HAL_RESET, nullptr); + return ClassifierEvent(ClassifierEventType::HAL_RESET, std::nullopt); } ClassifierEvent ClassifierEvent::createExitEvent() { - return ClassifierEvent(ClassifierEventType::EXIT, nullptr); + return ClassifierEvent(ClassifierEventType::EXIT, std::nullopt); } std::optional<int32_t> ClassifierEvent::getDeviceId() const { switch (type) { case ClassifierEventType::MOTION: { - NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(args.get()); - return motionArgs->deviceId; + const NotifyMotionArgs& motionArgs = std::get<NotifyMotionArgs>(*args); + return motionArgs.deviceId; } case ClassifierEventType::DEVICE_RESET: { - NotifyDeviceResetArgs* deviceResetArgs = - static_cast<NotifyDeviceResetArgs*>(args.get()); - return deviceResetArgs->deviceId; + const NotifyDeviceResetArgs& deviceResetArgs = std::get<NotifyDeviceResetArgs>(*args); + return deviceResetArgs.deviceId; } case ClassifierEventType::HAL_RESET: { return std::nullopt; @@ -180,7 +179,7 @@ MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> service) mHalThread = std::thread(&MotionClassifier::processEvents, this); #if defined(__linux__) // Set the thread name for debugging - pthread_setname_np(mHalThread.native_handle(), "InputClassifier"); + pthread_setname_np(mHalThread.native_handle(), "InputProcessor"); #endif } @@ -198,7 +197,7 @@ MotionClassifier::~MotionClassifier() { /** * Obtain the classification from the HAL for a given MotionEvent. - * Should only be called from the InputClassifier thread (mHalThread). + * Should only be called from the InputProcessor thread (mHalThread). * Should not be called from the thread that notifyMotion runs on. * * There is no way to provide a timeout for a HAL call. So if the HAL takes too long @@ -212,12 +211,12 @@ void MotionClassifier::processEvents() { bool halResponseOk = true; switch (event.type) { case ClassifierEventType::MOTION: { - NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get()); - common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs); + NotifyMotionArgs& motionArgs = std::get<NotifyMotionArgs>(*event.args); + common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(motionArgs); common::Classification classification; ndk::ScopedAStatus response = mService->classify(motionEvent, &classification); if (response.isOk()) { - updateClassification(motionArgs->deviceId, motionArgs->eventTime, + updateClassification(motionArgs.deviceId, motionArgs.eventTime, getMotionClassification(classification)); } break; @@ -239,8 +238,8 @@ void MotionClassifier::processEvents() { } } if (!halResponseOk) { - ALOGE("Error communicating with InputClassifier HAL. " - "Exiting MotionClassifier HAL thread"); + ALOGE("Error communicating with InputProcessor HAL. " + "Exiting MotionClassifier HAL thread"); clearClassifications(); return; } @@ -262,14 +261,14 @@ void MotionClassifier::requestExit() { } void MotionClassifier::updateClassification(int32_t deviceId, nsecs_t eventTime, - MotionClassification classification) { + MotionClassification classification) { std::scoped_lock lock(mLock); const nsecs_t lastDownTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0)); if (eventTime < lastDownTime) { // HAL just finished processing an event that belonged to an earlier gesture, // but new gesture is already in progress. Drop this classification. ALOGW("Received late classification. Late by at least %" PRId64 " ms.", - nanoseconds_to_milliseconds(lastDownTime - eventTime)); + nanoseconds_to_milliseconds(lastDownTime - eventTime)); return; } mClassifications[deviceId] = classification; @@ -307,8 +306,7 @@ MotionClassification MotionClassifier::classify(const NotifyMotionArgs& args) { updateLastDownTime(args.deviceId, args.downTime); } - ClassifierEvent event(std::make_unique<NotifyMotionArgs>(args)); - enqueueEvent(std::move(event)); + enqueueEvent(args); return getClassification(args.deviceId); } @@ -319,66 +317,66 @@ void MotionClassifier::reset() { /** * Per-device reset. Clear the outstanding events that are going to be sent to HAL. - * Request InputClassifier thread to call resetDevice for this particular device. + * Request InputProcessor thread to call resetDevice for this particular device. */ void MotionClassifier::reset(const NotifyDeviceResetArgs& args) { int32_t deviceId = args.deviceId; // Clear the pending events right away, to avoid unnecessary work done by the HAL. mEvents.erase([deviceId](const ClassifierEvent& event) { - std::optional<int32_t> eventDeviceId = event.getDeviceId(); - return eventDeviceId && (*eventDeviceId == deviceId); + std::optional<int32_t> eventDeviceId = event.getDeviceId(); + return eventDeviceId && (*eventDeviceId == deviceId); }); - enqueueEvent(std::make_unique<NotifyDeviceResetArgs>(args)); -} - -const char* MotionClassifier::getServiceStatus() REQUIRES(mLock) { - if (!mService) { - return "null"; - } - - if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) { - return "running"; - } - return "not responding"; + enqueueEvent(args); } void MotionClassifier::dump(std::string& dump) { std::scoped_lock lock(mLock); - dump += StringPrintf(INDENT2 "mService status: %s\n", getServiceStatus()); - dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n", - mEvents.size(), MAX_EVENTS); + dump += StringPrintf(INDENT2 "mService connected: %s\n", mService ? "true" : "false"); + dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n", mEvents.size(), MAX_EVENTS); dump += INDENT2 "mClassifications, mLastDownTimes:\n"; dump += INDENT3 "Device Id\tClassification\tLast down time"; // Combine mClassifications and mLastDownTimes into a single table. // Create a superset of device ids. std::unordered_set<int32_t> deviceIds; std::for_each(mClassifications.begin(), mClassifications.end(), - [&deviceIds](auto pair){ deviceIds.insert(pair.first); }); + [&deviceIds](auto pair) { deviceIds.insert(pair.first); }); std::for_each(mLastDownTimes.begin(), mLastDownTimes.end(), - [&deviceIds](auto pair){ deviceIds.insert(pair.first); }); - for(int32_t deviceId : deviceIds) { + [&deviceIds](auto pair) { deviceIds.insert(pair.first); }); + for (int32_t deviceId : deviceIds) { const MotionClassification classification = getValueForKey(mClassifications, deviceId, MotionClassification::NONE); const nsecs_t downTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0)); - dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64, - deviceId, motionClassificationToString(classification), downTime); + dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64, deviceId, + motionClassificationToString(classification), downTime); } } -// --- InputClassifier --- +void MotionClassifier::monitor() { + std::scoped_lock lock(mLock); + if (mService) { + // Ping the HAL service to ensure it is alive and not blocked. + const binder_status_t status = AIBinder_ping(mService->asBinder().get()); + if (status != STATUS_OK) { + ALOGW("IInputProcessor HAL is not responding; binder ping result: %s", + AStatus_getDescription(AStatus_fromStatus(status))); + } + } +} + +// --- InputProcessor --- -InputClassifier::InputClassifier(InputListenerInterface& listener) : mQueuedListener(listener) {} +InputProcessor::InputProcessor(InputListenerInterface& listener) : mQueuedListener(listener) {} -void InputClassifier::onBinderDied(void* cookie) { - InputClassifier* classifier = static_cast<InputClassifier*>(cookie); - if (classifier == nullptr) { +void InputProcessor::onBinderDied(void* cookie) { + InputProcessor* processor = static_cast<InputProcessor*>(cookie); + if (processor == nullptr) { LOG_ALWAYS_FATAL("Cookie is not valid"); return; } - classifier->setMotionClassifierEnabled(false); + processor->setMotionClassifierEnabled(false); } -void InputClassifier::setMotionClassifierEnabled(bool enabled) { +void InputProcessor::setMotionClassifierEnabled(bool enabled) { std::scoped_lock lock(mLock); if (enabled) { ALOGI("Enabling motion classifier"); @@ -391,7 +389,7 @@ void InputClassifier::setMotionClassifierEnabled(bool enabled) { * and we can't continue because 'mInitializeMotionClassifier' will block in its * destructor. */ - LOG_ALWAYS_FATAL("The thread to load IInputClassifier is stuck!"); + LOG_ALWAYS_FATAL("The thread to load IInputProcessor is stuck!"); } } mInitializeMotionClassifier = std::async(std::launch::async, [this] { @@ -415,19 +413,19 @@ void InputClassifier::setMotionClassifierEnabled(bool enabled) { } } -void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { +void InputProcessor::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { // pass through mQueuedListener.notifyConfigurationChanged(args); mQueuedListener.flush(); } -void InputClassifier::notifyKey(const NotifyKeyArgs* args) { +void InputProcessor::notifyKey(const NotifyKeyArgs* args) { // pass through mQueuedListener.notifyKey(args); mQueuedListener.flush(); } -void InputClassifier::notifyMotion(const NotifyMotionArgs* args) { +void InputProcessor::notifyMotion(const NotifyMotionArgs* args) { { // acquire lock std::scoped_lock lock(mLock); // MotionClassifier is only used for touch events, for now @@ -436,32 +434,38 @@ void InputClassifier::notifyMotion(const NotifyMotionArgs* args) { mQueuedListener.notifyMotion(args); } else { NotifyMotionArgs newArgs(*args); - newArgs.classification = mMotionClassifier->classify(newArgs); + const MotionClassification newClassification = mMotionClassifier->classify(newArgs); + LOG_ALWAYS_FATAL_IF(args->classification != MotionClassification::NONE && + newClassification != MotionClassification::NONE, + "Conflicting classifications %s (new) and %s (old)!", + motionClassificationToString(newClassification), + motionClassificationToString(args->classification)); + newArgs.classification = newClassification; mQueuedListener.notifyMotion(&newArgs); } } // release lock mQueuedListener.flush(); } -void InputClassifier::notifySensor(const NotifySensorArgs* args) { +void InputProcessor::notifySensor(const NotifySensorArgs* args) { // pass through mQueuedListener.notifySensor(args); mQueuedListener.flush(); } -void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) { +void InputProcessor::notifyVibratorState(const NotifyVibratorStateArgs* args) { // pass through mQueuedListener.notifyVibratorState(args); mQueuedListener.flush(); } -void InputClassifier::notifySwitch(const NotifySwitchArgs* args) { +void InputProcessor::notifySwitch(const NotifySwitchArgs* args) { // pass through mQueuedListener.notifySwitch(args); mQueuedListener.flush(); } -void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { +void InputProcessor::notifyDeviceReset(const NotifyDeviceResetArgs* args) { { // acquire lock std::scoped_lock lock(mLock); if (mMotionClassifier) { @@ -474,13 +478,13 @@ void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mQueuedListener.flush(); } -void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { +void InputProcessor::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { // pass through mQueuedListener.notifyPointerCaptureChanged(args); mQueuedListener.flush(); } -void InputClassifier::setMotionClassifierLocked( +void InputProcessor::setMotionClassifierLocked( std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) { if (motionClassifier == nullptr) { // Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath. @@ -490,9 +494,9 @@ void InputClassifier::setMotionClassifierLocked( mMotionClassifier = std::move(motionClassifier); } -void InputClassifier::dump(std::string& dump) { +void InputProcessor::dump(std::string& dump) { std::scoped_lock lock(mLock); - dump += "Input Classifier State:\n"; + dump += "Input Processor State:\n"; dump += INDENT1 "Motion Classifier:\n"; if (mMotionClassifier) { mMotionClassifier->dump(dump); @@ -502,11 +506,11 @@ void InputClassifier::dump(std::string& dump) { dump += "\n"; } -void InputClassifier::monitor() { +void InputProcessor::monitor() { std::scoped_lock lock(mLock); + if (mMotionClassifier) mMotionClassifier->monitor(); } -InputClassifier::~InputClassifier() { -} +InputProcessor::~InputProcessor() {} } // namespace android diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputProcessor.h index 56cf760256..f4d02b6f30 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputProcessor.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_CLASSIFIER_H -#define _UI_INPUT_CLASSIFIER_H +#pragma once #include <android-base/thread_annotations.h> #include <future> @@ -36,12 +35,12 @@ enum class ClassifierEventType : uint8_t { struct ClassifierEvent { ClassifierEventType type; - std::unique_ptr<NotifyArgs> args; + std::optional<NotifyArgs> args; - ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args); - ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args); - ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args); - ClassifierEvent(ClassifierEvent&& other); + ClassifierEvent(ClassifierEventType type, std::optional<NotifyArgs> args); + ClassifierEvent(const NotifyMotionArgs& args); + ClassifierEvent(const NotifyDeviceResetArgs& args); + ClassifierEvent(ClassifierEvent&& other) = default; ClassifierEvent& operator=(ClassifierEvent&& other); // Convenience function to create a HAL_RESET event @@ -61,8 +60,8 @@ struct ClassifierEvent { */ class MotionClassifierInterface { public: - MotionClassifierInterface() { } - virtual ~MotionClassifierInterface() { } + MotionClassifierInterface() {} + virtual ~MotionClassifierInterface() {} /** * Based on the motion event described by NotifyMotionArgs, * provide a MotionClassification for the current gesture. @@ -78,16 +77,21 @@ public: virtual void reset(const NotifyDeviceResetArgs& args) = 0; /** - * Dump the state of the motion classifier + * Dump the state of the motion classifier. */ virtual void dump(std::string& dump) = 0; + + /** + * Called by the heartbeat to ensure the HAL is still processing normally. + */ + virtual void monitor() = 0; }; /** * Base interface for an InputListener stage. * Provides classification to events. */ -class InputClassifierInterface : public InputListenerInterface { +class InputProcessorInterface : public InputListenerInterface { public: virtual void setMotionClassifierEnabled(bool enabled) = 0; /** @@ -96,11 +100,11 @@ public: */ virtual void dump(std::string& dump) = 0; - /* Called by the heatbeat to ensures that the classifier has not deadlocked. */ + /** Called by the heartbeat to ensure that the classifier has not deadlocked. */ virtual void monitor() = 0; - InputClassifierInterface() { } - virtual ~InputClassifierInterface() { } + InputProcessorInterface() {} + virtual ~InputProcessorInterface() {} }; // --- Implementations --- @@ -119,10 +123,10 @@ private: }; /** - * Implementation of MotionClassifierInterface that calls the InputClassifier HAL + * Implementation of MotionClassifierInterface that calls the InputProcessor HAL * in order to determine the classification for the current gesture. * - * The InputClassifier HAL may keep track of the entire gesture in order to determine + * The InputProcessor HAL may keep track of the entire gesture in order to determine * the classification, and may be hardware-specific. It may use the data in * NotifyMotionArgs::videoFrames field to drive the classification decisions. * The HAL is called from a separate thread. @@ -155,33 +159,34 @@ public: virtual void reset(const NotifyDeviceResetArgs& args) override; virtual void dump(std::string& dump) override; + virtual void monitor() override; private: friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation explicit MotionClassifier( std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service); - // The events that need to be sent to the HAL. + /** The events that need to be sent to the HAL. */ BlockingQueue<ClassifierEvent> mEvents; /** * Add an event to the queue mEvents. */ void enqueueEvent(ClassifierEvent&& event); /** - * Thread that will communicate with InputClassifier HAL. - * This should be the only thread that communicates with InputClassifier HAL, + * Thread that will communicate with InputProcessor HAL. + * This should be the only thread that communicates with InputProcessor HAL, * because this thread is allowed to block on the HAL calls. */ std::thread mHalThread; /** - * Process events and call the InputClassifier HAL + * Process events and call the InputProcessor HAL */ void processEvents(); /** * Access to the InputProcessor HAL. May be null if init() hasn't completed yet. * When init() successfully completes, mService is guaranteed to remain non-null and to not * change its value until MotionClassifier is destroyed. - * This variable is *not* guarded by mLock in the InputClassifier thread, because + * This variable is *not* guarded by mLock in the InputProcessor thread, because * that thread knows exactly when this variable is initialized. * When accessed in any other thread, mService is checked for nullness with a lock. */ @@ -191,8 +196,8 @@ private: * Per-device input classifications. Should only be accessed using the * getClassification / setClassification methods. */ - std::unordered_map<int32_t /*deviceId*/, MotionClassification> - mClassifications GUARDED_BY(mLock); + std::unordered_map<int32_t /*deviceId*/, MotionClassification> mClassifications + GUARDED_BY(mLock); /** * Set the current classification for a given device. */ @@ -202,7 +207,7 @@ private: */ MotionClassification getClassification(int32_t deviceId); void updateClassification(int32_t deviceId, nsecs_t eventTime, - MotionClassification classification); + MotionClassification classification); /** * Clear all current classifications */ @@ -211,7 +216,7 @@ private: * Per-device times when the last ACTION_DOWN was received. * Used to reject late classifications that do not belong to the current gesture. * - * Accessed indirectly by both InputClassifier thread and the thread that receives notifyMotion. + * Accessed indirectly by both InputProcessor thread and the thread that receives notifyMotion. */ std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock); @@ -220,7 +225,7 @@ private: void clearDeviceState(int32_t deviceId); /** - * Exit the InputClassifier HAL thread. + * Exit the InputProcessor HAL thread. * Useful for tests to ensure proper cleanup. */ void requestExit(); @@ -231,14 +236,14 @@ private: }; /** - * Implementation of the InputClassifierInterface. + * Implementation of the InputProcessorInterface. * Represents a separate stage of input processing. All of the input events go through this stage. * Acts as a passthrough for all input events except for motion events. * The events of motion type are sent to MotionClassifier. */ -class InputClassifier : public InputClassifierInterface { +class InputProcessor : public InputProcessorInterface { public: - explicit InputClassifier(InputListenerInterface& listener); + explicit InputProcessor(InputListenerInterface& listener); void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; void notifyKey(const NotifyKeyArgs* args) override; @@ -252,7 +257,7 @@ public: void dump(std::string& dump) override; void monitor() override; - ~InputClassifier(); + ~InputProcessor(); // Called from InputManager void setMotionClassifierEnabled(bool enabled) override; @@ -282,4 +287,3 @@ private: }; } // namespace android -#endif diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp index b87f7a1243..e2e64f992f 100644 --- a/services/inputflinger/InputThread.cpp +++ b/services/inputflinger/InputThread.cpp @@ -41,7 +41,7 @@ private: InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake) : mName(name), mThreadWake(wake) { - mThread = new InputThreadImpl(loop); + mThread = sp<InputThreadImpl>::make(loop); mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY); } diff --git a/services/inputflinger/NotifyArgs.cpp b/services/inputflinger/NotifyArgs.cpp new file mode 100644 index 0000000000..1f37774218 --- /dev/null +++ b/services/inputflinger/NotifyArgs.cpp @@ -0,0 +1,228 @@ +/* + * 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. + */ + +#define LOG_TAG "NotifyArgs" + +#define ATRACE_TAG ATRACE_TAG_INPUT + +#include "NotifyArgs.h" + +#include <android-base/stringprintf.h> +#include <android/log.h> +#include <math.h> +#include <utils/Trace.h> + +using android::base::StringPrintf; + +namespace android { + +// --- NotifyConfigurationChangedArgs --- + +NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime) + : id(id), eventTime(eventTime) {} + +// --- NotifyKeyArgs --- + +NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId, + uint32_t source, int32_t displayId, uint32_t policyFlags, + int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, + int32_t metaState, nsecs_t downTime) + : id(id), + eventTime(eventTime), + deviceId(deviceId), + source(source), + displayId(displayId), + policyFlags(policyFlags), + action(action), + flags(flags), + keyCode(keyCode), + scanCode(scanCode), + metaState(metaState), + downTime(downTime), + readTime(readTime) {} + +// --- NotifyMotionArgs --- + +NotifyMotionArgs::NotifyMotionArgs( + int32_t id, nsecs_t eventTime, nsecs_t readTime, 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, MotionClassification classification, + int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, float xPrecision, float yPrecision, + float xCursorPosition, float yCursorPosition, nsecs_t downTime, + const std::vector<TouchVideoFrame>& videoFrames) + : id(id), + eventTime(eventTime), + deviceId(deviceId), + source(source), + displayId(displayId), + policyFlags(policyFlags), + action(action), + actionButton(actionButton), + flags(flags), + metaState(metaState), + buttonState(buttonState), + classification(classification), + edgeFlags(edgeFlags), + pointerCount(pointerCount), + xPrecision(xPrecision), + yPrecision(yPrecision), + xCursorPosition(xCursorPosition), + yCursorPosition(yCursorPosition), + downTime(downTime), + readTime(readTime), + videoFrames(videoFrames) { + for (uint32_t i = 0; i < pointerCount; i++) { + this->pointerProperties[i].copyFrom(pointerProperties[i]); + this->pointerCoords[i].copyFrom(pointerCoords[i]); + } +} + +NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) + : id(other.id), + eventTime(other.eventTime), + deviceId(other.deviceId), + source(other.source), + displayId(other.displayId), + policyFlags(other.policyFlags), + action(other.action), + actionButton(other.actionButton), + flags(other.flags), + metaState(other.metaState), + buttonState(other.buttonState), + classification(other.classification), + edgeFlags(other.edgeFlags), + pointerCount(other.pointerCount), + xPrecision(other.xPrecision), + yPrecision(other.yPrecision), + xCursorPosition(other.xCursorPosition), + yCursorPosition(other.yCursorPosition), + downTime(other.downTime), + readTime(other.readTime), + videoFrames(other.videoFrames) { + for (uint32_t i = 0; i < pointerCount; i++) { + pointerProperties[i].copyFrom(other.pointerProperties[i]); + pointerCoords[i].copyFrom(other.pointerCoords[i]); + } +} + +static inline bool isCursorPositionEqual(float lhs, float rhs) { + return (isnan(lhs) && isnan(rhs)) || lhs == rhs; +} + +bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const { + bool equal = id == rhs.id && eventTime == rhs.eventTime && readTime == rhs.readTime && + deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId && + policyFlags == rhs.policyFlags && action == rhs.action && + actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState && + buttonState == rhs.buttonState && classification == rhs.classification && + edgeFlags == rhs.edgeFlags && + pointerCount == rhs.pointerCount + // PointerProperties and PointerCoords are compared separately below + && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision && + isCursorPositionEqual(xCursorPosition, rhs.xCursorPosition) && + isCursorPositionEqual(yCursorPosition, rhs.yCursorPosition) && + downTime == rhs.downTime && videoFrames == rhs.videoFrames; + if (!equal) { + return false; + } + + for (size_t i = 0; i < pointerCount; i++) { + equal = pointerProperties[i] == rhs.pointerProperties[i] && + pointerCoords[i] == rhs.pointerCoords[i]; + if (!equal) { + return false; + } + } + return true; +} + +std::string NotifyMotionArgs::dump() const { + std::string coords; + for (uint32_t i = 0; i < pointerCount; i++) { + if (!coords.empty()) { + coords += ", "; + } + coords += StringPrintf("{%" PRIu32 ": ", i); + coords += + StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f pressure=%.1f", pointerProperties[i].id, + pointerCoords[i].getX(), pointerCoords[i].getY(), + pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); + const int32_t toolType = pointerProperties[i].toolType; + if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) { + coords += StringPrintf(" toolType=%s", motionToolTypeToString(toolType)); + } + const float major = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR); + const float minor = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR); + const float orientation = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); + if (major != 0 || minor != 0) { + coords += StringPrintf(" major=%.1f minor=%.1f orientation=%.1f", major, minor, + orientation); + } + coords += "}"; + } + return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32 + ", source=%s, action=%s, pointerCount=%" PRIu32 + " pointers=%s, flags=0x%08x)", + id, eventTime, deviceId, inputEventSourceToString(source).c_str(), + MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str(), + flags); +} + +// --- NotifySwitchArgs --- + +NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, + uint32_t switchValues, uint32_t switchMask) + : id(id), + eventTime(eventTime), + policyFlags(policyFlags), + switchValues(switchValues), + switchMask(switchMask) {} + +// --- NotifySensorArgs --- + +NotifySensorArgs::NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, + InputDeviceSensorType sensorType, + InputDeviceSensorAccuracy accuracy, bool accuracyChanged, + nsecs_t hwTimestamp, std::vector<float> values) + : id(id), + eventTime(eventTime), + deviceId(deviceId), + source(source), + sensorType(sensorType), + accuracy(accuracy), + accuracyChanged(accuracyChanged), + hwTimestamp(hwTimestamp), + values(std::move(values)) {} + +// --- NotifyVibratorStateArgs --- + +NotifyVibratorStateArgs::NotifyVibratorStateArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, + bool isOn) + : id(id), eventTime(eventTime), deviceId(deviceId), isOn(isOn) {} + +// --- NotifyDeviceResetArgs --- + +NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId) + : id(id), eventTime(eventTime), deviceId(deviceId) {} + +// --- NotifyPointerCaptureChangedArgs --- + +NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs( + int32_t id, nsecs_t eventTime, const PointerCaptureRequest& request) + : id(id), eventTime(eventTime), request(request) {} + +} // namespace android diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index b4b617e188..4a0f2ec304 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -38,6 +38,7 @@ "name": "CtsViewTestCases", "options": [ { + "include-filter": "android.view.cts.input", "include-filter": "android.view.cts.MotionEventTest", "include-filter": "android.view.cts.PointerCaptureTest", "include-filter": "android.view.cts.VerifyInputEventTest" @@ -45,6 +46,101 @@ ] }, { + "name": "CtsWidgetTestCases", + "options": [ + { + "include-filter": "android.widget.cts.NumberPickerTest" + } + ] + }, + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.view.VerifiedKeyEventTest", + "include-filter": "android.view.VerifiedMotionEventTest" + } + ] + }, + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.input" + } + ] + }, + { + "name": "CtsSecurityTestCases", + "options": [ + { + "include-filter": "android.security.cts.MotionEventTest" + } + ] + }, + { + "name": "CtsSecurityBulletinHostTestCases", + "options": [ + { + "include-filter": "android.security.cts.Poc19_03#testPocBug_115739809" + } + ] + } + ], + "hwasan-postsubmit": [ + { + "name": "CtsWindowManagerDeviceTestCases", + "options": [ + { + "include-filter": "android.server.wm.WindowInputTests" + } + ] + }, + { + "name": "libinput_tests" + }, + { + "name": "inputflinger_tests" + }, + { + "name": "libpalmrejection_test" + }, + { + "name": "InputTests" + }, + { + "name": "libinputservice_test" + }, + { + "name": "CtsHardwareTestCases", + "options": [ + { + "include-filter": "android.hardware.input.cts.tests" + } + ] + }, + { + "name": "CtsInputTestCases" + }, + { + "name": "CtsViewTestCases", + "options": [ + { + "include-filter": "android.view.cts.MotionEventTest", + "include-filter": "android.view.cts.PointerCaptureTest", + "include-filter": "android.view.cts.VerifyInputEventTest" + } + ] + }, + { + "name": "CtsWidgetTestCases", + "options": [ + { + "include-filter": "android.widget.cts.NumberPickerTest" + } + ] + }, + { "name": "FrameworksCoreTests", "options": [ { diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp index 75071d55ac..e5c19afead 100644 --- a/services/inputflinger/benchmarks/Android.bp +++ b/services/inputflinger/benchmarks/Android.bp @@ -26,7 +26,6 @@ cc_benchmark { "libinputreporter", "liblog", "libstatslog", - "libui", "libutils", ], static_libs: [ diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index a2e60c4e6f..3d4dd7eabb 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -82,8 +82,6 @@ private: void notifyVibratorState(int32_t deviceId, bool isOn) override {} - void notifyUntrustedTouch(const std::string& obscuringPackage) override {} - void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override { *outConfig = mConfig; } @@ -260,14 +258,15 @@ static NotifyMotionArgs generateMotionArgs() { static void benchmarkNotifyMotion(benchmark::State& state) { // Create dispatcher - sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy(); + sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make(); InputDispatcher dispatcher(fakePolicy); dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); dispatcher.start(); // Create a window that will receive motion events std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window"); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window"); dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -294,14 +293,15 @@ static void benchmarkNotifyMotion(benchmark::State& state) { static void benchmarkInjectMotion(benchmark::State& state) { // Create dispatcher - sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy(); + sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make(); InputDispatcher dispatcher(fakePolicy); dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); dispatcher.start(); // Create a window that will receive motion events std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window"); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window"); dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -327,14 +327,15 @@ static void benchmarkInjectMotion(benchmark::State& state) { static void benchmarkOnWindowInfosChanged(benchmark::State& state) { // Create dispatcher - sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy(); + sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make(); InputDispatcher dispatcher(fakePolicy); dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); dispatcher.start(); // Create a window std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window"); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window"); std::vector<gui::WindowInfo> windowInfos{*window->getInfo()}; gui::DisplayInfo info; diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index cdad9c93fd..eb79b76b28 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -63,7 +63,6 @@ cc_defaults { "libstatslog", "libstatspull", "libstatssocket", - "libui", "libgui", "libutils", "server_configurable_flags", diff --git a/services/inputflinger/dispatcher/AnrTracker.h b/services/inputflinger/dispatcher/AnrTracker.h index 097dba5bea..5e5e0c4bae 100644 --- a/services/inputflinger/dispatcher/AnrTracker.h +++ b/services/inputflinger/dispatcher/AnrTracker.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H -#define _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H +#pragma once #include <binder/IBinder.h> #include <utils/Timers.h> @@ -56,5 +55,3 @@ private: }; } // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h index 99e2108dbf..d210e9e846 100644 --- a/services/inputflinger/dispatcher/CancelationOptions.h +++ b/services/inputflinger/dispatcher/CancelationOptions.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H -#define _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H +#pragma once +#include <utils/BitSet.h> #include <optional> -namespace android::inputdispatcher { +namespace android { +namespace inputdispatcher { /* Specifies which events are to be canceled and why. */ struct CancelationOptions { @@ -45,9 +46,11 @@ struct CancelationOptions { // The specific display id of events to cancel, or nullopt to cancel events on any display. std::optional<int32_t> displayId = std::nullopt; + // The specific pointers to cancel, or nullopt to cancel all pointer events + std::optional<BitSet32> pointerIds = std::nullopt; + CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) {} }; -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H +} // namespace inputdispatcher +} // namespace android diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h index dc6a081ff6..6040e9b078 100644 --- a/services/inputflinger/dispatcher/Connection.h +++ b/services/inputflinger/dispatcher/Connection.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_CONNECTION_H -#define _UI_INPUT_INPUTDISPATCHER_CONNECTION_H +#pragma once #include "InputState.h" @@ -74,5 +73,3 @@ public: }; } // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_CONNECTION_H diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h index 9a2aea69ec..d2ad40754a 100644 --- a/services/inputflinger/dispatcher/DebugConfig.h +++ b/services/inputflinger/dispatcher/DebugConfig.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H -#define _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H +#pragma once #define LOG_TAG "InputDispatcher" @@ -92,5 +91,3 @@ const bool DEBUG_APP_SWITCH = const bool DEBUG_HOVER = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Hover", ANDROID_LOG_INFO); } // namespace android::inputdispatcher - -#endif // _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
\ No newline at end of file diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h index d1c8b8a10e..9809148853 100644 --- a/services/inputflinger/dispatcher/DragState.h +++ b/services/inputflinger/dispatcher/DragState.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H -#define _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H +#pragma once #include <gui/WindowInfo.h> #include <utils/StrongPointer.h> @@ -44,5 +43,3 @@ struct DragState { } // namespace inputdispatcher } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H
\ No newline at end of file diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 8046bbe25c..33e7e17ec0 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -195,9 +195,10 @@ void KeyEntry::recycle() { // --- TouchModeEntry --- -TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode) +TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int displayId) : EventEntry(id, Type::TOUCH_MODE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER), - inTouchMode(inTouchMode) {} + inTouchMode(inTouchMode), + displayId(displayId) {} TouchModeEntry::~TouchModeEntry() {} diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 0f792967eb..60f319a056 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_ENTRY_H -#define _UI_INPUT_INPUTDISPATCHER_ENTRY_H +#pragma once #include "InjectionState.h" #include "InputTarget.h" @@ -211,8 +210,9 @@ struct SensorEntry : EventEntry { struct TouchModeEntry : EventEntry { bool inTouchMode; + int32_t displayId; - TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode); + TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int32_t displayId); std::string getDescription() const override; ~TouchModeEntry() override; @@ -257,5 +257,3 @@ VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry, const ui::Transform& rawTransform); } // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_ENTRY_H diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index a02b3e8779..4da846bcf8 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -13,24 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#define LOG_TAG "FocusResolver" +#define LOG_TAG "InputDispatcher" #define ATRACE_TAG ATRACE_TAG_INPUT #define INDENT " " #define INDENT2 " " -// Log debug messages about input focus tracking. -static constexpr bool DEBUG_FOCUS = false; - #include <inttypes.h> #include <android-base/stringprintf.h> #include <binder/Binder.h> #include <ftl/enum.h> #include <gui/WindowInfo.h> -#include <log/log.h> +#include "DebugConfig.h" #include "FocusResolver.h" using android::gui::FocusRequest; diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h index 90cf150ac3..d9e27ba50b 100644 --- a/services/inputflinger/dispatcher/InjectionState.h +++ b/services/inputflinger/dispatcher/InjectionState.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H -#define _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H +#pragma once #include <stdint.h> #include "InputDispatcherInterface.h" @@ -41,5 +40,3 @@ private: } // namespace inputdispatcher } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9d1adad7ec..399153c0d7 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -56,7 +56,6 @@ using android::gui::FocusRequest; using android::gui::TouchOcclusionMode; using android::gui::WindowInfo; using android::gui::WindowInfoHandle; -using android::os::BlockUntrustedTouchesMode; using android::os::IInputConstants; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; @@ -545,24 +544,19 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), - // mInTouchMode will be initialized by the WindowManager to the default device config. - // To avoid leaking stack in case that call never comes, and for tests, - // initialize it here anyways. - mInTouchMode(kDefaultInTouchMode), mMaximumObscuringOpacityForTouch(1.0f), mFocusedDisplayId(ADISPLAY_ID_DEFAULT), mWindowTokenWithPointerCapture(nullptr), mStaleEventTimeout(staleEventTimeout), mLatencyAggregator(), mLatencyTracker(&mLatencyAggregator) { - mLooper = new Looper(false); + mLooper = sp<Looper>::make(false); mReporter = createInputReporter(); - mWindowInfoListener = new DispatcherWindowListener(*this); + mWindowInfoListener = sp<DispatcherWindowListener>::make(*this); SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener); mKeyRepeatState.lastKeyEntry = nullptr; - policy->getDispatcherConfiguration(&mConfig); } @@ -1435,7 +1429,7 @@ void InputDispatcher::dispatchPointerCaptureChangedLocked( void InputDispatcher::dispatchTouchModeChangeLocked(nsecs_t currentTime, const std::shared_ptr<TouchModeEntry>& entry) { const std::vector<sp<WindowInfoHandle>>& windowHandles = - getWindowHandlesLocked(mFocusedDisplayId); + getWindowHandlesLocked(entry->displayId); if (windowHandles.empty()) { return; } @@ -1452,7 +1446,6 @@ std::vector<InputTarget> InputDispatcher::getInputTargetsFromWindowHandlesLocked const std::vector<sp<WindowInfoHandle>>& windowHandles) const { std::vector<InputTarget> inputTargets; for (const sp<WindowInfoHandle>& handle : windowHandles) { - // TODO(b/193718270): Due to performance concerns, consider notifying visible windows only. const sp<IBinder>& token = handle->getToken(); if (token == nullptr) { continue; @@ -1658,6 +1651,13 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< InputEventInjectionResult injectionResult; if (isPointerEvent) { // Pointer event. (eg. touchscreen) + + if (mDragState && + (entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) { + // If drag and drop ongoing and pointer down occur: pilfer drag window pointers + pilferPointersLocked(mDragState->dragWindow->getToken()); + } + injectionResult = findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime, &conflictingPointerActions); @@ -1866,6 +1866,17 @@ bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime, return false; } +static std::optional<nsecs_t> getDownTime(const EventEntry& eventEntry) { + if (eventEntry.type == EventEntry::Type::KEY) { + const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry); + return keyEntry.downTime; + } else if (eventEntry.type == EventEntry::Type::MOTION) { + const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry); + return motionEntry.downTime; + } + return std::nullopt; +} + InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( nsecs_t currentTime, const EventEntry& entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { @@ -1955,7 +1966,7 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( // Success! Output targets. addWindowTargetLocked(focusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0), inputTargets); + BitSet32(0), getDownTime(entry), inputTargets); // Done. return InputEventInjectionResult::SUCCEEDED; @@ -2152,23 +2163,17 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } // Drop events that can't be trusted due to occlusion - if (mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) { - TouchOcclusionInfo occlusionInfo = - computeTouchOcclusionInfoLocked(windowHandle, x, y); - if (!isTouchTrustedLocked(occlusionInfo)) { - if (DEBUG_TOUCH_OCCLUSION) { - ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y); - for (const auto& log : occlusionInfo.debugInfo) { - ALOGD("%s", log.c_str()); - } - } - sendUntrustedTouchCommandLocked(occlusionInfo.obscuringPackage); - if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) { - ALOGW("Dropping untrusted touch event due to %s/%d", - occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid); - continue; + TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(windowHandle, x, y); + if (!isTouchTrustedLocked(occlusionInfo)) { + if (DEBUG_TOUCH_OCCLUSION) { + ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y); + for (const auto& log : occlusionInfo.debugInfo) { + ALOGD("%s", log.c_str()); } } + ALOGW("Dropping untrusted touch event due to %s/%d", + occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid); + continue; } // Drop touch events if requested by input feature @@ -2197,8 +2202,18 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( BitSet32 pointerIds; pointerIds.markBit(entry.pointerProperties[pointerIndex].id); - tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds); + tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds, + entry.eventTime); + } + + // If any existing window is pilfering pointers from newly added window, remove it + BitSet32 canceledPointers = BitSet32(0); + for (const TouchedWindow& window : tempTouchState.windows) { + if (window.isPilferingPointers) { + canceledPointers |= window.pointerIds; + } } + tempTouchState.cancelPointersForNonPilferingWindows(canceledPointers); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ @@ -2273,7 +2288,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( BitSet32 pointerIds; pointerIds.markBit(entry.pointerProperties[0].id); - tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); + tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds, + entry.eventTime); } } } @@ -2390,7 +2406,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( InputTarget:: FLAG_WINDOW_IS_PARTIALLY_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); + BitSet32(0), entry.eventTime); } } } @@ -2401,7 +2417,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( for (const TouchedWindow& touchedWindow : tempTouchState.windows) { addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, inputTargets); + touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget, + inputTargets); } // Drop the outside or hover touch windows since we will not care about them @@ -2593,6 +2610,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, + std::optional<nsecs_t> firstDownTimeInTarget, std::vector<InputTarget>& inputTargets) { std::vector<InputTarget>::iterator it = std::find_if(inputTargets.begin(), inputTargets.end(), @@ -2614,6 +2632,7 @@ void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHa inputTarget.inputChannel = inputChannel; inputTarget.flags = targetFlags; inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; + inputTarget.firstDownTimeInTarget = firstDownTimeInTarget; const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId); if (displayInfoIt != mDisplayInfos.end()) { inputTarget.displayTransform = displayInfoIt->second.transform; @@ -2639,6 +2658,8 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& InputTarget target; target.inputChannel = monitor.inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; + // target.firstDownTimeInTarget is not set for global monitors. It is only required in split + // touch and global monitoring works as intended even without setting firstDownTimeInTarget if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) { target.displayTransform = it->second.transform; } @@ -2923,8 +2944,12 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry); if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) { + LOG_ALWAYS_FATAL_IF(!inputTarget.firstDownTimeInTarget.has_value(), + "Splitting motion events requires a down time to be set for the " + "target"); std::unique_ptr<MotionEntry> splitMotionEntry = - splitMotionEvent(originalMotionEntry, inputTarget.pointerIds); + splitMotionEvent(originalMotionEntry, inputTarget.pointerIds, + inputTarget.firstDownTimeInTarget.value()); if (!splitMotionEntry) { return; // split event was dropped } @@ -2959,7 +2984,7 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, ATRACE_NAME(message.c_str()); } - bool wasEmpty = connection->outboundQueue.empty(); + const bool wasEmpty = connection->outboundQueue.empty(); // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, @@ -3685,15 +3710,13 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( - const sp<Connection>& connection) { + const nsecs_t downTime, const sp<Connection>& connection) { if (connection->status == Connection::Status::BROKEN) { return; } - nsecs_t currentTime = now(); - std::vector<std::unique_ptr<EventEntry>> downEvents = - connection->inputState.synthesizePointerDownEvents(currentTime); + connection->inputState.synthesizePointerDownEvents(downTime); if (downEvents.empty()) { return; @@ -3716,7 +3739,6 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( target.flags = InputTarget::FLAG_DISPATCH_AS_IS; const bool wasEmpty = connection->outboundQueue.empty(); - for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) { switch (downEventEntry->type) { case EventEntry::Type::MOTION: { @@ -3742,14 +3764,15 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( enqueueDispatchEntryLocked(connection, std::move(downEventEntry), target, InputTarget::FLAG_DISPATCH_AS_IS); } + // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.empty()) { - startDispatchCycleLocked(currentTime, connection); + startDispatchCycleLocked(downTime, connection); } } std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( - const MotionEntry& originalMotionEntry, BitSet32 pointerIds) { + const MotionEntry& originalMotionEntry, BitSet32 pointerIds, nsecs_t splitDownTime) { ALOG_ASSERT(pointerIds.value != 0); uint32_t splitPointerIndexMap[MAX_POINTERS]; @@ -3817,6 +3840,13 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( } } + if (action == AMOTION_EVENT_ACTION_DOWN) { + LOG_ALWAYS_FATAL_IF(splitDownTime != originalMotionEntry.eventTime, + "Split motion event has mismatching downTime and eventTime for " + "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64 "ms", + originalMotionEntry.getDescription().c_str(), ns2ms(splitDownTime)); + } + int32_t newId = mIdGenerator.nextId(); if (ATRACE_ENABLED()) { std::string message = StringPrintf("Split MotionEvent(id=0x%" PRIx32 @@ -3837,9 +3867,9 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( originalMotionEntry.xPrecision, originalMotionEntry.yPrecision, originalMotionEntry.xCursorPosition, - originalMotionEntry.yCursorPosition, - originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords); + originalMotionEntry.yCursorPosition, splitDownTime, + splitPointerCount, splitPointerProperties, + splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -4970,19 +5000,25 @@ void InputDispatcher::setInputFilterEnabled(bool enabled) { mLooper->wake(); } -bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, - bool hasPermission) { +bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission, + int32_t displayId) { bool needWake = false; { std::scoped_lock lock(mLock); - if (mInTouchMode == inTouchMode) { + ALOGD_IF(DEBUG_TOUCH_MODE, + "Request to change touch mode to %s (calling pid=%d, uid=%d, " + "hasPermission=%s, target displayId=%d, mTouchModePerDisplay[displayId]=%s)", + toString(inTouchMode), pid, uid, toString(hasPermission), displayId, + mTouchModePerDisplay.count(displayId) == 0 + ? "not set" + : std::to_string(mTouchModePerDisplay[displayId]).c_str()); + + // TODO(b/198499018): Ensure that WM can guarantee that touch mode is properly set when + // display is created. + auto touchModeIt = mTouchModePerDisplay.find(displayId); + if (touchModeIt != mTouchModePerDisplay.end() && touchModeIt->second == inTouchMode) { return false; } - if (DEBUG_TOUCH_MODE) { - ALOGD("Request to change touch mode from %s to %s (calling pid=%d, uid=%d, " - "hasPermission=%s)", - toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission)); - } if (!hasPermission) { if (!focusedWindowIsOwnedByLocked(pid, uid) && !recentWindowsAreOwnedByLocked(pid, uid)) { @@ -4992,11 +5028,9 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, return false; } } - - // TODO(b/198499018): Store touch mode per display. - mInTouchMode = inTouchMode; - - auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode); + mTouchModePerDisplay[displayId] = inTouchMode; + auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode, + displayId); needWake = enqueueInboundEventLocked(std::move(entry)); } // release lock @@ -5034,11 +5068,6 @@ void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) { mMaximumObscuringOpacityForTouch = opacity; } -void InputDispatcher::setBlockUntrustedTouchesMode(BlockUntrustedTouchesMode mode) { - std::scoped_lock lock(mLock); - mBlockUntrustedTouchesMode = mode; -} - std::pair<TouchState*, TouchedWindow*> InputDispatcher::findTouchStateAndWindowLocked( const sp<IBinder>& token) { for (auto& [displayId, state] : mTouchStatesByDisplay) { @@ -5089,12 +5118,13 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< state->removeWindowByToken(fromToken); // Add new window. + nsecs_t downTimeInTarget = now(); int32_t newTargetFlags = oldTargetFlags & (InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) { newTargetFlags |= InputTarget::FLAG_FOREGROUND; } - state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); + state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds, downTimeInTarget); // Store the dragging window. if (isDragDrop) { @@ -5117,7 +5147,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< options(CancelationOptions::CANCEL_POINTER_EVENTS, "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); - synthesizePointerDownEventsForConnectionLocked(toConnection); + synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection); } if (DEBUG_FOCUS) { @@ -5267,10 +5297,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT3 "Windows:\n"; for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; - dump += StringPrintf(INDENT4 - "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, " + "targetFlags=0x%x, firstDownTimeInTarget=%" PRId64 + "ms\n", i, touchedWindow.windowHandle->getName().c_str(), - touchedWindow.pointerIds.value, touchedWindow.targetFlags); + touchedWindow.pointerIds.value, touchedWindow.targetFlags, + ns2ms(touchedWindow.firstDownTimeInTarget.value_or(0))); } } else { dump += INDENT3 "Windows: <none>\n"; @@ -5438,6 +5470,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT "AppSwitch: not pending\n"; } + if (!mTouchModePerDisplay.empty()) { + dump += INDENT "TouchModePerDisplay:\n"; + for (const auto& [displayId, touchMode] : mTouchModePerDisplay) { + dump += StringPrintf(INDENT2 "Display: %" PRId32 " TouchMode: %s\n", displayId, + std::to_string(touchMode).c_str()); + } + } else { + dump += INDENT "TouchModePerDisplay: <none>\n"; + } + dump += INDENT "Configuration:\n"; dump += StringPrintf(INDENT2 "KeyRepeatDelay: %" PRId64 "ms\n", ns2ms(mConfig.keyRepeatDelay)); dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %" PRId64 "ms\n", @@ -5483,7 +5525,7 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const const sp<IBinder>& token = serverChannel->getConnectionToken(); int fd = serverChannel->getFd(); sp<Connection> connection = - new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator); + sp<Connection>::make(std::move(serverChannel), false /*monitor*/, mIdGenerator); if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) { ALOGE("Created a new connection, but the token %p is already known", token.get()); @@ -5493,7 +5535,8 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback, this, std::placeholders::_1, token); - mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr); + mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback), + nullptr); } // release lock // Wake the looper because some connections have changed. @@ -5519,7 +5562,8 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(int32_ << " without a specified display."; } - sp<Connection> connection = new Connection(serverChannel, true /*monitor*/, mIdGenerator); + sp<Connection> connection = + sp<Connection>::make(serverChannel, true /*monitor*/, mIdGenerator); const sp<IBinder>& token = serverChannel->getConnectionToken(); const int fd = serverChannel->getFd(); @@ -5532,7 +5576,8 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(int32_ mGlobalMonitorsByDisplay[displayId].emplace_back(serverChannel, pid); - mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr); + mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback), + nullptr); } // Wake the looper because some connections have changed. @@ -5596,7 +5641,10 @@ void InputDispatcher::removeMonitorChannelLocked(const sp<IBinder>& connectionTo status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { std::scoped_lock _l(mLock); + return pilferPointersLocked(token); +} +status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { const std::shared_ptr<InputChannel> requestingChannel = getInputChannelLocked(token); if (!requestingChannel) { ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token"); @@ -5611,16 +5659,20 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { } TouchState& state = *statePtr; - + TouchedWindow& window = *windowPtr; // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "input channel stole pointer stream"); options.deviceId = state.deviceId; options.displayId = state.displayId; + if (state.split) { + // If split pointers then selectively cancel pointers otherwise cancel all pointers + options.pointerIds = window.pointerIds; + } std::string canceledWindows; - for (const TouchedWindow& window : state.windows) { + for (const TouchedWindow& w : state.windows) { const std::shared_ptr<InputChannel> channel = - getInputChannelLocked(window.windowHandle->getToken()); + getInputChannelLocked(w.windowHandle->getToken()); if (channel != nullptr && channel->getConnectionToken() != token) { synthesizeCancelationEventsForInputChannelLocked(channel, options); canceledWindows += canceledWindows.empty() ? "[" : ", "; @@ -5632,8 +5684,14 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { canceledWindows.c_str()); // Prevent the gesture from being sent to any other windows. - state.filterWindowsExcept(token); - state.preventNewTargets = true; + // This only blocks relevant pointers to be sent to other windows + window.isPilferingPointers = true; + + if (state.split) { + state.cancelPointersForWindowsExcept(window.pointerIds, token); + } else { + state.filterWindowsExcept(token); + } return OK; } @@ -5805,14 +5863,6 @@ void InputDispatcher::sendDropWindowCommandLocked(const sp<IBinder>& token, floa postCommandLocked(std::move(command)); } -void InputDispatcher::sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) { - auto command = [this, obscuringPackage]() REQUIRES(mLock) { - scoped_unlock unlock(mLock); - mPolicy->notifyUntrustedTouch(obscuringPackage); - }; - postCommandLocked(std::move(command)); -} - void InputDispatcher::onAnrLocked(const sp<Connection>& connection) { if (connection == nullptr) { LOG_ALWAYS_FATAL("Caller must check for nullness"); @@ -6322,6 +6372,8 @@ void InputDispatcher::displayRemoved(int32_t displayId) { mFocusResolver.displayRemoved(displayId); // Reset pointer capture eligibility, regardless of previous state. std::erase(mIneligibleDisplaysForPointerCapture, displayId); + // Remove the associated touch mode state. + mTouchModePerDisplay.erase(displayId); } // release lock // Wake up poll loop since it may need to make new input dispatching choices. @@ -6335,7 +6387,7 @@ void InputDispatcher::onWindowInfosChanged(const std::vector<WindowInfo>& window std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay; for (const auto& info : windowInfos) { handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>()); - handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info)); + handlesPerDisplay[info.displayId].push_back(sp<WindowInfoHandle>::make(info)); } { // acquire lock diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index ed89ed0b0f..630d21a95d 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_DISPATCHER_H -#define _UI_INPUT_DISPATCHER_H +#pragma once #include "AnrTracker.h" #include "CancelationOptions.h" @@ -42,7 +41,6 @@ #include <input/InputTransport.h> #include <limits.h> #include <stddef.h> -#include <ui/Region.h> #include <unistd.h> #include <utils/BitSet.h> #include <utils/Looper.h> @@ -119,9 +117,9 @@ public: void setFocusedDisplay(int32_t displayId) override; void setInputDispatchMode(bool enabled, bool frozen) override; void setInputFilterEnabled(bool enabled) override; - bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) override; + bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission, + int32_t displayId) override; void setMaximumObscuringOpacityForTouch(float opacity) override; - void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override; bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop = false) override; @@ -256,6 +254,8 @@ private: void removeConnectionLocked(const sp<Connection>& connection) REQUIRES(mLock); + status_t pilferPointersLocked(const sp<IBinder>& token) REQUIRES(mLock); + template <typename T> struct StrongPointerHash { std::size_t operator()(const sp<T>& b) const { return std::hash<T*>{}(b.get()); } @@ -342,9 +342,12 @@ private: bool mDispatchEnabled GUARDED_BY(mLock); bool mDispatchFrozen GUARDED_BY(mLock); bool mInputFilterEnabled GUARDED_BY(mLock); - bool mInTouchMode GUARDED_BY(mLock); float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock); - android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock); + + // This map is not really needed, but it helps a lot with debugging (dumpsys input). + // In the java layer, touch mode states are spread across multiple DisplayContent objects, + // making harder to snapshot and retrieve them. + std::map<int32_t /*displayId*/, bool /*inTouchMode*/> mTouchModePerDisplay GUARDED_BY(mLock); class DispatcherWindowListener : public gui::WindowInfosListener { public: @@ -384,7 +387,7 @@ private: bool hasResponsiveConnectionLocked(android::gui::WindowInfoHandle& windowHandle) const REQUIRES(mLock); - // Gets all the input targets (with their respective input channels) from the window handles + // Returns all the input targets (with their respective input channels) from the window handles // passed as argument. std::vector<InputTarget> getInputTargetsFromWindowHandlesLocked( const std::vector<sp<android::gui::WindowInfoHandle>>& windowHandles) const @@ -550,6 +553,7 @@ private: void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, + std::optional<nsecs_t> firstDownTimeInTarget, std::vector<InputTarget>& inputTargets) REQUIRES(mLock); void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId) REQUIRES(mLock); @@ -621,12 +625,14 @@ private: const CancelationOptions& options) REQUIRES(mLock); - void synthesizePointerDownEventsForConnectionLocked(const sp<Connection>& connection) + void synthesizePointerDownEventsForConnectionLocked(const nsecs_t downTime, + const sp<Connection>& connection) REQUIRES(mLock); - // Splitting motion events across windows. + // Splitting motion events across windows. When splitting motion event for a target, + // splitDownTime refers to the time of first 'down' event on that particular target std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry, - BitSet32 pointerIds); + BitSet32 pointerIds, nsecs_t splitDownTime); // Reset and drop everything the dispatcher is doing. void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock); @@ -652,7 +658,6 @@ private: void sendFocusChangedCommandLocked(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) REQUIRES(mLock); void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock); - void sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) REQUIRES(mLock); void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock); void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock); void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window, @@ -687,5 +692,3 @@ private: }; } // namespace android::inputdispatcher - -#endif // _UI_INPUT_DISPATCHER_H diff --git a/services/inputflinger/dispatcher/InputEventTimeline.h b/services/inputflinger/dispatcher/InputEventTimeline.h index 77b8472f89..daf375d918 100644 --- a/services/inputflinger/dispatcher/InputEventTimeline.h +++ b/services/inputflinger/dispatcher/InputEventTimeline.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTEVENTTIMELINE_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTEVENTTIMELINE_H +#pragma once #include <binder/IBinder.h> #include <input/Input.h> @@ -104,5 +103,3 @@ public: } // namespace inputdispatcher } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTEVENTTIMELINE_H diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index f46a8bce7e..047c628e67 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -286,19 +286,30 @@ std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents for (const MotionMemento& memento : mMotionMementos) { if (shouldCancelMotion(memento, options)) { - const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT - : AMOTION_EVENT_ACTION_CANCEL; - events.push_back( - std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, - memento.deviceId, memento.source, - memento.displayId, memento.policyFlags, action, - 0 /*actionButton*/, memento.flags, AMETA_NONE, - 0 /*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, - memento.yPrecision, memento.xCursorPosition, - memento.yCursorPosition, memento.downTime, - memento.pointerCount, memento.pointerProperties, - memento.pointerCoords)); + if (options.pointerIds == std::nullopt) { + const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT + : AMOTION_EVENT_ACTION_CANCEL; + events.push_back( + std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, + memento.deviceId, memento.source, + memento.displayId, memento.policyFlags, + action, 0 /*actionButton*/, memento.flags, + AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + memento.xPrecision, memento.yPrecision, + memento.xCursorPosition, + memento.yCursorPosition, memento.downTime, + memento.pointerCount, + memento.pointerProperties, + memento.pointerCoords)); + } else { + std::vector<std::unique_ptr<MotionEntry>> pointerCancelEvents = + synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(), + currentTime); + events.insert(events.end(), std::make_move_iterator(pointerCancelEvents.begin()), + std::make_move_iterator(pointerCancelEvents.end())); + } } } return events; @@ -359,6 +370,73 @@ std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents return events; } +std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEventsForPointers( + const MotionMemento& memento, const BitSet32 pointerIds, nsecs_t currentTime) { + std::vector<std::unique_ptr<MotionEntry>> events; + std::vector<uint32_t> canceledPointerIndices; + std::vector<PointerProperties> pointerProperties(MAX_POINTERS); + std::vector<PointerCoords> pointerCoords(MAX_POINTERS); + for (uint32_t pointerIdx = 0; pointerIdx < memento.pointerCount; pointerIdx++) { + uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id); + pointerProperties[pointerIdx].copyFrom(memento.pointerProperties[pointerIdx]); + pointerCoords[pointerIdx].copyFrom(memento.pointerCoords[pointerIdx]); + if (pointerIds.hasBit(pointerId)) { + canceledPointerIndices.push_back(pointerIdx); + } + } + + if (canceledPointerIndices.size() == memento.pointerCount) { + const int32_t action = + memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; + events.push_back( + std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId, + memento.source, memento.displayId, + memento.policyFlags, action, 0 /*actionButton*/, + memento.flags, AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, + memento.yPrecision, memento.xCursorPosition, + memento.yCursorPosition, memento.downTime, + memento.pointerCount, memento.pointerProperties, + memento.pointerCoords)); + } else { + // If we aren't canceling all pointers, we need to generated ACTION_POINTER_UP with + // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the + // previously canceled pointers from PointerProperties and PointerCoords, and update + // pointerCount appropriately. For convenience, sort the canceled pointer indices so that we + // can just slide the remaining pointers to the beginning of the array when a pointer is + // canceled. + std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(), + std::greater<uint32_t>()); + + uint32_t pointerCount = memento.pointerCount; + for (const uint32_t pointerIdx : canceledPointerIndices) { + const int32_t action = pointerCount == 1 ? AMOTION_EVENT_ACTION_CANCEL + : AMOTION_EVENT_ACTION_POINTER_UP | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + events.push_back( + std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, + memento.deviceId, memento.source, + memento.displayId, memento.policyFlags, action, + 0 /*actionButton*/, + memento.flags | AMOTION_EVENT_FLAG_CANCELED, + AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, + memento.yPrecision, memento.xCursorPosition, + memento.yCursorPosition, memento.downTime, + pointerCount, pointerProperties.data(), + pointerCoords.data())); + + // Cleanup pointer information + pointerProperties.erase(pointerProperties.begin() + pointerIdx); + pointerCoords.erase(pointerCoords.begin() + pointerIdx); + pointerCount--; + } + } + return events; +} + void InputState::clear() { mKeyMementos.clear(); mMotionMementos.clear(); diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index 74ae21f76a..6ab48c9273 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -14,15 +14,15 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H +#pragma once #include "CancelationOptions.h" #include "Entry.h" #include <utils/Timers.h> -namespace android::inputdispatcher { +namespace android { +namespace inputdispatcher { static constexpr int32_t INVALID_POINTER_INDEX = -1; @@ -125,8 +125,11 @@ private: static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options); static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options); -}; -} // namespace android::inputdispatcher + // Synthesizes pointer cancel events for a particular set of pointers. + std::vector<std::unique_ptr<MotionEntry>> synthesizeCancelationEventsForPointers( + const MotionMemento& memento, const BitSet32 pointerIds, nsecs_t currentTime); +}; -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H +} // namespace inputdispatcher +} // namespace android diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h index 0725389ed6..b2966f680c 100644 --- a/services/inputflinger/dispatcher/InputTarget.h +++ b/services/inputflinger/dispatcher/InputTarget.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H +#pragma once #include <gui/constants.h> #include <input/InputTransport.h> @@ -106,6 +105,9 @@ struct InputTarget { // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set. BitSet32 pointerIds; + // Event time for the first motion event (ACTION_DOWN) dispatched to this input target if + // FLAG_SPLIT is set. + std::optional<nsecs_t> firstDownTimeInTarget; // The data is stored by the pointerId. Use the bit position of pointerIds to look up // Transform per pointerId. ui::Transform pointerTransforms[MAX_POINTERS]; @@ -133,5 +135,3 @@ struct InputTarget { std::string dispatchModeToString(int32_t dispatchMode); } // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H diff --git a/services/inputflinger/dispatcher/LatencyAggregator.h b/services/inputflinger/dispatcher/LatencyAggregator.h index ed5731f8d9..accfc29d8e 100644 --- a/services/inputflinger/dispatcher/LatencyAggregator.h +++ b/services/inputflinger/dispatcher/LatencyAggregator.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_LATENCYAGGREGATOR_H -#define _UI_INPUT_INPUTDISPATCHER_LATENCYAGGREGATOR_H +#pragma once #include <kll.h> #include <statslog.h> @@ -86,5 +85,3 @@ private: }; } // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_LATENCYAGGREGATOR_H diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h index 4b0c618590..64dfeef20d 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.h +++ b/services/inputflinger/dispatcher/LatencyTracker.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_LATENCYTRACKER_H -#define _UI_INPUT_INPUTDISPATCHER_LATENCYTRACKER_H +#pragma once #include <map> #include <unordered_map> @@ -81,5 +80,3 @@ private: }; } // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_LATENCYTRACKER_H diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h index 365d5bee4c..7b511915d0 100644 --- a/services/inputflinger/dispatcher/Monitor.h +++ b/services/inputflinger/dispatcher/Monitor.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_MONITOR_H -#define _UI_INPUT_INPUTDISPATCHER_MONITOR_H +#pragma once #include <input/InputTransport.h> @@ -30,5 +29,3 @@ struct Monitor { }; } // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_MONITOR_H diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 61e78ccbe4..cf0c38af33 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -30,7 +30,7 @@ void TouchState::reset() { } void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags, - BitSet32 pointerIds) { + BitSet32 pointerIds, std::optional<nsecs_t> eventTime) { if (targetFlags & InputTarget::FLAG_SPLIT) { split = true; } @@ -42,17 +42,22 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; } + // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have + // downTime set initially. Need to update existing window when an pointer is down for + // the window. touchedWindow.pointerIds.value |= pointerIds.value; + if (!touchedWindow.firstDownTimeInTarget.has_value()) { + touchedWindow.firstDownTimeInTarget = eventTime; + } return; } } - if (preventNewTargets) return; // Don't add new TouchedWindows. - TouchedWindow touchedWindow; touchedWindow.windowHandle = windowHandle; touchedWindow.targetFlags = targetFlags; touchedWindow.pointerIds = pointerIds; + touchedWindow.firstDownTimeInTarget = eventTime; windows.push_back(touchedWindow); } @@ -79,6 +84,27 @@ void TouchState::filterNonAsIsTouchWindows() { } } +void TouchState::cancelPointersForWindowsExcept(const BitSet32 pointerIds, + const sp<IBinder>& token) { + if (pointerIds.isEmpty()) return; + std::for_each(windows.begin(), windows.end(), [&pointerIds, &token](TouchedWindow& w) { + if (w.windowHandle->getToken() != token) { + w.pointerIds &= BitSet32(~pointerIds.value); + } + }); + std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); }); +} + +void TouchState::cancelPointersForNonPilferingWindows(const BitSet32 pointerIds) { + if (pointerIds.isEmpty()) return; + std::for_each(windows.begin(), windows.end(), [&pointerIds](TouchedWindow& w) { + if (!w.isPilferingPointers) { + w.pointerIds &= BitSet32(~pointerIds.value); + } + }); + std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); }); +} + void TouchState::filterWindowsExcept(const sp<IBinder>& token) { std::erase_if(windows, [&token](const TouchedWindow& w) { return w.windowHandle->getToken() != token; }); diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 9efb2808c5..cf5f1e58c6 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H -#define _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H +#pragma once #include "Monitor.h" #include "TouchedWindow.h" @@ -31,7 +30,6 @@ namespace inputdispatcher { struct TouchState { bool down = false; bool split = false; - bool preventNewTargets = false; // id of the device that is currently down, others are rejected int32_t deviceId = -1; @@ -48,10 +46,18 @@ struct TouchState { void reset(); void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds); + int32_t targetFlags, BitSet32 pointerIds, + std::optional<nsecs_t> eventTime = std::nullopt); void removeWindowByToken(const sp<IBinder>& token); void filterNonAsIsTouchWindows(); void filterWindowsExcept(const sp<IBinder>& token); + + // Cancel pointers for current set of windows except the window with particular binder token. + void cancelPointersForWindowsExcept(const BitSet32 pointerIds, const sp<IBinder>& token); + // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow + // set to false. + void cancelPointersForNonPilferingWindows(const BitSet32 pointerIds); + sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const; bool isSlippery() const; sp<android::gui::WindowInfoHandle> getWallpaperWindow() const; @@ -60,5 +66,3 @@ struct TouchState { } // namespace inputdispatcher } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 6783022ca1..a6c505b854 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H -#define _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H +#pragma once namespace android { @@ -30,9 +29,11 @@ struct TouchedWindow { sp<gui::WindowInfoHandle> windowHandle; int32_t targetFlags; BitSet32 pointerIds; + bool isPilferingPointers = false; + // Time at which the first action down occurred on this window. + // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE scenario. + std::optional<nsecs_t> firstDownTimeInTarget; }; } // namespace inputdispatcher } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h index 00abf47cd2..5eb3a32ef9 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H +#pragma once #include <utils/Timers.h> @@ -40,5 +39,3 @@ struct InputDispatcherConfiguration { }; } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherFactory.h b/services/inputflinger/dispatcher/include/InputDispatcherFactory.h index 38d0c32529..5247d8eabb 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherFactory.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherFactory.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H +#pragma once #include <utils/StrongPointer.h> @@ -29,5 +28,3 @@ std::unique_ptr<InputDispatcherInterface> createInputDispatcher( const sp<InputDispatcherPolicyInterface>& policy); } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 67fed8b4f1..484b0d3b7f 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -14,13 +14,12 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H +#pragma once #include <InputListener.h> #include <android-base/result.h> #include <android/gui/FocusRequest.h> -#include <android/os/BlockUntrustedTouchesMode.h> + #include <android/os/InputEventInjectionResult.h> #include <android/os/InputEventInjectionSync.h> #include <gui/InputApplication.h> @@ -132,7 +131,8 @@ public: * * Returns true when changing touch mode state. */ - virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) = 0; + virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission, + int32_t displayId) = 0; /** * Sets the maximum allowed obscuring opacity by UID to propagate touches. @@ -142,13 +142,6 @@ public: */ virtual void setMaximumObscuringOpacityForTouch(float opacity) = 0; - /** - * Sets the mode of the block untrusted touches feature. - * - * TODO(b/169067926): Clean-up feature modes. - */ - virtual void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) = 0; - /* Transfers touch focus from one window to another window. * * Returns true on success. False if the window did not actually have touch focus. @@ -232,5 +225,3 @@ public: }; } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 575b3d7059..7843923a1f 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H +#pragma once #include "InputDispatcherConfiguration.h" @@ -75,9 +74,6 @@ public: InputDeviceSensorAccuracy accuracy) = 0; virtual void notifyVibratorState(int32_t deviceId, bool isOn) = 0; - /* Notifies the system that an untrusted touch occurred. */ - virtual void notifyUntrustedTouch(const std::string& obscuringPackage) = 0; - /* Gets the input dispatcher configuration. */ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; @@ -143,5 +139,3 @@ public: }; } // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp index 2ebdbcfcc4..97d57e4bd0 100644 --- a/services/inputflinger/host/InputDriver.cpp +++ b/services/inputflinger/host/InputDriver.cpp @@ -240,19 +240,16 @@ input_property_map_t* InputDriver::inputGetDevicePropertyMap(input_device_identi return nullptr; } -input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, - const char* key) { - String8 keyString(key); +input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) { if (map != nullptr) { - if (map->propertyMap->hasProperty(keyString)) { - auto prop = new input_property_t(); - if (!map->propertyMap->tryGetProperty(keyString, prop->value)) { - delete prop; - return nullptr; - } - prop->key = keyString; - return prop; + std::string value; + auto prop = std::make_unique<input_property_t>(); + if (!map->propertyMap->tryGetProperty(key, value)) { + return nullptr; } + prop->key = key; + prop->value = value.c_str(); + return prop.release(); } return nullptr; } diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h index e56673b4d3..b4c90943a8 100644 --- a/services/inputflinger/host/InputDriver.h +++ b/services/inputflinger/host/InputDriver.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_INPUT_DRIVER_H -#define ANDROID_INPUT_DRIVER_H +#pragma once #include <stdint.h> #include <sys/types.h> @@ -192,4 +191,3 @@ void input_free_device_property_map(input_host_t* host, input_property_map_t* ma } } // namespace android -#endif // ANDROID_INPUT_DRIVER_H diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h index 3cf1b2b797..388988bfce 100644 --- a/services/inputflinger/host/InputFlinger.h +++ b/services/inputflinger/host/InputFlinger.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_INPUT_FLINGER_H -#define ANDROID_INPUT_FLINGER_H +#pragma once #include <stdint.h> #include <sys/types.h> @@ -58,5 +57,3 @@ private: }; } // namespace android - -#endif // ANDROID_INPUT_FLINGER_H diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h index eda4a89c73..bdc4225738 100644 --- a/services/inputflinger/host/InputHost.h +++ b/services/inputflinger/host/InputHost.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_INPUT_HOST_H -#define ANDROID_INPUT_HOST_H +#pragma once #include <vector> @@ -55,4 +54,3 @@ private: }; } // namespace android -#endif // ANDRIOD_INPUT_HOST_H diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h index d9822ce156..8647bcb737 100644 --- a/services/inputflinger/include/InputListener.h +++ b/services/inputflinger/include/InputListener.h @@ -14,238 +14,17 @@ * limitations under the License. */ -#ifndef _UI_INPUT_LISTENER_H -#define _UI_INPUT_LISTENER_H +#pragma once #include <vector> #include <input/Input.h> #include <input/InputDevice.h> #include <input/TouchVideoFrame.h> +#include "NotifyArgs.h" namespace android { -class InputListenerInterface; - - -/* Superclass of all input event argument objects */ -struct NotifyArgs { - int32_t id; - nsecs_t eventTime; - - inline NotifyArgs() : id(0), eventTime(0) {} - - inline explicit NotifyArgs(int32_t id, nsecs_t eventTime) : id(id), eventTime(eventTime) {} - - virtual ~NotifyArgs() { } - - virtual void notify(InputListenerInterface& listener) const = 0; -}; - - -/* Describes a configuration change event. */ -struct NotifyConfigurationChangedArgs : public NotifyArgs { - - inline NotifyConfigurationChangedArgs() { } - - bool operator==(const NotifyConfigurationChangedArgs& rhs) const; - - NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime); - - NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other); - - virtual ~NotifyConfigurationChangedArgs() { } - - void notify(InputListenerInterface& listener) const override; -}; - - -/* Describes a key event. */ -struct NotifyKeyArgs : public NotifyArgs { - int32_t deviceId; - uint32_t source; - int32_t displayId; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - nsecs_t downTime; - nsecs_t readTime; - - inline NotifyKeyArgs() { } - - NotifyKeyArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId, - uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - nsecs_t downTime); - - bool operator==(const NotifyKeyArgs& rhs) const; - - NotifyKeyArgs(const NotifyKeyArgs& other); - - virtual ~NotifyKeyArgs() { } - - void notify(InputListenerInterface& listener) const override; -}; - - -/* Describes a motion event. */ -struct NotifyMotionArgs : public NotifyArgs { - 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; - /** - * Classification of the current touch gesture - */ - MotionClassification classification; - int32_t edgeFlags; - - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - float xPrecision; - float yPrecision; - /** - * Mouse cursor position when this event is reported relative to the origin of the specified - * display. Only valid if this is a mouse event (originates from a mouse or from a trackpad in - * gestures enabled mode. - */ - float xCursorPosition; - float yCursorPosition; - nsecs_t downTime; - nsecs_t readTime; - std::vector<TouchVideoFrame> videoFrames; - - inline NotifyMotionArgs() { } - - NotifyMotionArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, 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, - MotionClassification classification, int32_t edgeFlags, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, nsecs_t downTime, - const std::vector<TouchVideoFrame>& videoFrames); - - NotifyMotionArgs(const NotifyMotionArgs& other); - - virtual ~NotifyMotionArgs() { } - - bool operator==(const NotifyMotionArgs& rhs) const; - - void notify(InputListenerInterface& listener) const override; - - std::string dump() const; -}; - -/* Describes a sensor event. */ -struct NotifySensorArgs : public NotifyArgs { - int32_t deviceId; - uint32_t source; - InputDeviceSensorType sensorType; - InputDeviceSensorAccuracy accuracy; - bool accuracyChanged; - nsecs_t hwTimestamp; - std::vector<float> values; - - inline NotifySensorArgs() {} - - NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, - InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy, - bool accuracyChanged, nsecs_t hwTimestamp, std::vector<float> values); - - NotifySensorArgs(const NotifySensorArgs& other); - - bool operator==(const NotifySensorArgs rhs) const; - - ~NotifySensorArgs() override {} - - void notify(InputListenerInterface& listener) const override; -}; - -/* Describes a switch event. */ -struct NotifySwitchArgs : public NotifyArgs { - uint32_t policyFlags; - uint32_t switchValues; - uint32_t switchMask; - - inline NotifySwitchArgs() { } - - NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, uint32_t switchValues, - uint32_t switchMask); - - NotifySwitchArgs(const NotifySwitchArgs& other); - - bool operator==(const NotifySwitchArgs rhs) const; - - virtual ~NotifySwitchArgs() { } - - void notify(InputListenerInterface& listener) const override; -}; - - -/* Describes a device reset event, such as when a device is added, - * reconfigured, or removed. */ -struct NotifyDeviceResetArgs : public NotifyArgs { - int32_t deviceId; - - inline NotifyDeviceResetArgs() { } - - NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId); - - NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other); - - bool operator==(const NotifyDeviceResetArgs& rhs) const; - - virtual ~NotifyDeviceResetArgs() { } - - void notify(InputListenerInterface& listener) const override; -}; - -/* Describes a change in the state of Pointer Capture. */ -struct NotifyPointerCaptureChangedArgs : public NotifyArgs { - // The sequence number of the Pointer Capture request, if enabled. - PointerCaptureRequest request; - - inline NotifyPointerCaptureChangedArgs() {} - - NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, const PointerCaptureRequest&); - - NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other); - - bool operator==(const NotifyPointerCaptureChangedArgs& rhs) const; - - virtual ~NotifyPointerCaptureChangedArgs() {} - - void notify(InputListenerInterface& listener) const override; -}; - -/* Describes a vibrator state event. */ -struct NotifyVibratorStateArgs : public NotifyArgs { - int32_t deviceId; - bool isOn; - - inline NotifyVibratorStateArgs() {} - - NotifyVibratorStateArgs(int32_t id, nsecs_t eventTIme, int32_t deviceId, bool isOn); - - NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other); - - bool operator==(const NotifyVibratorStateArgs rhs) const; - - virtual ~NotifyVibratorStateArgs() {} - - void notify(InputListenerInterface& listener) const override; -}; - /* * The interface used by the InputReader to notify the InputListener about input events. */ @@ -264,6 +43,8 @@ public: virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) = 0; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0; virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) = 0; + + void notify(const NotifyArgs& args); }; /* @@ -288,9 +69,7 @@ public: private: InputListenerInterface& mInnerListener; - std::vector<std::unique_ptr<NotifyArgs>> mArgsQueue; + std::vector<NotifyArgs> mArgsQueue; }; } // namespace android - -#endif // _UI_INPUT_LISTENER_H diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 41ecef365d..cacb63cb8b 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_READER_BASE_H -#define _UI_INPUT_READER_BASE_H +#pragma once #include <android/os/IInputConstants.h> #include <input/DisplayViewport.h> @@ -95,7 +94,7 @@ public: /* Determine whether physical keys exist for the given framework-domain key codes. */ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; + const std::vector<int32_t>& keyCodes, uint8_t* outFlags) = 0; /* Requests that a reconfiguration of all input devices. * The changes flag is a bitfield that indicates what has changed and whether @@ -114,6 +113,8 @@ public: virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) = 0; /* Get battery status of a particular input device. */ virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0; + /* Get the device path for the battery of an input device. */ + virtual std::optional<std::string> getBatteryDevicePath(int32_t deviceId) = 0; virtual std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) = 0; @@ -395,5 +396,3 @@ public: }; } // namespace android - -#endif // _UI_INPUT_READER_COMMON_H diff --git a/services/inputflinger/include/InputThread.h b/services/inputflinger/include/InputThread.h index 407365a269..5e75027056 100644 --- a/services/inputflinger/include/InputThread.h +++ b/services/inputflinger/include/InputThread.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_THREAD_H -#define _UI_INPUT_THREAD_H +#pragma once #include <utils/Thread.h> @@ -42,5 +41,3 @@ private: }; } // namespace android - -#endif // _UI_INPUT_THREAD_H
\ No newline at end of file diff --git a/services/inputflinger/include/NotifyArgs.h b/services/inputflinger/include/NotifyArgs.h new file mode 100644 index 0000000000..611b1aac81 --- /dev/null +++ b/services/inputflinger/include/NotifyArgs.h @@ -0,0 +1,216 @@ +/* + * 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. + */ + +#pragma once + +#include <vector> + +#include <input/Input.h> +#include <input/InputDevice.h> +#include <input/TouchVideoFrame.h> + +namespace android { + +/* Describes a configuration change event. */ +struct NotifyConfigurationChangedArgs { + int32_t id; + nsecs_t eventTime; + + inline NotifyConfigurationChangedArgs() {} + + NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime); + + bool operator==(const NotifyConfigurationChangedArgs& rhs) const = default; + + NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other) = default; +}; + +/* Describes a key event. */ +struct NotifyKeyArgs { + int32_t id; + nsecs_t eventTime; + + int32_t deviceId; + uint32_t source; + int32_t displayId; + uint32_t policyFlags; + int32_t action; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + nsecs_t downTime; + nsecs_t readTime; + + inline NotifyKeyArgs() {} + + NotifyKeyArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId, + uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, + int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, + nsecs_t downTime); + + bool operator==(const NotifyKeyArgs& rhs) const = default; + + NotifyKeyArgs(const NotifyKeyArgs& other) = default; +}; + +/* Describes a motion event. */ +struct NotifyMotionArgs { + int32_t id; + 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; + /** + * Classification of the current touch gesture + */ + MotionClassification classification; + int32_t edgeFlags; + + uint32_t pointerCount; + PointerProperties pointerProperties[MAX_POINTERS]; + PointerCoords pointerCoords[MAX_POINTERS]; + float xPrecision; + float yPrecision; + /** + * Mouse cursor position when this event is reported relative to the origin of the specified + * display. Only valid if this is a mouse event (originates from a mouse or from a trackpad in + * gestures enabled mode. + */ + float xCursorPosition; + float yCursorPosition; + nsecs_t downTime; + nsecs_t readTime; + std::vector<TouchVideoFrame> videoFrames; + + inline NotifyMotionArgs() {} + + NotifyMotionArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, 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, + MotionClassification classification, int32_t edgeFlags, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, + const std::vector<TouchVideoFrame>& videoFrames); + + NotifyMotionArgs(const NotifyMotionArgs& other); + + bool operator==(const NotifyMotionArgs& rhs) const; + + std::string dump() const; +}; + +/* Describes a sensor event. */ +struct NotifySensorArgs { + int32_t id; + nsecs_t eventTime; + + int32_t deviceId; + uint32_t source; + InputDeviceSensorType sensorType; + InputDeviceSensorAccuracy accuracy; + bool accuracyChanged; + nsecs_t hwTimestamp; + std::vector<float> values; + + inline NotifySensorArgs() {} + + NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, + InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy, + bool accuracyChanged, nsecs_t hwTimestamp, std::vector<float> values); + + NotifySensorArgs(const NotifySensorArgs& other) = default; +}; + +/* Describes a switch event. */ +struct NotifySwitchArgs { + int32_t id; + nsecs_t eventTime; + + uint32_t policyFlags; + uint32_t switchValues; + uint32_t switchMask; + + inline NotifySwitchArgs() {} + + NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, uint32_t switchValues, + uint32_t switchMask); + + NotifySwitchArgs(const NotifySwitchArgs& other) = default; + + bool operator==(const NotifySwitchArgs& rhs) const = default; +}; + +/* Describes a device reset event, such as when a device is added, + * reconfigured, or removed. */ +struct NotifyDeviceResetArgs { + int32_t id; + nsecs_t eventTime; + + int32_t deviceId; + + inline NotifyDeviceResetArgs() {} + + NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId); + + NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) = default; + + bool operator==(const NotifyDeviceResetArgs& rhs) const = default; +}; + +/* Describes a change in the state of Pointer Capture. */ +struct NotifyPointerCaptureChangedArgs { + // The sequence number of the Pointer Capture request, if enabled. + int32_t id; + nsecs_t eventTime; + + PointerCaptureRequest request; + + inline NotifyPointerCaptureChangedArgs() {} + + NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, const PointerCaptureRequest&); + + NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other) = default; +}; + +/* Describes a vibrator state event. */ +struct NotifyVibratorStateArgs { + int32_t id; + nsecs_t eventTime; + + int32_t deviceId; + bool isOn; + + inline NotifyVibratorStateArgs() {} + + NotifyVibratorStateArgs(int32_t id, nsecs_t eventTIme, int32_t deviceId, bool isOn); + + NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other) = default; +}; + +using NotifyArgs = std::variant<NotifyConfigurationChangedArgs, NotifyKeyArgs, NotifyMotionArgs, + NotifySensorArgs, NotifySwitchArgs, NotifyDeviceResetArgs, + NotifyPointerCaptureChangedArgs, NotifyVibratorStateArgs>; + +} // namespace android diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index db4228d862..647e10c974 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H -#define _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H +#pragma once #include <input/DisplayViewport.h> #include <input/Input.h> @@ -108,5 +107,3 @@ public: }; } // namespace android - -#endif // _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H diff --git a/services/inputflinger/include/VibrationElement.h b/services/inputflinger/include/VibrationElement.h index 736041e7fd..04c2e394c8 100644 --- a/services/inputflinger/include/VibrationElement.h +++ b/services/inputflinger/include/VibrationElement.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _VIBRATION_ELEMENT_H -#define _VIBRATION_ELEMENT_H +#pragma once #include <array> #include <chrono> @@ -71,5 +70,3 @@ struct VibrationSequence { }; } // namespace android - -#endif // _VIBRATION_ELEMENT_H diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index 01146a3c8b..0f87201caf 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -69,12 +69,12 @@ cc_defaults { "libinput", "liblog", "libstatslog", - "libui", "libutils", "libPlatformProperties", ], static_libs: [ "libc++fs", + "libui-types", ], header_libs: [ "libbatteryservice_headers", diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 20baa42a20..ca7e426fdf 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -52,6 +52,7 @@ #include <filesystem> #include <regex> +#include <utility> #include "EventHub.h" @@ -60,6 +61,7 @@ #define INDENT3 " " using android::base::StringPrintf; +using android::hardware::input::InputDeviceCountryCode; namespace android { @@ -74,6 +76,8 @@ static constexpr size_t OBFUSCATED_LENGTH = 8; static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0; static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1; +static constexpr size_t EVENT_BUFFER_SIZE = 256; + // Mapping for input battery class node IDs lookup. // https://www.kernel.org/doc/Documentation/power/power_supply_class.txt static const std::unordered_map<std::string, InputBatteryClass> BATTERY_CLASSES = @@ -115,7 +119,8 @@ static const std::unordered_map<std::string, InputLightClass> LIGHT_CLASSES = {"brightness", InputLightClass::BRIGHTNESS}, {"multi_index", InputLightClass::MULTI_INDEX}, {"multi_intensity", InputLightClass::MULTI_INTENSITY}, - {"max_brightness", InputLightClass::MAX_BRIGHTNESS}}; + {"max_brightness", InputLightClass::MAX_BRIGHTNESS}, + {"kbd_backlight", InputLightClass::KEYBOARD_BACKLIGHT}}; // Mapping for input multicolor led class node names. // https://www.kernel.org/doc/html/latest/leds/leds-class-multicolor.html @@ -193,8 +198,7 @@ static nsecs_t processEventTimestamp(const struct input_event& event) { } /** - * Returns the sysfs root path of the input device - * + * Returns the sysfs root path of the input device. */ static std::optional<std::filesystem::path> getSysfsRootPath(const char* devicePath) { std::error_code errorCode; @@ -301,6 +305,112 @@ static std::optional<std::array<LightColor, COLOR_NUM>> getColorIndexArray( return colors; } +/** + * Read country code information exposed through the sysfs path. + */ +static InputDeviceCountryCode readCountryCodeLocked(const std::filesystem::path& sysfsRootPath) { + // Check the sysfs root path + int hidCountryCode = static_cast<int>(InputDeviceCountryCode::INVALID); + std::string str; + if (base::ReadFileToString(sysfsRootPath / "country", &str)) { + hidCountryCode = std::stoi(str, nullptr, 16); + LOG_ALWAYS_FATAL_IF(hidCountryCode > 35 || hidCountryCode < 0, + "HID country code should be in range [0, 35]. Found country code " + "to be %d", + hidCountryCode); + } + + return static_cast<InputDeviceCountryCode>(hidCountryCode); +} + +/** + * Read information about batteries exposed through the sysfs path. + */ +static std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> readBatteryConfiguration( + const std::filesystem::path& sysfsRootPath) { + std::unordered_map<int32_t, RawBatteryInfo> batteryInfos; + int32_t nextBatteryId = 0; + // Check if device has any battery. + const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::POWER_SUPPLY); + for (const auto& nodePath : paths) { + RawBatteryInfo info; + info.id = ++nextBatteryId; + info.path = nodePath; + info.name = nodePath.filename(); + + // Scan the path for all the files + // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt + const auto& files = allFilesInPath(nodePath); + for (const auto& file : files) { + const auto it = BATTERY_CLASSES.find(file.filename().string()); + if (it != BATTERY_CLASSES.end()) { + info.flags |= it->second; + } + } + batteryInfos.insert_or_assign(info.id, info); + ALOGD("configureBatteryLocked rawBatteryId %d name %s", info.id, info.name.c_str()); + } + return batteryInfos; +} + +/** + * Read information about lights exposed through the sysfs path. + */ +static std::unordered_map<int32_t /*lightId*/, RawLightInfo> readLightsConfiguration( + const std::filesystem::path& sysfsRootPath) { + std::unordered_map<int32_t, RawLightInfo> lightInfos; + int32_t nextLightId = 0; + // Check if device has any lights. + const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::LEDS); + for (const auto& nodePath : paths) { + RawLightInfo info; + info.id = ++nextLightId; + info.path = nodePath; + info.name = nodePath.filename(); + info.maxBrightness = std::nullopt; + + // Light name should follow the naming pattern <name>:<color>:<function> + // Refer kernel docs /leds/leds-class.html for valid supported LED names. + std::regex indexPattern("([a-zA-Z0-9_.:]*:)?([a-zA-Z0-9_.]*):([a-zA-Z0-9_.]*)"); + std::smatch results; + + if (std::regex_match(info.name, results, indexPattern)) { + // regex_match will return full match at index 0 and <name> at index 1. For RawLightInfo + // we only care about sections <color> and <function> which will be at index 2 and 3. + for (int i = 2; i <= 3; i++) { + const auto it = LIGHT_CLASSES.find(results.str(i)); + if (it != LIGHT_CLASSES.end()) { + info.flags |= it->second; + } + } + + // Set name of the raw light to <function> which represents playerIDs for LEDs that + // turn on/off based on the current player ID (Refer to PeripheralController.cpp for + // player ID logic) + info.name = results.str(3); + } + // Scan the path for all the files + // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt + const auto& files = allFilesInPath(nodePath); + for (const auto& file : files) { + const auto it = LIGHT_CLASSES.find(file.filename().string()); + if (it != LIGHT_CLASSES.end()) { + info.flags |= it->second; + // If the node has maximum brightness, read it + if (it->second == InputLightClass::MAX_BRIGHTNESS) { + std::string str; + if (base::ReadFileToString(file, &str)) { + info.maxBrightness = std::stoi(str); + } + } + } + } + lightInfos.insert_or_assign(info.id, info); + ALOGD("configureLightsLocked rawLightId %d name %s", info.id, info.name.c_str()); + } + return lightInfos; +} + // --- Global Functions --- ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, @@ -357,18 +467,18 @@ ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, // --- EventHub::Device --- -EventHub::Device::Device(int fd, int32_t id, const std::string& path, - const InputDeviceIdentifier& identifier) +EventHub::Device::Device(int fd, int32_t id, std::string path, InputDeviceIdentifier identifier, + std::shared_ptr<const AssociatedDevice> assocDev) : fd(fd), id(id), - path(path), - identifier(identifier), + path(std::move(path)), + identifier(std::move(identifier)), classes(0), configuration(nullptr), virtualKeyMap(nullptr), ffEffectPlaying(false), ffEffectId(-1), - associatedDevice(nullptr), + associatedDevice(std::move(assocDev)), controllerNumber(0), enabled(true), isVirtual(fd < 0) {} @@ -502,7 +612,7 @@ status_t EventHub::Device::loadKeyMapLocked() { bool EventHub::Device::isExternalDeviceLocked() { if (configuration) { bool value; - if (configuration->tryGetProperty(String8("device.internal"), value)) { + if (configuration->tryGetProperty("device.internal", value)) { return !value; } } @@ -512,7 +622,7 @@ bool EventHub::Device::isExternalDeviceLocked() { bool EventHub::Device::deviceHasMicLocked() { if (configuration) { bool value; - if (configuration->tryGetProperty(String8("audio.mic"), value)) { + if (configuration->tryGetProperty("audio.mic", value)) { return value; } } @@ -557,75 +667,6 @@ status_t EventHub::Device::mapLed(int32_t led, int32_t* outScanCode) const { return NAME_NOT_FOUND; } -// Check the sysfs path for any input device batteries, returns true if battery found. -bool EventHub::AssociatedDevice::configureBatteryLocked() { - nextBatteryId = 0; - // Check if device has any battery. - const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::POWER_SUPPLY); - for (const auto& nodePath : paths) { - RawBatteryInfo info; - info.id = ++nextBatteryId; - info.path = nodePath; - info.name = nodePath.filename(); - - // Scan the path for all the files - // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt - const auto& files = allFilesInPath(nodePath); - for (const auto& file : files) { - const auto it = BATTERY_CLASSES.find(file.filename().string()); - if (it != BATTERY_CLASSES.end()) { - info.flags |= it->second; - } - } - batteryInfos.insert_or_assign(info.id, info); - ALOGD("configureBatteryLocked rawBatteryId %d name %s", info.id, info.name.c_str()); - } - return !batteryInfos.empty(); -} - -// Check the sysfs path for any input device lights, returns true if lights found. -bool EventHub::AssociatedDevice::configureLightsLocked() { - nextLightId = 0; - // Check if device has any lights. - const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::LEDS); - for (const auto& nodePath : paths) { - RawLightInfo info; - info.id = ++nextLightId; - info.path = nodePath; - info.name = nodePath.filename(); - info.maxBrightness = std::nullopt; - size_t nameStart = info.name.rfind(":"); - if (nameStart != std::string::npos) { - // Trim the name to color name - info.name = info.name.substr(nameStart + 1); - // Set InputLightClass flag for colors - const auto it = LIGHT_CLASSES.find(info.name); - if (it != LIGHT_CLASSES.end()) { - info.flags |= it->second; - } - } - // Scan the path for all the files - // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt - const auto& files = allFilesInPath(nodePath); - for (const auto& file : files) { - const auto it = LIGHT_CLASSES.find(file.filename().string()); - if (it != LIGHT_CLASSES.end()) { - info.flags |= it->second; - // If the node has maximum brightness, read it - if (it->second == InputLightClass::MAX_BRIGHTNESS) { - std::string str; - if (base::ReadFileToString(file, &str)) { - info.maxBrightness = std::stoi(str); - } - } - } - } - lightInfos.insert_or_assign(info.id, info); - ALOGD("configureLightsLocked rawLightId %d name %s", info.id, info.name.c_str()); - } - return !lightInfos.empty(); -} - /** * Get the capabilities for the current process. * Crashes the system if unable to create / check / destroy the capabilities object. @@ -687,6 +728,7 @@ EventHub::EventHub(void) LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno)); mINotifyFd = inotify_init1(IN_CLOEXEC); + LOG_ALWAYS_FATAL_IF(mINotifyFd < 0, "Could not create inotify instance: %s", strerror(errno)); std::error_code errorCode; bool isDeviceInotifyAdded = false; @@ -952,20 +994,20 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* return -1; } -bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, +bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); if (device != nullptr && device->keyMap.haveKeyLayout()) { - for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { + for (size_t codeIndex = 0; codeIndex < keyCodes.size(); codeIndex++) { std::vector<int32_t> scanCodes = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex]); // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver - for (size_t sc = 0; sc < scanCodes.size(); sc++) { - if (device->keyBitmask.test(scanCodes[sc])) { + for (const int32_t scanCode : scanCodes) { + if (device->keyBitmask.test(scanCode)) { outFlags[codeIndex] = 1; break; } @@ -1033,7 +1075,7 @@ status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxis } base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int32_t deviceId, - int32_t absCode) { + int32_t absCode) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); @@ -1055,18 +1097,19 @@ const std::unordered_map<int32_t, RawBatteryInfo>& EventHub::getBatteryInfoLocke return device->associatedDevice->batteryInfos; } -const std::vector<int32_t> EventHub::getRawBatteryIds(int32_t deviceId) { +std::vector<int32_t> EventHub::getRawBatteryIds(int32_t deviceId) const { std::scoped_lock _l(mLock); std::vector<int32_t> batteryIds; - for (const auto [id, info] : getBatteryInfoLocked(deviceId)) { + for (const auto& [id, info] : getBatteryInfoLocked(deviceId)) { batteryIds.push_back(id); } return batteryIds; } -std::optional<RawBatteryInfo> EventHub::getRawBatteryInfo(int32_t deviceId, int32_t batteryId) { +std::optional<RawBatteryInfo> EventHub::getRawBatteryInfo(int32_t deviceId, + int32_t batteryId) const { std::scoped_lock _l(mLock); const auto infos = getBatteryInfoLocked(deviceId); @@ -1080,7 +1123,7 @@ std::optional<RawBatteryInfo> EventHub::getRawBatteryInfo(int32_t deviceId, int3 } // Gets the light info map from light ID to RawLightInfo of the miscellaneous device associated -// with the deivice ID. Returns an empty map if no miscellaneous device found. +// with the device ID. Returns an empty map if no miscellaneous device found. const std::unordered_map<int32_t, RawLightInfo>& EventHub::getLightInfoLocked( int32_t deviceId) const { static const std::unordered_map<int32_t, RawLightInfo> EMPTY_LIGHT_INFO = {}; @@ -1091,18 +1134,18 @@ const std::unordered_map<int32_t, RawLightInfo>& EventHub::getLightInfoLocked( return device->associatedDevice->lightInfos; } -const std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) { +std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) const { std::scoped_lock _l(mLock); std::vector<int32_t> lightIds; - for (const auto [id, info] : getLightInfoLocked(deviceId)) { + for (const auto& [id, info] : getLightInfoLocked(deviceId)) { lightIds.push_back(id); } return lightIds; } -std::optional<RawLightInfo> EventHub::getRawLightInfo(int32_t deviceId, int32_t lightId) { +std::optional<RawLightInfo> EventHub::getRawLightInfo(int32_t deviceId, int32_t lightId) const { std::scoped_lock _l(mLock); const auto infos = getLightInfoLocked(deviceId); @@ -1115,7 +1158,7 @@ std::optional<RawLightInfo> EventHub::getRawLightInfo(int32_t deviceId, int32_t return std::nullopt; } -std::optional<int32_t> EventHub::getLightBrightness(int32_t deviceId, int32_t lightId) { +std::optional<int32_t> EventHub::getLightBrightness(int32_t deviceId, int32_t lightId) const { std::scoped_lock _l(mLock); const auto infos = getLightInfoLocked(deviceId); @@ -1132,7 +1175,7 @@ std::optional<int32_t> EventHub::getLightBrightness(int32_t deviceId, int32_t li } std::optional<std::unordered_map<LightColor, int32_t>> EventHub::getLightIntensities( - int32_t deviceId, int32_t lightId) { + int32_t deviceId, int32_t lightId) const { std::scoped_lock _l(mLock); const auto infos = getLightInfoLocked(deviceId); @@ -1228,6 +1271,15 @@ void EventHub::setLightIntensities(int32_t deviceId, int32_t lightId, } } +InputDeviceCountryCode EventHub::getCountryCode(int32_t deviceId) const { + std::scoped_lock _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device == nullptr || !device->associatedDevice) { + return InputDeviceCountryCode::INVALID; + } + return device->associatedDevice->countryCode; +} + void EventHub::setExcludedDevices(const std::vector<std::string>& devices) { std::scoped_lock _l(mLock); @@ -1357,6 +1409,39 @@ void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) { identifier.descriptor.c_str()); } +std::shared_ptr<const EventHub::AssociatedDevice> EventHub::obtainAssociatedDeviceLocked( + const std::filesystem::path& devicePath) const { + const std::optional<std::filesystem::path> sysfsRootPathOpt = + getSysfsRootPath(devicePath.c_str()); + if (!sysfsRootPathOpt) { + return nullptr; + } + + const auto& path = *sysfsRootPathOpt; + + std::shared_ptr<const AssociatedDevice> associatedDevice = std::make_shared<AssociatedDevice>( + AssociatedDevice{.sysfsRootPath = path, + .countryCode = readCountryCodeLocked(path), + .batteryInfos = readBatteryConfiguration(path), + .lightInfos = readLightsConfiguration(path)}); + + bool associatedDeviceChanged = false; + for (const auto& [id, dev] : mDevices) { + if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == path) { + if (*associatedDevice != *dev->associatedDevice) { + associatedDeviceChanged = true; + dev->associatedDevice = associatedDevice; + } + associatedDevice = dev->associatedDevice; + } + } + ALOGI_IF(associatedDeviceChanged, + "The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s", + path.c_str(), associatedDevice->dump().c_str()); + + return associatedDevice; +} + void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); @@ -1414,7 +1499,7 @@ void EventHub::cancelVibrate(int32_t deviceId) { } } -std::vector<int32_t> EventHub::getVibratorIds(int32_t deviceId) { +std::vector<int32_t> EventHub::getVibratorIds(int32_t deviceId) const { std::scoped_lock _l(mLock); std::vector<int32_t> vibrators; Device* device = getDeviceLocked(deviceId); @@ -1495,7 +1580,7 @@ std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId, int32_t ba // the lock to prevent event processing from being blocked by this call. std::scoped_lock _l(mLock); - const auto infos = getBatteryInfoLocked(deviceId); + const auto& infos = getBatteryInfoLocked(deviceId); auto it = infos.find(batteryId); if (it == infos.end()) { return std::nullopt; @@ -1536,7 +1621,7 @@ std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId, int32_t batt // the lock to prevent event processing from being blocked by this call. std::scoped_lock _l(mLock); - const auto infos = getBatteryInfoLocked(deviceId); + const auto& infos = getBatteryInfoLocked(deviceId); auto it = infos.find(batteryId); if (it == infos.end()) { return std::nullopt; @@ -1561,15 +1646,12 @@ std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId, int32_t batt return std::nullopt; } -size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { - ALOG_ASSERT(bufferSize >= 1); - +std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) { std::scoped_lock _l(mLock); - struct input_event readBuffer[bufferSize]; + std::array<input_event, EVENT_BUFFER_SIZE> readBuffer; - RawEvent* event = buffer; - size_t capacity = bufferSize; + std::vector<RawEvent> events; bool awoken = false; for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); @@ -1589,15 +1671,17 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) { std::unique_ptr<Device> device = std::move(*it); ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str()); - event->when = now; - event->deviceId = (device->id == mBuiltInKeyboardId) + const int32_t deviceId = (device->id == mBuiltInKeyboardId) ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID : device->id; - event->type = DEVICE_REMOVED; - event += 1; + events.push_back({ + .when = now, + .deviceId = deviceId, + .type = DEVICE_REMOVED, + }); it = mClosingDevices.erase(it); mNeedToSendFinishedDeviceScan = true; - if (--capacity == 0) { + if (events.size() == EVENT_BUFFER_SIZE) { break; } } @@ -1612,10 +1696,12 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin()); mOpeningDevices.pop_back(); ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str()); - event->when = now; - event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - event->type = DEVICE_ADDED; - event += 1; + const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + events.push_back({ + .when = now, + .deviceId = deviceId, + .type = DEVICE_ADDED, + }); // Try to find a matching video device by comparing device names for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end(); @@ -1633,17 +1719,18 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz ALOGW("Device id %d exists, replaced.", device->id); } mNeedToSendFinishedDeviceScan = true; - if (--capacity == 0) { + if (events.size() == EVENT_BUFFER_SIZE) { break; } } if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; - event->when = now; - event->type = FINISHED_DEVICE_SCAN; - event += 1; - if (--capacity == 0) { + events.push_back({ + .when = now, + .type = FINISHED_DEVICE_SCAN, + }); + if (events.size() == EVENT_BUFFER_SIZE) { break; } } @@ -1707,12 +1794,13 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz // This must be an input event if (eventItem.events & EPOLLIN) { int32_t readSize = - read(device->fd, readBuffer, sizeof(struct input_event) * capacity); + read(device->fd, readBuffer.data(), + sizeof(decltype(readBuffer)::value_type) * readBuffer.size()); if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { // Device was removed before INotify noticed. ALOGW("could not get event, removed? (fd: %d size: %" PRId32 - " bufferSize: %zu capacity: %zu errno: %d)\n", - device->fd, readSize, bufferSize, capacity, errno); + " capacity: %zu errno: %d)\n", + device->fd, readSize, readBuffer.size(), errno); deviceChanged = true; closeDeviceLocked(*device); } else if (readSize < 0) { @@ -1722,21 +1810,21 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz } else if ((readSize % sizeof(struct input_event)) != 0) { ALOGE("could not get event (wrong size: %d)", readSize); } else { - int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - size_t count = size_t(readSize) / sizeof(struct input_event); + const size_t count = size_t(readSize) / sizeof(struct input_event); for (size_t i = 0; i < count; i++) { struct input_event& iev = readBuffer[i]; - event->when = processEventTimestamp(iev); - event->readTime = systemTime(SYSTEM_TIME_MONOTONIC); - event->deviceId = deviceId; - event->type = iev.type; - event->code = iev.code; - event->value = iev.value; - event += 1; - capacity -= 1; + events.push_back({ + .when = processEventTimestamp(iev), + .readTime = systemTime(SYSTEM_TIME_MONOTONIC), + .deviceId = deviceId, + .type = iev.type, + .code = iev.code, + .value = iev.value, + }); } - if (capacity == 0) { + if (events.size() >= EVENT_BUFFER_SIZE) { // The result buffer is full. Reset the pending event index // so we will try to read the device again on the next iteration. mPendingEventIndex -= 1; @@ -1759,7 +1847,10 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz // before closing the devices. if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { mPendingINotify = false; - readNotifyLocked(); + const auto res = readNotifyLocked(); + if (!res.ok()) { + ALOGW("Failed to read from inotify: %s", res.error().message().c_str()); + } deviceChanged = true; } @@ -1769,7 +1860,7 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz } // Return now if we have collected any events or if we were explicitly awoken. - if (event != buffer || awoken) { + if (!events.empty() || awoken) { break; } @@ -1815,7 +1906,7 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz } // All done, return the number of events we read. - return event - buffer; + return events; } std::vector<TouchVideoFrame> EventHub::getVideoFrames(int32_t deviceId) { @@ -2042,7 +2133,9 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { // Allocate device. (The device object takes ownership of the fd at this point.) int32_t deviceId = mNextDeviceId++; - std::unique_ptr<Device> device = std::make_unique<Device>(fd, deviceId, devicePath, identifier); + std::unique_ptr<Device> device = + std::make_unique<Device>(fd, deviceId, devicePath, identifier, + obtainAssociatedDeviceLocked(devicePath)); ALOGV("add device %d: %s\n", deviceId, devicePath.c_str()); ALOGV(" bus: %04x\n" @@ -2060,27 +2153,6 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { // Load the configuration file for the device. device->loadConfigurationLocked(); - bool hasBattery = false; - bool hasLights = false; - // Check the sysfs root path - std::optional<std::filesystem::path> sysfsRootPath = getSysfsRootPath(devicePath.c_str()); - if (sysfsRootPath.has_value()) { - std::shared_ptr<AssociatedDevice> associatedDevice; - for (const auto& [id, dev] : mDevices) { - if (device->identifier.descriptor == dev->identifier.descriptor && - !dev->associatedDevice) { - associatedDevice = dev->associatedDevice; - } - } - if (!associatedDevice) { - associatedDevice = std::make_shared<AssociatedDevice>(sysfsRootPath.value()); - } - hasBattery = associatedDevice->configureBatteryLocked(); - hasLights = associatedDevice->configureLightsLocked(); - - device->associatedDevice = associatedDevice; - } - // Figure out the kinds of events the device reports. device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0), device->absBitmask); @@ -2108,10 +2180,9 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { } // See if this is a rotary encoder type device. - String8 deviceType = String8(); - if (device->configuration && - device->configuration->tryGetProperty(String8("device.type"), deviceType)) { - if (!deviceType.compare(String8("rotaryEncoder"))) { + std::string deviceType; + if (device->configuration && device->configuration->tryGetProperty("device.type", deviceType)) { + if (deviceType == "rotaryEncoder") { device->classes |= InputDeviceClass::ROTARY_ENCODER; } } @@ -2231,12 +2302,12 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { } // Classify InputDeviceClass::BATTERY. - if (hasBattery) { + if (device->associatedDevice && !device->associatedDevice->batteryInfos.empty()) { device->classes |= InputDeviceClass::BATTERY; } // Classify InputDeviceClass::LIGHT. - if (hasLights) { + if (device->associatedDevice && !device->associatedDevice->lightInfos.empty()) { device->classes |= InputDeviceClass::LIGHT; } @@ -2304,7 +2375,7 @@ bool EventHub::tryAddVideoDeviceLocked(EventHub::Device& device, return true; } -bool EventHub::isDeviceEnabled(int32_t deviceId) { +bool EventHub::isDeviceEnabled(int32_t deviceId) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); if (device == nullptr) { @@ -2359,7 +2430,7 @@ void EventHub::createVirtualKeyboardLocked() { std::unique_ptr<Device> device = std::make_unique<Device>(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>", - identifier); + identifier, nullptr /*associatedDevice*/); device->classes = InputDeviceClass::KEYBOARD | InputDeviceClass::ALPHAKEY | InputDeviceClass::DPAD | InputDeviceClass::VIRTUAL; device->loadKeyMapLocked(); @@ -2449,53 +2520,56 @@ void EventHub::closeDeviceLocked(Device& device) { mDevices.erase(device.id); } -status_t EventHub::readNotifyLocked() { - int res; - char event_buf[512]; - int event_size; - int event_pos = 0; - struct inotify_event* event; +base::Result<void> EventHub::readNotifyLocked() { + static constexpr auto EVENT_SIZE = static_cast<ssize_t>(sizeof(inotify_event)); + uint8_t eventBuffer[512]; + ssize_t sizeRead; ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd); - res = read(mINotifyFd, event_buf, sizeof(event_buf)); - if (res < (int)sizeof(*event)) { - if (errno == EINTR) return 0; - ALOGW("could not get event, %s\n", strerror(errno)); - return -1; - } - - while (res >= (int)sizeof(*event)) { - event = (struct inotify_event*)(event_buf + event_pos); - if (event->len) { - if (event->wd == mDeviceInputWd) { - std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event->name; - if (event->mask & IN_CREATE) { - openDeviceLocked(filename); - } else { - ALOGI("Removing device '%s' due to inotify event\n", filename.c_str()); - closeDeviceByPathLocked(filename); - } - } else if (event->wd == mDeviceWd) { - if (isV4lTouchNode(event->name)) { - std::string filename = std::string(DEVICE_PATH) + "/" + event->name; - if (event->mask & IN_CREATE) { - openVideoDeviceLocked(filename); - } else { - ALOGI("Removing video device '%s' due to inotify event", filename.c_str()); - closeVideoDeviceByPathLocked(filename); - } - } else if (strcmp(event->name, "input") == 0 && event->mask & IN_CREATE) { - addDeviceInputInotify(); - } + do { + sizeRead = read(mINotifyFd, eventBuffer, sizeof(eventBuffer)); + } while (sizeRead < 0 && errno == EINTR); + + if (sizeRead < EVENT_SIZE) return Errorf("could not get event, %s", strerror(errno)); + + for (ssize_t eventPos = 0; sizeRead >= EVENT_SIZE;) { + const inotify_event* event; + event = (const inotify_event*)(eventBuffer + eventPos); + if (event->len == 0) continue; + + handleNotifyEventLocked(*event); + + const ssize_t eventSize = EVENT_SIZE + event->len; + sizeRead -= eventSize; + eventPos += eventSize; + } + return {}; +} + +void EventHub::handleNotifyEventLocked(const inotify_event& event) { + if (event.wd == mDeviceInputWd) { + std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event.name; + if (event.mask & IN_CREATE) { + openDeviceLocked(filename); + } else { + ALOGI("Removing device '%s' due to inotify event\n", filename.c_str()); + closeDeviceByPathLocked(filename); + } + } else if (event.wd == mDeviceWd) { + if (isV4lTouchNode(event.name)) { + std::string filename = std::string(DEVICE_PATH) + "/" + event.name; + if (event.mask & IN_CREATE) { + openVideoDeviceLocked(filename); } else { - LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd); + ALOGI("Removing video device '%s' due to inotify event", filename.c_str()); + closeVideoDeviceByPathLocked(filename); } + } else if (strcmp(event.name, "input") == 0 && event.mask & IN_CREATE) { + addDeviceInputInotify(); } - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; + } else { + LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event.wd); } - return 0; } status_t EventHub::scanDirLocked(const std::string& dirname) { @@ -2525,7 +2599,7 @@ void EventHub::requestReopenDevices() { mNeedToReopenDevices = true; } -void EventHub::dump(std::string& dump) { +void EventHub::dump(std::string& dump) const { dump += "Event Hub State:\n"; { // acquire lock @@ -2558,14 +2632,18 @@ void EventHub::dump(std::string& dump) { device->keyMap.keyLayoutFile.c_str()); dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n", device->keyMap.keyCharacterMapFile.c_str()); + dump += StringPrintf(INDENT3 "CountryCode: %d\n", + device->associatedDevice ? device->associatedDevice->countryCode + : InputDeviceCountryCode::INVALID); dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n", device->configurationFile.c_str()); - dump += INDENT3 "VideoDevice: "; - if (device->videoDevice) { - dump += device->videoDevice->dump() + "\n"; - } else { - dump += "<none>\n"; - } + dump += StringPrintf(INDENT3 "VideoDevice: %s\n", + device->videoDevice ? device->videoDevice->dump().c_str() + : "<none>"); + dump += StringPrintf(INDENT3 "SysfsDevicePath: %s\n", + device->associatedDevice + ? device->associatedDevice->sysfsRootPath.c_str() + : "<none>"); } dump += INDENT "Unattached video devices:\n"; @@ -2578,9 +2656,14 @@ void EventHub::dump(std::string& dump) { } // release lock } -void EventHub::monitor() { +void EventHub::monitor() const { // Acquire and release the lock to ensure that the event hub has not deadlocked. std::unique_lock<std::mutex> lock(mLock); } -}; // namespace android +std::string EventHub::AssociatedDevice::dump() const { + return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(), + batteryInfos.size(), lightInfos.size()); +} + +} // namespace android diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 3ee0fe8de6..6b9b9f1255 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -35,6 +35,8 @@ #include "SwitchInputMapper.h" #include "VibratorInputMapper.h" +using android::hardware::input::InputDeviceCountryCode; + namespace android { InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, @@ -232,6 +234,10 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { } void InputDevice::removeEventHubDevice(int32_t eventHubId) { + if (mController != nullptr && mController->getEventHubId() == eventHubId) { + // Delete mController, since the corresponding eventhub device is going away + mController = nullptr; + } mDevices.erase(eventHubId); } @@ -240,6 +246,7 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config mSources = 0; mClasses = ftl::Flags<InputDeviceClass>(0); mControllerNumber = 0; + mCountryCode = InputDeviceCountryCode::INVALID; for_each_subdevice([this](InputDeviceContext& context) { mClasses |= context.getDeviceClasses(); @@ -251,6 +258,16 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } mControllerNumber = controllerNumber; } + + InputDeviceCountryCode countryCode = context.getCountryCode(); + if (countryCode != InputDeviceCountryCode::INVALID) { + if (mCountryCode != InputDeviceCountryCode::INVALID && mCountryCode != countryCode) { + ALOGW("InputDevice::configure(): %s device contains multiple unique country " + "codes", + getName().c_str()); + } + mCountryCode = countryCode; + } }); mIsExternal = mClasses.test(InputDeviceClass::EXTERNAL); @@ -422,7 +439,7 @@ void InputDevice::updateExternalStylusState(const StylusState& state) { InputDeviceInfo InputDevice::getDeviceInfo() { InputDeviceInfo outDeviceInfo; outDeviceInfo.initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal, - mHasMic); + mHasMic, mCountryCode); for_each_mapper( [&outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(&outDeviceInfo); }); @@ -466,12 +483,12 @@ int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc ge return result; } -bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { +bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { bool result = false; - for_each_mapper([&result, sourceMask, numCodes, keyCodes, outFlags](InputMapper& mapper) { + for_each_mapper([&result, sourceMask, keyCodes, outFlags](InputMapper& mapper) { if (sourcesMatchMask(mapper.getSources(), sourceMask)) { - result |= mapper.markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + result |= mapper.markSupportedKeyCodes(sourceMask, keyCodes, outFlags); } }); return result; diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 905b348caa..86508766f5 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -120,14 +120,14 @@ void InputReader::loopOnce() { } } // release lock - size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); + std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis); { // acquire lock std::scoped_lock _l(mLock); mReaderIsAliveCondition.notify_all(); - if (count) { - processEventsLocked(mEventBuffer, count); + if (!events.empty()) { + processEventsLocked(events.data(), events.size()); } if (mNextTimeout != LLONG_MAX) { @@ -583,28 +583,28 @@ void InputReader::toggleCapsLockState(int32_t deviceId) { device->updateMetaState(AKEYCODE_CAPS_LOCK); } -bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { +bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, + const std::vector<int32_t>& keyCodes, uint8_t* outFlags) { std::scoped_lock _l(mLock); - memset(outFlags, 0, numCodes); - return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); + memset(outFlags, 0, keyCodes.size()); + return markSupportedKeyCodesLocked(deviceId, sourceMask, keyCodes, outFlags); } bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, + const std::vector<int32_t>& keyCodes, uint8_t* outFlags) { bool result = false; if (deviceId >= 0) { InputDevice* device = findInputDeviceLocked(deviceId); if (device && !device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + result = device->markSupportedKeyCodes(sourceMask, keyCodes, outFlags); } } else { for (auto& devicePair : mDevices) { std::shared_ptr<InputDevice>& device = devicePair.second; if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + result |= device->markSupportedKeyCodes(sourceMask, keyCodes, outFlags); } } } @@ -721,7 +721,10 @@ std::optional<int32_t> InputReader::getBatteryCapacity(int32_t deviceId) { if (!eventHubId) return {}; const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId); - if (batteryIds.empty()) return {}; + if (batteryIds.empty()) { + ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId); + return {}; + } return mEventHub->getBatteryCapacity(*eventHubId, batteryIds.front()); } @@ -741,10 +744,35 @@ std::optional<int32_t> InputReader::getBatteryStatus(int32_t deviceId) { if (!eventHubId) return {}; const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId); - if (batteryIds.empty()) return {}; + if (batteryIds.empty()) { + ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId); + return {}; + } return mEventHub->getBatteryStatus(*eventHubId, batteryIds.front()); } +std::optional<std::string> InputReader::getBatteryDevicePath(int32_t deviceId) { + std::scoped_lock _l(mLock); + + InputDevice* device = findInputDeviceLocked(deviceId); + if (!device) return {}; + + std::optional<int32_t> eventHubId = device->getBatteryEventHubId(); + if (!eventHubId) return {}; + const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId); + if (batteryIds.empty()) { + ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId); + return {}; + } + const auto batteryInfo = mEventHub->getRawBatteryInfo(*eventHubId, batteryIds.front()); + if (!batteryInfo) { + ALOGW("%s: Failed to get RawBatteryInfo for battery %d of EventHub device %d", __func__, + batteryIds.front(), *eventHubId); + return {}; + } + return batteryInfo->path; +} + std::vector<InputDeviceLightInfo> InputReader::getLights(int32_t deviceId) { std::scoped_lock _l(mLock); diff --git a/services/inputflinger/reader/Macros.h b/services/inputflinger/reader/Macros.h index d8376894f6..e107d882b7 100644 --- a/services/inputflinger/reader/Macros.h +++ b/services/inputflinger/reader/Macros.h @@ -14,33 +14,70 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_MACROS_H -#define _UI_INPUTREADER_MACROS_H +#pragma once #define LOG_TAG "InputReader" //#define LOG_NDEBUG 0 +#include <log/log.h> +#include <log/log_event_list.h> -// Log debug messages for each raw event received from the EventHub. -static constexpr bool DEBUG_RAW_EVENTS = false; +namespace android { +/** + * Log debug messages for each raw event received from the EventHub. + * Enable this via "adb shell setprop log.tag.InputReaderRawEvents DEBUG" (requires restart) + */ +const bool DEBUG_RAW_EVENTS = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "RawEvents", ANDROID_LOG_INFO); -// Log debug messages about virtual key processing. -static constexpr bool DEBUG_VIRTUAL_KEYS = false; +/** + * Log debug messages about virtual key processing. + * Enable this via "adb shell setprop log.tag.InputReaderVirtualKeys DEBUG" (requires restart) + */ +const bool DEBUG_VIRTUAL_KEYS = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "VirtualKeys", ANDROID_LOG_INFO); -// Log debug messages about pointers. -static constexpr bool DEBUG_POINTERS = false; +/** + * Log debug messages about pointers. + * Enable this via "adb shell setprop log.tag.InputReaderPointers DEBUG" (requires restart) + */ +const bool DEBUG_POINTERS = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Pointers", ANDROID_LOG_INFO); -// Log debug messages about pointer assignment calculations. -static constexpr bool DEBUG_POINTER_ASSIGNMENT = false; +/** + * Log debug messages about pointer assignment calculations. + * Enable this via "adb shell setprop log.tag.InputReaderPointerAssignment DEBUG" (requires restart) + */ +const bool DEBUG_POINTER_ASSIGNMENT = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "PointerAssignment", ANDROID_LOG_INFO); +/** + * Log debug messages about gesture detection. + * Enable this via "adb shell setprop log.tag.InputReaderGestures DEBUG" (requires restart) + */ +const bool DEBUG_GESTURES = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Gestures", ANDROID_LOG_INFO); -// Log debug messages about gesture detection. -static constexpr bool DEBUG_GESTURES = false; +/** + * Log debug messages about the vibrator. + * Enable this via "adb shell setprop log.tag.InputReaderVibrator DEBUG" (requires restart) + */ +const bool DEBUG_VIBRATOR = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Vibrator", ANDROID_LOG_INFO); -// Log debug messages about the vibrator. -static constexpr bool DEBUG_VIBRATOR = false; +/** + * Log debug messages about fusing stylus data. + * Enable this via "adb shell setprop log.tag.InputReaderStylusFusion DEBUG" (requires restart) + */ +const bool DEBUG_STYLUS_FUSION = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "StylusFusion", ANDROID_LOG_INFO); -// Log debug messages about fusing stylus data. -static constexpr bool DEBUG_STYLUS_FUSION = false; +/** + * Log detailed debug messages about input device lights. + * Enable this via "adb shell setprop log.tag.InputReaderLightDetails DEBUG" (requires restart) + */ +const bool DEBUG_LIGHT_DETAILS = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "LightDetails", ANDROID_LOG_INFO); +} // namespace android #define INDENT " " #define INDENT2 " " @@ -77,5 +114,3 @@ static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { } } // namespace android - -#endif // _UI_INPUTREADER_MACROS_H
\ No newline at end of file diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp index 8065f57524..cedbacb046 100644 --- a/services/inputflinger/reader/controller/PeripheralController.cpp +++ b/services/inputflinger/reader/controller/PeripheralController.cpp @@ -16,15 +16,13 @@ #include <locale> #include <regex> +#include <set> #include <ftl/enum.h> #include "../Macros.h" #include "PeripheralController.h" -// Log detailed debug messages about input device lights. -static constexpr bool DEBUG_LIGHT_DETAILS = false; - namespace android { static inline int32_t getAlpha(int32_t color) { @@ -73,7 +71,7 @@ std::optional<std::int32_t> PeripheralController::Light::getRawLightBrightness(i // If the light node doesn't have max brightness, use the default max brightness. int rawMaxBrightness = rawInfoOpt->maxBrightness.value_or(MAX_BRIGHTNESS); - float ratio = MAX_BRIGHTNESS / rawMaxBrightness; + float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness; // Scale the returned brightness in [0, rawMaxBrightness] to [0, 255] if (rawMaxBrightness != MAX_BRIGHTNESS) { brightness = brightness * ratio; @@ -92,7 +90,7 @@ void PeripheralController::Light::setRawLightBrightness(int32_t rawLightId, int3 } // If the light node doesn't have max brightness, use the default max brightness. int rawMaxBrightness = rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS); - float ratio = MAX_BRIGHTNESS / rawMaxBrightness; + float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness; // Scale the requested brightness in [0, 255] to [0, rawMaxBrightness] if (rawMaxBrightness != MAX_BRIGHTNESS) { brightness = ceil(brightness / ratio); @@ -274,7 +272,8 @@ void PeripheralController::populateDeviceInfo(InputDeviceInfo* deviceInfo) { for (const auto& [lightId, light] : mLights) { // Input device light doesn't support ordinal, always pass 1. - InputDeviceLightInfo lightInfo(light->name, light->id, light->type, 1 /* ordinal */); + InputDeviceLightInfo lightInfo(light->name, light->id, light->type, light->capabilityFlags, + 1 /* ordinal */); deviceInfo->addLightInfo(lightInfo); } } @@ -287,6 +286,8 @@ void PeripheralController::dump(std::string& dump) { dump += StringPrintf(INDENT4 "Id: %d", lightId); dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str()); dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str()); + dump += StringPrintf(INDENT4 "Capability flags: %s", + light->capabilityFlags.string().c_str()); light->dump(dump); } } @@ -366,6 +367,8 @@ void PeripheralController::configureLights() { std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds; // Map from player Id to raw light Id std::unordered_map<int32_t, int32_t> playerIdLightIds; + // Set of Keyboard backlights + std::set<int32_t> keyboardBacklightIds; // Check raw lights const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds(); @@ -394,6 +397,10 @@ void PeripheralController::configureLights() { } } } + // Check if this is a Keyboard backlight + if (rawInfo->flags.test(InputLightClass::KEYBOARD_BACKLIGHT)) { + keyboardBacklightIds.insert(rawId); + } // Check if this is an LED of RGB light if (rawInfo->flags.test(InputLightClass::RED)) { hasRedLed = true; @@ -434,8 +441,21 @@ void PeripheralController::configureLights() { ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED), rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE)); } + bool isKeyboardBacklight = keyboardBacklightIds.find(rawRgbIds.at(LightColor::RED)) != + keyboardBacklightIds.end() && + keyboardBacklightIds.find(rawRgbIds.at(LightColor::GREEN)) != + keyboardBacklightIds.end() && + keyboardBacklightIds.find(rawRgbIds.at(LightColor::BLUE)) != + keyboardBacklightIds.end() && + (!rawGlobalId.has_value() || + keyboardBacklightIds.find(rawGlobalId.value()) != keyboardBacklightIds.end()); + std::unique_ptr<Light> light = - std::make_unique<RgbLight>(getDeviceContext(), ++mNextId, rawRgbIds, rawGlobalId); + std::make_unique<RgbLight>(getDeviceContext(), ++mNextId, + isKeyboardBacklight + ? InputDeviceLightType::KEYBOARD_BACKLIGHT + : InputDeviceLightType::INPUT, + rawRgbIds, rawGlobalId); mLights.insert_or_assign(light->id, std::move(light)); // Remove from raw light info as they've been composed a RBG light. rawInfos.erase(rawRgbIds.at(LightColor::RED)); @@ -448,6 +468,10 @@ void PeripheralController::configureLights() { // Check the rest of raw light infos for (const auto& [rawId, rawInfo] : rawInfos) { + InputDeviceLightType type = keyboardBacklightIds.find(rawId) != keyboardBacklightIds.end() + ? InputDeviceLightType::KEYBOARD_BACKLIGHT + : InputDeviceLightType::INPUT; + // If the node is multi-color led, construct a MULTI_COLOR light if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) && rawInfo.flags.test(InputLightClass::MULTI_INTENSITY)) { @@ -456,7 +480,7 @@ void PeripheralController::configureLights() { } std::unique_ptr<Light> light = std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name, ++mNextId, - rawInfo.id); + type, rawInfo.id); mLights.insert_or_assign(light->id, std::move(light)); continue; } @@ -465,7 +489,7 @@ void PeripheralController::configureLights() { ALOGD("Mono light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str()); } std::unique_ptr<Light> light = std::make_unique<MonoLight>(getDeviceContext(), rawInfo.name, - ++mNextId, rawInfo.id); + ++mNextId, type, rawInfo.id); mLights.insert_or_assign(light->id, std::move(light)); } diff --git a/services/inputflinger/reader/controller/PeripheralController.h b/services/inputflinger/reader/controller/PeripheralController.h index ac951ebe2a..8ac42c3792 100644 --- a/services/inputflinger/reader/controller/PeripheralController.h +++ b/services/inputflinger/reader/controller/PeripheralController.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_LIGHT_CONTROLLER_H -#define _UI_INPUTREADER_LIGHT_CONTROLLER_H +#pragma once #include "PeripheralControllerInterface.h" @@ -68,6 +67,7 @@ private: std::string name; int32_t id; InputDeviceLightType type; + ftl::Flags<InputDeviceLightCapability> capabilityFlags; virtual bool setLightColor(int32_t color) { return false; } virtual std::optional<int32_t> getLightColor() { return std::nullopt; } @@ -82,8 +82,10 @@ private: struct MonoLight : public Light { explicit MonoLight(InputDeviceContext& context, const std::string& name, int32_t id, - int32_t rawId) - : Light(context, name, id, InputDeviceLightType::MONO), rawId(rawId) {} + InputDeviceLightType type, int32_t rawId) + : Light(context, name, id, type), rawId(rawId) { + capabilityFlags |= InputDeviceLightCapability::BRIGHTNESS; + } int32_t rawId; bool setLightColor(int32_t color) override; @@ -92,15 +94,15 @@ private: }; struct RgbLight : public Light { - explicit RgbLight(InputDeviceContext& context, int32_t id, + explicit RgbLight(InputDeviceContext& context, int32_t id, InputDeviceLightType type, const std::unordered_map<LightColor, int32_t>& rawRgbIds, std::optional<int32_t> rawGlobalId) - : Light(context, "RGB", id, InputDeviceLightType::RGB), - rawRgbIds(rawRgbIds), - rawGlobalId(rawGlobalId) { + : Light(context, "RGB", id, type), rawRgbIds(rawRgbIds), rawGlobalId(rawGlobalId) { brightness = rawGlobalId.has_value() ? getRawLightBrightness(rawGlobalId.value()).value_or(MAX_BRIGHTNESS) : MAX_BRIGHTNESS; + capabilityFlags |= InputDeviceLightCapability::BRIGHTNESS; + capabilityFlags |= InputDeviceLightCapability::RGB; } // Map from color to raw light id. std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds; @@ -115,8 +117,11 @@ private: struct MultiColorLight : public Light { explicit MultiColorLight(InputDeviceContext& context, const std::string& name, int32_t id, - int32_t rawId) - : Light(context, name, id, InputDeviceLightType::MULTI_COLOR), rawId(rawId) {} + InputDeviceLightType type, int32_t rawId) + : Light(context, name, id, type), rawId(rawId) { + capabilityFlags |= InputDeviceLightCapability::BRIGHTNESS; + capabilityFlags |= InputDeviceLightCapability::RGB; + } int32_t rawId; bool setLightColor(int32_t color) override; @@ -132,7 +137,7 @@ private: // Map from player Id to raw light Id std::unordered_map<int32_t, int32_t> rawLightIds; - bool setLightPlayerId(int32_t palyerId) override; + bool setLightPlayerId(int32_t playerId) override; std::optional<int32_t> getLightPlayerId() override; void dump(std::string& dump) override; }; @@ -150,5 +155,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_LIGHT_CONTROLLER_H diff --git a/services/inputflinger/reader/controller/PeripheralControllerInterface.h b/services/inputflinger/reader/controller/PeripheralControllerInterface.h index 306e36119b..76ed1ca038 100644 --- a/services/inputflinger/reader/controller/PeripheralControllerInterface.h +++ b/services/inputflinger/reader/controller/PeripheralControllerInterface.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_INPUT_CONTROLLER_H -#define _UI_INPUTREADER_INPUT_CONTROLLER_H +#pragma once #include "EventHub.h" #include "InputDevice.h" @@ -50,5 +49,3 @@ public: }; } // namespace android - -#endif // _UI_INPUTREADER_INPUT_CONTROLLER_H diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 54c6810a33..6933ec7399 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -14,13 +14,13 @@ * limitations under the License. */ -#ifndef _RUNTIME_EVENT_HUB_H -#define _RUNTIME_EVENT_HUB_H +#pragma once #include <bitset> #include <climits> #include <filesystem> #include <unordered_map> +#include <utility> #include <vector> #include <batteryservice/BatteryService.h> @@ -36,13 +36,15 @@ #include <sys/epoll.h> #include <utils/BitSet.h> #include <utils/Errors.h> -#include <utils/KeyedVector.h> #include <utils/List.h> #include <utils/Log.h> #include <utils/Mutex.h> #include "TouchVideoDevice.h" #include "VibrationElement.h" +#include "android/hardware/input/InputDeviceCountryCode.h" + +struct inotify_event; namespace android { @@ -172,6 +174,8 @@ enum class InputLightClass : uint32_t { MULTI_INTENSITY = 0x00000040, /* The input light has max brightness node. */ MAX_BRIGHTNESS = 0x00000080, + /* The input light has kbd_backlight name */ + KEYBOARD_BACKLIGHT = 0x00000100, }; enum class InputBatteryClass : uint32_t { @@ -191,6 +195,9 @@ struct RawLightInfo { ftl::Flags<InputLightClass> flags; std::array<int32_t, COLOR_NUM> rgbIndex; std::filesystem::path path; + + bool operator==(const RawLightInfo&) const = default; + bool operator!=(const RawLightInfo&) const = default; }; /* Describes a raw battery. */ @@ -199,6 +206,9 @@ struct RawBatteryInfo { std::string name; ftl::Flags<InputBatteryClass> flags; std::filesystem::path path; + + bool operator==(const RawBatteryInfo&) const = default; + bool operator!=(const RawBatteryInfo&) const = default; }; /* @@ -278,29 +288,30 @@ public: * * Returns the number of events obtained, or 0 if the timeout expired. */ - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; + virtual std::vector<RawEvent> getEvents(int timeoutMillis) = 0; virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) = 0; - virtual base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId, - int32_t absCode) = 0; + virtual base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor( + int32_t deviceId, int32_t absCode) const = 0; // Raw batteries are sysfs power_supply nodes we found from the EventHub device sysfs node, // containing the raw info of the sysfs node structure. - virtual const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) = 0; + virtual std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const = 0; virtual std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, - int32_t BatteryId) = 0; + int32_t BatteryId) const = 0; // Raw lights are sysfs led light nodes we found from the EventHub device sysfs node, // containing the raw info of the sysfs node structure. - virtual const std::vector<int32_t> getRawLightIds(int32_t deviceId) = 0; - virtual std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) = 0; - virtual std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) = 0; + virtual std::vector<int32_t> getRawLightIds(int32_t deviceId) const = 0; + virtual std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, + int32_t lightId) const = 0; + virtual std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const = 0; virtual void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) = 0; virtual std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( - int32_t deviceId, int32_t lightId) = 0; + int32_t deviceId, int32_t lightId) const = 0; virtual void setLightIntensities(int32_t deviceId, int32_t lightId, std::unordered_map<LightColor, int32_t> intensities) = 0; - /* - * Query current input state. - */ + /* Query Country code associated with the input device. */ + virtual hardware::input::InputDeviceCountryCode getCountryCode(int32_t deviceId) const = 0; + /* Query current input state. */ virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; @@ -311,7 +322,7 @@ public: /* * Examine key input devices for specific framework keycode support */ - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + virtual bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const = 0; virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; @@ -331,7 +342,7 @@ public: /* Control the vibrator. */ virtual void vibrate(int32_t deviceId, const VibrationElement& effect) = 0; virtual void cancelVibrate(int32_t deviceId) = 0; - virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0; + virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) const = 0; /* Query battery level. */ virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId, @@ -347,13 +358,13 @@ public: virtual void wake() = 0; /* Dump EventHub state to a string. */ - virtual void dump(std::string& dump) = 0; + virtual void dump(std::string& dump) const = 0; /* Called by the heatbeat to ensures that the reader has not deadlocked. */ - virtual void monitor() = 0; + virtual void monitor() const = 0; /* Return true if the device is enabled. */ - virtual bool isDeviceEnabled(int32_t deviceId) = 0; + virtual bool isDeviceEnabled(int32_t deviceId) const = 0; /* Enable an input device */ virtual status_t enableDevice(int32_t deviceId) = 0; @@ -461,23 +472,27 @@ public: AxisInfo* outAxisInfo) const override final; base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor( - int32_t deviceId, int32_t absCode) override final; + int32_t deviceId, int32_t absCode) const override final; - const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) override final; + std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override final; std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, - int32_t BatteryId) override final; + int32_t BatteryId) const override final; - const std::vector<int32_t> getRawLightIds(int32_t deviceId) override final; + std::vector<int32_t> getRawLightIds(int32_t deviceId) const override final; - std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override final; + std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, + int32_t lightId) const override final; - std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) override final; + std::optional<int32_t> getLightBrightness(int32_t deviceId, + int32_t lightId) const override final; void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override final; std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( - int32_t deviceId, int32_t lightId) override final; + int32_t deviceId, int32_t lightId) const override final; void setLightIntensities(int32_t deviceId, int32_t lightId, std::unordered_map<LightColor, int32_t> intensities) override final; + hardware::input::InputDeviceCountryCode getCountryCode(int32_t deviceId) const override final; + void setExcludedDevices(const std::vector<std::string>& devices) override final; int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override final; @@ -488,10 +503,10 @@ public: status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const override final; - bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const override final; - size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override final; + std::vector<RawEvent> getEvents(int timeoutMillis) override final; std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override final; bool hasScanCode(int32_t deviceId, int32_t scanCode) const override final; @@ -510,15 +525,15 @@ public: void vibrate(int32_t deviceId, const VibrationElement& effect) override final; void cancelVibrate(int32_t deviceId) override final; - std::vector<int32_t> getVibratorIds(int32_t deviceId) override final; + std::vector<int32_t> getVibratorIds(int32_t deviceId) const override final; void requestReopenDevices() override final; void wake() override final; - void dump(std::string& dump) override final; + void dump(std::string& dump) const override final; - void monitor() override final; + void monitor() const override final; std::optional<int32_t> getBatteryCapacity(int32_t deviceId, int32_t batteryId) const override final; @@ -526,7 +541,7 @@ public: std::optional<int32_t> getBatteryStatus(int32_t deviceId, int32_t batteryId) const override final; - bool isDeviceEnabled(int32_t deviceId) override final; + bool isDeviceEnabled(int32_t deviceId) const override final; status_t enableDevice(int32_t deviceId) override final; @@ -535,20 +550,17 @@ public: ~EventHub() override; private: + // Holds information about the sysfs device associated with the Device. struct AssociatedDevice { - // The device descriptor from evdev device the misc device associated with. - std::string descriptor; // The sysfs root path of the misc device. std::filesystem::path sysfsRootPath; + hardware::input::InputDeviceCountryCode countryCode; + std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> batteryInfos; + std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos; - int32_t nextBatteryId; - int32_t nextLightId; - std::unordered_map<int32_t, RawBatteryInfo> batteryInfos; - std::unordered_map<int32_t, RawLightInfo> lightInfos; - explicit AssociatedDevice(std::filesystem::path sysfsRootPath) - : sysfsRootPath(sysfsRootPath), nextBatteryId(0), nextLightId(0) {} - bool configureBatteryLocked(); - bool configureLightsLocked(); + bool operator==(const AssociatedDevice&) const = default; + bool operator!=(const AssociatedDevice&) const = default; + std::string dump() const; }; struct Device { @@ -581,13 +593,13 @@ private: int16_t ffEffectId; // initially -1 // A shared_ptr of a device associated with the input device. - // The input devices with same descriptor has the same associated device. - std::shared_ptr<AssociatedDevice> associatedDevice; + // The input devices that have the same sysfs path have the same associated device. + std::shared_ptr<const AssociatedDevice> associatedDevice; int32_t controllerNumber; - Device(int fd, int32_t id, const std::string& path, - const InputDeviceIdentifier& identifier); + Device(int fd, int32_t id, std::string path, InputDeviceIdentifier identifier, + std::shared_ptr<const AssociatedDevice> assocDev); ~Device(); void close(); @@ -632,6 +644,8 @@ private: void createVirtualKeyboardLocked() REQUIRES(mLock); void addDeviceLocked(std::unique_ptr<Device> device) REQUIRES(mLock); void assignDescriptorLocked(InputDeviceIdentifier& identifier) REQUIRES(mLock); + std::shared_ptr<const AssociatedDevice> obtainAssociatedDeviceLocked( + const std::filesystem::path& devicePath) const REQUIRES(mLock); void closeDeviceByPathLocked(const std::string& devicePath) REQUIRES(mLock); void closeVideoDeviceByPathLocked(const std::string& devicePath) REQUIRES(mLock); @@ -648,7 +662,8 @@ private: status_t scanDirLocked(const std::string& dirname) REQUIRES(mLock); status_t scanVideoDirLocked(const std::string& dirname) REQUIRES(mLock); void scanDevicesLocked() REQUIRES(mLock); - status_t readNotifyLocked() REQUIRES(mLock); + base::Result<void> readNotifyLocked() REQUIRES(mLock); + void handleNotifyEventLocked(const inotify_event&) REQUIRES(mLock); Device* getDeviceLocked(int32_t deviceId) const REQUIRES(mLock); Device* getDeviceByPathLocked(const std::string& devicePath) const REQUIRES(mLock); @@ -728,5 +743,3 @@ private: }; } // namespace android - -#endif // _RUNTIME_EVENT_HUB_H diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index b3a24af8a9..4ae9ae9dd0 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_INPUT_DEVICE_H -#define _UI_INPUTREADER_INPUT_DEVICE_H +#pragma once #include <ftl/flags.h> #include <input/DisplayViewport.h> @@ -86,7 +85,7 @@ public: int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const; - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, uint8_t* outFlags); void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token); void cancelVibrate(int32_t token); @@ -155,6 +154,7 @@ private: int32_t mId; int32_t mGeneration; int32_t mControllerNumber; + hardware::input::InputDeviceCountryCode mCountryCode; InputDeviceIdentifier mIdentifier; std::string mAlias; ftl::Flags<InputDeviceClass> mClasses; @@ -308,6 +308,9 @@ public: } inline std::vector<TouchVideoFrame> getVideoFrames() { return mEventHub->getVideoFrames(mId); } + inline hardware::input::InputDeviceCountryCode getCountryCode() const { + return mEventHub->getCountryCode(mId); + } inline int32_t getScanCodeState(int32_t scanCode) const { return mEventHub->getScanCodeState(mId, scanCode); } @@ -321,9 +324,9 @@ public: inline status_t getAbsoluteAxisValue(int32_t code, int32_t* outValue) const { return mEventHub->getAbsoluteAxisValue(mId, code, outValue); } - inline bool markSupportedKeyCodes(size_t numCodes, const int32_t* keyCodes, + inline bool markSupportedKeyCodes(const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const { - return mEventHub->markSupportedKeyCodes(mId, numCodes, keyCodes, outFlags); + return mEventHub->markSupportedKeyCodes(mId, keyCodes, outFlags); } inline bool hasScanCode(int32_t scanCode) const { return mEventHub->hasScanCode(mId, scanCode); @@ -405,5 +408,3 @@ private: }; } // namespace android - -#endif //_UI_INPUTREADER_INPUT_DEVICE_H diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index daeaa1dbe3..012d43fc3a 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_INPUT_READER_H -#define _UI_INPUTREADER_INPUT_READER_H +#pragma once #include <PointerControllerInterface.h> #include <android-base/thread_annotations.h> @@ -73,7 +72,7 @@ public: void toggleCapsLockState(int32_t deviceId) override; - bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, + bool hasKeys(int32_t deviceId, uint32_t sourceMask, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) override; void requestRefreshConfiguration(uint32_t changes) override; @@ -100,6 +99,8 @@ public: std::optional<int32_t> getBatteryStatus(int32_t deviceId) override; + std::optional<std::string> getBatteryDevicePath(int32_t deviceId) override; + std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) override; std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) override; @@ -169,10 +170,6 @@ private: InputReaderConfiguration mConfig GUARDED_BY(mLock); - // The event queue. - static const int EVENT_BUFFER_SIZE = 256; - RawEvent mEventBuffer[EVENT_BUFFER_SIZE] GUARDED_BY(mLock); - // An input device can represent a collection of EventHub devices. This map provides a way // to lookup the input device instance from the EventHub device id. std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices @@ -237,13 +234,12 @@ private: typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) REQUIRES(mLock); - bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) REQUIRES(mLock); + bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, + const std::vector<int32_t>& keyCodes, uint8_t* outFlags) + REQUIRES(mLock); // find an InputDevice from an InputDevice id InputDevice* findInputDeviceLocked(int32_t deviceId) const REQUIRES(mLock); }; } // namespace android - -#endif // _UI_INPUTREADER_INPUT_READER_H diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h index 823d160f86..f2f156c6e2 100644 --- a/services/inputflinger/reader/include/InputReaderContext.h +++ b/services/inputflinger/reader/include/InputReaderContext.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_INPUT_READER_CONTEXT_H -#define _UI_INPUTREADER_INPUT_READER_CONTEXT_H +#pragma once #include <input/InputDevice.h> @@ -65,5 +64,3 @@ public: }; } // namespace android - -#endif // _UI_INPUTREADER_INPUT_READER_CONTEXT_H diff --git a/services/inputflinger/reader/include/StylusState.h b/services/inputflinger/reader/include/StylusState.h index 17f158c9e1..8d14d3c169 100644 --- a/services/inputflinger/reader/include/StylusState.h +++ b/services/inputflinger/reader/include/StylusState.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_STYLUS_STATE_H -#define _UI_INPUTREADER_STYLUS_STATE_H +#pragma once #include <input/Input.h> @@ -49,5 +48,3 @@ struct StylusState { }; } // namespace android - -#endif // _UI_INPUTREADER_STYLUS_STATE_H diff --git a/services/inputflinger/reader/include/TouchVideoDevice.h b/services/inputflinger/reader/include/TouchVideoDevice.h index 7de9b830b2..08eba31199 100644 --- a/services/inputflinger/reader/include/TouchVideoDevice.h +++ b/services/inputflinger/reader/include/TouchVideoDevice.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H -#define _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H +#pragma once #include <android-base/unique_fd.h> #include <input/TouchVideoFrame.h> @@ -123,5 +122,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index f4f3ae95a1..d6d324b5b2 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -245,18 +245,17 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* void CursorInputMapper::configureParameters() { mParameters.mode = Parameters::Mode::POINTER; - String8 cursorModeString; - if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"), - cursorModeString)) { + std::string cursorModeString; + if (getDeviceContext().getConfiguration().tryGetProperty("cursor.mode", cursorModeString)) { if (cursorModeString == "navigation") { mParameters.mode = Parameters::Mode::NAVIGATION; } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); + ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.c_str()); } } mParameters.orientationAware = false; - getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.orientationAware"), + getDeviceContext().getConfiguration().tryGetProperty("cursor.orientationAware", mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 60b3dd9ee0..a0229a74c7 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H -#define _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H +#pragma once #include "CursorButtonAccumulator.h" #include "CursorScrollAccumulator.h" @@ -129,5 +128,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h index 516aa51a14..03d9909b51 100644 --- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h +++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H -#define _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H +#pragma once #include "InputMapper.h" @@ -49,5 +48,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp index 7b185e029c..75cebf3ddb 100644 --- a/services/inputflinger/reader/mapper/InputMapper.cpp +++ b/services/inputflinger/reader/mapper/InputMapper.cpp @@ -55,8 +55,8 @@ int32_t InputMapper::getKeyCodeForKeyLocation(int32_t locationKeyCode) const { return AKEYCODE_UNKNOWN; } -bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { +bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { return false; } diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h index fce6409b3f..5567cac6a9 100644 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_INPUT_MAPPER_H -#define _UI_INPUTREADER_INPUT_MAPPER_H +#pragma once #include "EventHub.h" #include "InputDevice.h" @@ -64,8 +63,8 @@ public: virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); virtual int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const; - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags); virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t token); virtual bool isVibrating(); @@ -109,5 +108,3 @@ protected: }; } // namespace android - -#endif // _UI_INPUTREADER_INPUT_MAPPER_H diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h index 307bf5b38b..e0023970de 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.h +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H -#define _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H +#pragma once #include "InputMapper.h" @@ -111,5 +110,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index 2ac81781fa..9bb6273d71 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -127,7 +127,6 @@ void KeyboardInputMapper::dump(std::string& dump) { dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation()); dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState); - dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); } std::optional<DisplayViewport> KeyboardInputMapper::findViewport( @@ -160,7 +159,7 @@ void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* property) { int32_t mapped = 0; - if (config.tryGetProperty(String8(property), mapped) && mapped > 0) { + if (config.tryGetProperty(property, mapped) && mapped > 0) { for (size_t i = 0; i < stemKeyRotationMapSize; i++) { if (stemKeyRotationMap[i][0] == keyCode) { stemKeyRotationMap[i][1] = mapped; @@ -173,7 +172,7 @@ static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* p void KeyboardInputMapper::configureParameters() { mParameters.orientationAware = false; const PropertyMap& config = getDeviceContext().getConfiguration(); - config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware); + config.tryGetProperty("keyboard.orientationAware", mParameters.orientationAware); if (mParameters.orientationAware) { mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary"); @@ -183,10 +182,10 @@ void KeyboardInputMapper::configureParameters() { } mParameters.handlesKeyRepeat = false; - config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat); + config.tryGetProperty("keyboard.handlesKeyRepeat", mParameters.handlesKeyRepeat); mParameters.doNotWakeByDefault = false; - config.tryGetProperty(String8("keyboard.doNotWakeByDefault"), mParameters.doNotWakeByDefault); + config.tryGetProperty("keyboard.doNotWakeByDefault", mParameters.doNotWakeByDefault); } void KeyboardInputMapper::dumpParameters(std::string& dump) { @@ -196,9 +195,7 @@ void KeyboardInputMapper::dumpParameters(std::string& dump) { } void KeyboardInputMapper::reset(nsecs_t when) { - mMetaState = AMETA_NONE; - mDownTime = 0; - mKeyDowns.clear(); + cancelAllDownKeys(when); mCurrentHidUsage = 0; resetLedState(); @@ -281,6 +278,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, policyFlags = 0; } + nsecs_t downTime = when; if (down) { // Rotate key codes according to orientation if needed. if (mParameters.orientationAware) { @@ -292,6 +290,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, if (keyDownIndex >= 0) { // key repeat, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns[keyDownIndex].keyCode; + downTime = mKeyDowns[keyDownIndex].downTime; } else { // key down if ((policyFlags & POLICY_FLAG_VIRTUAL) && @@ -305,16 +304,16 @@ void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, KeyDown keyDown; keyDown.keyCode = keyCode; keyDown.scanCode = scanCode; + keyDown.downTime = when; mKeyDowns.push_back(keyDown); } - - mDownTime = when; } else { // Remove key down. ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { // key up, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns[keyDownIndex].keyCode; + downTime = mKeyDowns[keyDownIndex].downTime; mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex); } else { // key was not actually down @@ -333,8 +332,6 @@ void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, keyMetaState = mMetaState; } - nsecs_t downTime = mDownTime; - // Key down on external an keyboard should wake the device. // We don't do this for internal keyboards to prevent them from waking up in your pocket. // For internal keyboards and devices for which the default wake behavior is explicitly @@ -379,9 +376,10 @@ int32_t KeyboardInputMapper::getKeyCodeForKeyLocation(int32_t locationKeyCode) c return getDeviceContext().getKeyCodeForKeyLocation(locationKeyCode); } -bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return getDeviceContext().markSupportedKeyCodes(numCodes, keyCodes, outFlags); +bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, + const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { + return getDeviceContext().markSupportedKeyCodes(keyCodes, outFlags); } int32_t KeyboardInputMapper::getMetaState() { @@ -433,13 +431,12 @@ void KeyboardInputMapper::updateLedState(bool reset) { mMetaState |= getContext()->getLedMetaState(); constexpr int32_t META_NUM = 3; - const std::array<int32_t, META_NUM> keyCodes = {AKEYCODE_CAPS_LOCK, AKEYCODE_NUM_LOCK, - AKEYCODE_SCROLL_LOCK}; + const std::vector<int32_t> keyCodes{AKEYCODE_CAPS_LOCK, AKEYCODE_NUM_LOCK, + AKEYCODE_SCROLL_LOCK}; const std::array<int32_t, META_NUM> metaCodes = {AMETA_CAPS_LOCK_ON, AMETA_NUM_LOCK_ON, AMETA_SCROLL_LOCK_ON}; std::array<uint8_t, META_NUM> flags = {0, 0, 0}; - bool hasKeyLayout = - getDeviceContext().markSupportedKeyCodes(META_NUM, keyCodes.data(), flags.data()); + bool hasKeyLayout = getDeviceContext().markSupportedKeyCodes(keyCodes, flags.data()); // If the device doesn't have the physical meta key it shouldn't generate the corresponding // meta state. if (hasKeyLayout) { @@ -473,4 +470,19 @@ std::optional<int32_t> KeyboardInputMapper::getAssociatedDisplayId() { return std::nullopt; } +void KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) { + size_t n = mKeyDowns.size(); + for (size_t i = 0; i < n; i++) { + NotifyKeyArgs args(getContext()->getNextId(), when, systemTime(SYSTEM_TIME_MONOTONIC), + getDeviceId(), mSource, getDisplayId(), 0 /*policyFlags*/, + AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED, + mKeyDowns[i].keyCode, mKeyDowns[i].scanCode, AMETA_NONE, + mKeyDowns[i].downTime); + getListener().notifyKey(&args); + } + mKeyDowns.clear(); + mMetaState = AMETA_NONE; +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h index 378769639e..2136d253c9 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H -#define _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H +#pragma once #include "InputMapper.h" @@ -36,8 +35,8 @@ public: virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override; virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override; - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) override; + virtual bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) override; virtual int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const override; virtual int32_t getMetaState() override; @@ -50,6 +49,7 @@ private: std::optional<DisplayViewport> mViewport; struct KeyDown { + nsecs_t downTime; int32_t keyCode; int32_t scanCode; }; @@ -59,7 +59,6 @@ private: std::vector<KeyDown> mKeyDowns; // keys that are down int32_t mMetaState; - nsecs_t mDownTime; // time of most recent key down int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none @@ -98,8 +97,7 @@ private: void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset); std::optional<DisplayViewport> findViewport(nsecs_t when, const InputReaderConfiguration* config); + void cancelAllDownKeys(nsecs_t when); }; } // namespace android - -#endif // _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index 41a8426e42..8f5dc9bfd5 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -31,23 +31,15 @@ static constexpr size_t MAX_SLOTS = 32; MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), - mSlots(nullptr), - mSlotCount(0), mUsingSlotsProtocol(false), mHaveStylus(false) {} -MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { - delete[] mSlots; -} - void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol) { - mSlotCount = slotCount; mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - delete[] mSlots; - mSlots = new Slot[slotCount]; + mSlots = std::vector<Slot>(slotCount); } void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) { @@ -76,10 +68,8 @@ void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) { } void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - if (mSlots) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); - } + for (Slot& slot : mSlots) { + slot.clear(); } mCurrentSlot = initialSlot; } @@ -96,68 +86,68 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { mCurrentSlot = 0; } - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { + if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { if (DEBUG_POINTERS) { if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %zd; ignoring this slot.", - mCurrentSlot, mSlotCount - 1); + mCurrentSlot, mSlots.size() - 1); } } } else { - Slot* slot = &mSlots[mCurrentSlot]; + Slot& slot = mSlots[mCurrentSlot]; // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while // updating the slot. if (!mUsingSlotsProtocol) { - slot->mInUse = true; + slot.mInUse = true; } switch (rawEvent->code) { case ABS_MT_POSITION_X: - slot->mAbsMTPositionX = rawEvent->value; - warnIfNotInUse(*rawEvent, *slot); + slot.mAbsMTPositionX = rawEvent->value; + warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_POSITION_Y: - slot->mAbsMTPositionY = rawEvent->value; - warnIfNotInUse(*rawEvent, *slot); + slot.mAbsMTPositionY = rawEvent->value; + warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_TOUCH_MAJOR: - slot->mAbsMTTouchMajor = rawEvent->value; + slot.mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: - slot->mAbsMTTouchMinor = rawEvent->value; - slot->mHaveAbsMTTouchMinor = true; + slot.mAbsMTTouchMinor = rawEvent->value; + slot.mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: - slot->mAbsMTWidthMajor = rawEvent->value; + slot.mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: - slot->mAbsMTWidthMinor = rawEvent->value; - slot->mHaveAbsMTWidthMinor = true; + slot.mAbsMTWidthMinor = rawEvent->value; + slot.mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: - slot->mAbsMTOrientation = rawEvent->value; + slot.mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. - slot->mInUse = false; + slot.mInUse = false; } else { - slot->mInUse = true; - slot->mAbsMTTrackingId = rawEvent->value; + slot.mInUse = true; + slot.mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: - slot->mAbsMTPressure = rawEvent->value; + slot.mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: - slot->mAbsMTDistance = rawEvent->value; + slot.mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: - slot->mAbsMTToolType = rawEvent->value; - slot->mHaveAbsMTToolType = true; + slot.mAbsMTToolType = rawEvent->value; + slot.mHaveAbsMTToolType = true; break; } } @@ -186,28 +176,6 @@ void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Sl // --- MultiTouchMotionAccumulator::Slot --- -MultiTouchMotionAccumulator::Slot::Slot() { - clear(); -} - -void MultiTouchMotionAccumulator::Slot::clear() { - mInUse = false; - mHaveAbsMTTouchMinor = false; - mHaveAbsMTWidthMinor = false; - mHaveAbsMTToolType = false; - mAbsMTPositionX = 0; - mAbsMTPositionY = 0; - mAbsMTTouchMajor = 0; - mAbsMTTouchMinor = 0; - mAbsMTWidthMajor = 0; - mAbsMTWidthMinor = 0; - mAbsMTOrientation = 0; - mAbsMTTrackingId = -1; - mAbsMTPressure = 0; - mAbsMTDistance = 0; - mAbsMTToolType = 0; -} - int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMTToolType) { switch (mAbsMTToolType) { @@ -264,14 +232,14 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { mHavePointerIds = true; for (size_t inIndex = 0; inIndex < inCount; inIndex++) { - const MultiTouchMotionAccumulator::Slot* inSlot = + const MultiTouchMotionAccumulator::Slot& inSlot = mMultiTouchMotionAccumulator.getSlot(inIndex); - if (!inSlot->isInUse()) { + if (!inSlot.isInUse()) { continue; } - if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { - std::optional<int32_t> id = getActiveBitId(*inSlot); + if (inSlot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { + std::optional<int32_t> id = getActiveBitId(inSlot); if (id) { outState->rawPointerData.canceledIdBits.markBit(id.value()); } @@ -292,19 +260,19 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { } RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; - outPointer.x = inSlot->getX(); - outPointer.y = inSlot->getY(); - outPointer.pressure = inSlot->getPressure(); - outPointer.touchMajor = inSlot->getTouchMajor(); - outPointer.touchMinor = inSlot->getTouchMinor(); - outPointer.toolMajor = inSlot->getToolMajor(); - outPointer.toolMinor = inSlot->getToolMinor(); - outPointer.orientation = inSlot->getOrientation(); - outPointer.distance = inSlot->getDistance(); + outPointer.x = inSlot.getX(); + outPointer.y = inSlot.getY(); + outPointer.pressure = inSlot.getPressure(); + outPointer.touchMajor = inSlot.getTouchMajor(); + outPointer.touchMinor = inSlot.getTouchMinor(); + outPointer.toolMajor = inSlot.getToolMajor(); + outPointer.toolMinor = inSlot.getToolMinor(); + outPointer.orientation = inSlot.getOrientation(); + outPointer.distance = inSlot.getDistance(); outPointer.tiltX = 0; outPointer.tiltY = 0; - outPointer.toolType = inSlot->getToolType(); + outPointer.toolType = inSlot.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { @@ -318,12 +286,12 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || - (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); + (mRawPointerAxes.pressure.valid && inSlot.getPressure() <= 0)); outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. if (mHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); + int32_t trackingId = inSlot.getTrackingId(); int32_t id = -1; if (trackingId >= 0) { for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) { diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h index b7c3457285..212c9c9108 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H -#define _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H +#pragma once #include "TouchInputMapper.h" @@ -46,29 +45,27 @@ public: private: friend class MultiTouchMotionAccumulator; - bool mInUse; - bool mHaveAbsMTTouchMinor; - bool mHaveAbsMTWidthMinor; - bool mHaveAbsMTToolType; - - int32_t mAbsMTPositionX; - int32_t mAbsMTPositionY; - int32_t mAbsMTTouchMajor; - int32_t mAbsMTTouchMinor; - int32_t mAbsMTWidthMajor; - int32_t mAbsMTWidthMinor; - int32_t mAbsMTOrientation; - int32_t mAbsMTTrackingId; - int32_t mAbsMTPressure; - int32_t mAbsMTDistance; - int32_t mAbsMTToolType; - - Slot(); - void clear(); + bool mInUse = false; + bool mHaveAbsMTTouchMinor = false; + bool mHaveAbsMTWidthMinor = false; + bool mHaveAbsMTToolType = false; + + int32_t mAbsMTPositionX = 0; + int32_t mAbsMTPositionY = 0; + int32_t mAbsMTTouchMajor = 0; + int32_t mAbsMTTouchMinor = 0; + int32_t mAbsMTWidthMajor = 0; + int32_t mAbsMTWidthMinor = 0; + int32_t mAbsMTOrientation = 0; + int32_t mAbsMTTrackingId = -1; + int32_t mAbsMTPressure = 0; + int32_t mAbsMTDistance = 0; + int32_t mAbsMTToolType = 0; + + void clear() { *this = Slot(); } }; MultiTouchMotionAccumulator(); - ~MultiTouchMotionAccumulator(); void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); void reset(InputDeviceContext& deviceContext); @@ -76,13 +73,15 @@ public: void finishSync(); bool hasStylus() const; - inline size_t getSlotCount() const { return mSlotCount; } - inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } + inline size_t getSlotCount() const { return mSlots.size(); } + inline const Slot& getSlot(size_t index) const { + LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); + return mSlots[index]; + } private: int32_t mCurrentSlot; - Slot* mSlots; - size_t mSlotCount; + std::vector<Slot> mSlots; bool mUsingSlotsProtocol; bool mHaveStylus; @@ -122,5 +121,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index eca25f6e6a..05973f783c 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -40,10 +40,10 @@ void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { float res = 0.0f; - if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.res"), res)) { + if (!getDeviceContext().getConfiguration().tryGetProperty("device.res", res)) { ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); } - if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.scalingFactor"), + if (!getDeviceContext().getConfiguration().tryGetProperty("device.scalingFactor", mScalingFactor)) { ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," "default to 1.0!\n"); diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h index 1859355a93..42e2421c37 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H -#define _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H +#pragma once #include "CursorScrollAccumulator.h" #include "InputMapper.h" @@ -46,5 +45,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp index b01c2bc13f..573f99cf87 100644 --- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp @@ -64,7 +64,7 @@ uint32_t SensorInputMapper::getSources() const { template <typename T> bool SensorInputMapper::tryGetProperty(std::string keyName, T& outValue) { const auto& config = getDeviceContext().getConfiguration(); - return config.tryGetProperty(String8(keyName.c_str()), outValue); + return config.tryGetProperty(keyName, outValue); } void SensorInputMapper::parseSensorConfiguration(InputDeviceSensorType sensorType, int32_t absCode, diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.h b/services/inputflinger/reader/mapper/SensorInputMapper.h index 27a61771f2..38d4c3c935 100644 --- a/services/inputflinger/reader/mapper/SensorInputMapper.h +++ b/services/inputflinger/reader/mapper/SensorInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H -#define _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H +#pragma once #include "InputMapper.h" @@ -133,5 +132,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h index 9cb3f67f20..f54c19502e 100644 --- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H -#define _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H +#pragma once #include "SingleTouchMotionAccumulator.h" #include "TouchInputMapper.h" @@ -40,5 +39,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.h b/services/inputflinger/reader/mapper/SwitchInputMapper.h index 64b9aa27b4..e0c949f012 100644 --- a/services/inputflinger/reader/mapper/SwitchInputMapper.h +++ b/services/inputflinger/reader/mapper/SwitchInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H -#define _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H +#pragma once #include "InputMapper.h" @@ -41,5 +40,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 31a3d2e172..42d819b362 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H -#define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H +#pragma once #include <input/DisplayViewport.h> #include <stdint.h> @@ -99,5 +98,3 @@ static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, ns } } // namespace android - -#endif // _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 2ddacef02d..4cd2cce9f9 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -42,6 +42,8 @@ static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); // data. static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); +// Minimum width between two pointers to determine a gesture as freeform gesture in mm +static const float MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER = 30; // --- Static Definitions --- static const DisplayViewport kUninitializedViewport; @@ -206,30 +208,30 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { y.fuzz, y.resolution); } - if (mOrientedRanges.haveSize) { - info->addMotionRange(mOrientedRanges.size); + if (mOrientedRanges.size) { + info->addMotionRange(*mOrientedRanges.size); } - if (mOrientedRanges.haveTouchSize) { - info->addMotionRange(mOrientedRanges.touchMajor); - info->addMotionRange(mOrientedRanges.touchMinor); + if (mOrientedRanges.touchMajor) { + info->addMotionRange(*mOrientedRanges.touchMajor); + info->addMotionRange(*mOrientedRanges.touchMinor); } - if (mOrientedRanges.haveToolSize) { - info->addMotionRange(mOrientedRanges.toolMajor); - info->addMotionRange(mOrientedRanges.toolMinor); + if (mOrientedRanges.toolMajor) { + info->addMotionRange(*mOrientedRanges.toolMajor); + info->addMotionRange(*mOrientedRanges.toolMinor); } - if (mOrientedRanges.haveOrientation) { - info->addMotionRange(mOrientedRanges.orientation); + if (mOrientedRanges.orientation) { + info->addMotionRange(*mOrientedRanges.orientation); } - if (mOrientedRanges.haveDistance) { - info->addMotionRange(mOrientedRanges.distance); + if (mOrientedRanges.distance) { + info->addMotionRange(*mOrientedRanges.distance); } - if (mOrientedRanges.haveTilt) { - info->addMotionRange(mOrientedRanges.tilt); + if (mOrientedRanges.tilt) { + info->addMotionRange(*mOrientedRanges.tilt); } if (mCursorScrollAccumulator.haveRelativeVWheel()) { @@ -421,15 +423,15 @@ void TouchInputMapper::configureParameters() { ? Parameters::GestureMode::SINGLE_TOUCH : Parameters::GestureMode::MULTI_TOUCH; - String8 gestureModeString; - if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.gestureMode"), + std::string gestureModeString; + if (getDeviceContext().getConfiguration().tryGetProperty("touch.gestureMode", gestureModeString)) { if (gestureModeString == "single-touch") { mParameters.gestureMode = Parameters::GestureMode::SINGLE_TOUCH; } else if (gestureModeString == "multi-touch") { mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH; } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); + ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.c_str()); } } @@ -439,11 +441,6 @@ void TouchInputMapper::configureParameters() { } else if (getDeviceContext().hasInputProperty(INPUT_PROP_POINTER)) { // The device is a pointing device like a track pad. mParameters.deviceType = Parameters::DeviceType::POINTER; - } else if (getDeviceContext().hasRelativeAxis(REL_X) || - getDeviceContext().hasRelativeAxis(REL_Y)) { - // The device is a cursor device with a touch pad attached. - // By default don't use the touch pad to move the pointer. - mParameters.deviceType = Parameters::DeviceType::TOUCH_PAD; } else { // The device is a touch pad of unknown purpose. mParameters.deviceType = Parameters::DeviceType::POINTER; @@ -451,29 +448,27 @@ void TouchInputMapper::configureParameters() { mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD); - String8 deviceTypeString; - if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.deviceType"), + std::string deviceTypeString; + if (getDeviceContext().getConfiguration().tryGetProperty("touch.deviceType", deviceTypeString)) { if (deviceTypeString == "touchScreen") { mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN; - } else if (deviceTypeString == "touchPad") { - mParameters.deviceType = Parameters::DeviceType::TOUCH_PAD; } else if (deviceTypeString == "touchNavigation") { mParameters.deviceType = Parameters::DeviceType::TOUCH_NAVIGATION; } else if (deviceTypeString == "pointer") { mParameters.deviceType = Parameters::DeviceType::POINTER; } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); + ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str()); } } mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN; - getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"), + getDeviceContext().getConfiguration().tryGetProperty("touch.orientationAware", mParameters.orientationAware); mParameters.orientation = Parameters::Orientation::ORIENTATION_0; - String8 orientationString; - if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientation"), + std::string orientationString; + if (getDeviceContext().getConfiguration().tryGetProperty("touch.orientation", orientationString)) { if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) { ALOGW("The configuration 'touch.orientation' is only supported for touchscreens."); @@ -484,7 +479,7 @@ void TouchInputMapper::configureParameters() { } else if (orientationString == "ORIENTATION_270") { mParameters.orientation = Parameters::Orientation::ORIENTATION_270; } else if (orientationString != "ORIENTATION_0") { - ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string()); + ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str()); } } @@ -496,8 +491,8 @@ void TouchInputMapper::configureParameters() { mParameters.hasAssociatedDisplay = true; if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) { mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal(); - String8 uniqueDisplayId; - getDeviceContext().getConfiguration().tryGetProperty(String8("touch.displayId"), + std::string uniqueDisplayId; + getDeviceContext().getConfiguration().tryGetProperty("touch.displayId", uniqueDisplayId); mParameters.uniqueDisplayId = uniqueDisplayId.c_str(); } @@ -510,7 +505,7 @@ void TouchInputMapper::configureParameters() { // Normally we don't do this for internal touch screens to prevent them from waking // up in your pocket but you can enable it using the input device configuration. mParameters.wake = getDeviceContext().isExternal(); - getDeviceContext().getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake); + getDeviceContext().getConfiguration().tryGetProperty("touch.wake", mParameters.wake); } void TouchInputMapper::dumpParameters(std::string& dump) { @@ -645,57 +640,58 @@ void TouchInputMapper::initializeSizeRanges() { mSizeScale = 0.0f; } - mOrientedRanges.haveTouchSize = true; - mOrientedRanges.haveToolSize = true; - mOrientedRanges.haveSize = true; + mOrientedRanges.touchMajor = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR, + .source = mSource, + .min = 0, + .max = diagonalSize, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; - mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mSource; - mOrientedRanges.touchMajor.min = 0; - mOrientedRanges.touchMajor.max = diagonalSize; - mOrientedRanges.touchMajor.flat = 0; - mOrientedRanges.touchMajor.fuzz = 0; - mOrientedRanges.touchMajor.resolution = 0; if (mRawPointerAxes.touchMajor.valid) { mRawPointerAxes.touchMajor.resolution = clampResolution("touchMajor", mRawPointerAxes.touchMajor.resolution); - mOrientedRanges.touchMajor.resolution = mRawPointerAxes.touchMajor.resolution; + mOrientedRanges.touchMajor->resolution = mRawPointerAxes.touchMajor.resolution; } mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; - mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; + mOrientedRanges.touchMinor->axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; if (mRawPointerAxes.touchMinor.valid) { mRawPointerAxes.touchMinor.resolution = clampResolution("touchMinor", mRawPointerAxes.touchMinor.resolution); - mOrientedRanges.touchMinor.resolution = mRawPointerAxes.touchMinor.resolution; - } - - mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mSource; - mOrientedRanges.toolMajor.min = 0; - mOrientedRanges.toolMajor.max = diagonalSize; - mOrientedRanges.toolMajor.flat = 0; - mOrientedRanges.toolMajor.fuzz = 0; - mOrientedRanges.toolMajor.resolution = 0; + mOrientedRanges.touchMinor->resolution = mRawPointerAxes.touchMinor.resolution; + } + + mOrientedRanges.toolMajor = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_TOOL_MAJOR, + .source = mSource, + .min = 0, + .max = diagonalSize, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; if (mRawPointerAxes.toolMajor.valid) { mRawPointerAxes.toolMajor.resolution = clampResolution("toolMajor", mRawPointerAxes.toolMajor.resolution); - mOrientedRanges.toolMajor.resolution = mRawPointerAxes.toolMajor.resolution; + mOrientedRanges.toolMajor->resolution = mRawPointerAxes.toolMajor.resolution; } mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; - mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; + mOrientedRanges.toolMinor->axis = AMOTION_EVENT_AXIS_TOOL_MINOR; if (mRawPointerAxes.toolMinor.valid) { mRawPointerAxes.toolMinor.resolution = clampResolution("toolMinor", mRawPointerAxes.toolMinor.resolution); - mOrientedRanges.toolMinor.resolution = mRawPointerAxes.toolMinor.resolution; + mOrientedRanges.toolMinor->resolution = mRawPointerAxes.toolMinor.resolution; } if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) { - mOrientedRanges.touchMajor.resolution *= mGeometricScale; - mOrientedRanges.touchMinor.resolution *= mGeometricScale; - mOrientedRanges.toolMajor.resolution *= mGeometricScale; - mOrientedRanges.toolMinor.resolution *= mGeometricScale; + mOrientedRanges.touchMajor->resolution *= mGeometricScale; + mOrientedRanges.touchMinor->resolution *= mGeometricScale; + mOrientedRanges.toolMajor->resolution *= mGeometricScale; + mOrientedRanges.toolMinor->resolution *= mGeometricScale; } else { // Support for other calibrations can be added here. ALOGW("%s calibration is not supported for size ranges at the moment. " @@ -703,13 +699,15 @@ void TouchInputMapper::initializeSizeRanges() { ftl::enum_string(mCalibration.sizeCalibration).c_str()); } - mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mSource; - mOrientedRanges.size.min = 0; - mOrientedRanges.size.max = 1.0; - mOrientedRanges.size.flat = 0; - mOrientedRanges.size.fuzz = 0; - mOrientedRanges.size.resolution = 0; + mOrientedRanges.size = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_SIZE, + .source = mSource, + .min = 0, + .max = 1.0, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; } void TouchInputMapper::initializeOrientedRanges() { @@ -736,21 +734,23 @@ void TouchInputMapper::initializeOrientedRanges() { float pressureMax = 1.0; if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL || mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; + if (mCalibration.pressureScale) { + mPressureScale = *mCalibration.pressureScale; pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; } } - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = pressureMax; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; - mOrientedRanges.pressure.resolution = 0; + mOrientedRanges.pressure = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_PRESSURE, + .source = mSource, + .min = 0, + .max = pressureMax, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; // Tilt mTiltXCenter = 0; @@ -771,29 +771,30 @@ void TouchInputMapper::initializeOrientedRanges() { mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution; } - mOrientedRanges.haveTilt = true; - - mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; - mOrientedRanges.tilt.source = mSource; - mOrientedRanges.tilt.min = 0; - mOrientedRanges.tilt.max = M_PI_2; - mOrientedRanges.tilt.flat = 0; - mOrientedRanges.tilt.fuzz = 0; - mOrientedRanges.tilt.resolution = 0; + mOrientedRanges.tilt = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_TILT, + .source = mSource, + .min = 0, + .max = M_PI_2, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; } // Orientation mOrientationScale = 0; if (mHaveTilt) { - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI; - mOrientedRanges.orientation.max = M_PI; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; + mOrientedRanges.orientation = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_ORIENTATION, + .source = mSource, + .min = -M_PI, + .max = M_PI, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; + } else if (mCalibration.orientationCalibration != Calibration::OrientationCalibration::NONE) { if (mCalibration.orientationCalibration == Calibration::OrientationCalibration::INTERPOLATED) { @@ -808,37 +809,34 @@ void TouchInputMapper::initializeOrientedRanges() { } } - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; + mOrientedRanges.orientation = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_ORIENTATION, + .source = mSource, + .min = -M_PI_2, + .max = M_PI_2, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; } // Distance mDistanceScale = 0; if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) { if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) { - if (mCalibration.haveDistanceScale) { - mDistanceScale = mCalibration.distanceScale; - } else { - mDistanceScale = 1.0f; - } + mDistanceScale = mCalibration.distanceScale.value_or(1.0f); } - mOrientedRanges.haveDistance = true; + mOrientedRanges.distance = InputDeviceInfo::MotionRange{ - mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mSource; - mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; - mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale; - mOrientedRanges.distance.flat = 0; - mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale; - mOrientedRanges.distance.resolution = 0; + .axis = AMOTION_EVENT_AXIS_DISTANCE, + .source = mSource, + .min = mRawPointerAxes.distance.minValue * mDistanceScale, + .max = mRawPointerAxes.distance.maxValue * mDistanceScale, + .flat = 0, + .fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale, + .resolution = 0, + }; } // Compute oriented precision, scales and ranges. @@ -935,6 +933,11 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) // Raw width and height in the natural orientation. const int32_t rawWidth = mRawPointerAxes.getRawWidth(); const int32_t rawHeight = mRawPointerAxes.getRawHeight(); + const int32_t rawXResolution = mRawPointerAxes.x.resolution; + const int32_t rawYResolution = mRawPointerAxes.y.resolution; + // Calculate the mean resolution when both x and y resolution are set, otherwise set it to 0. + const float rawMeanResolution = + (rawXResolution > 0 && rawYResolution > 0) ? (rawXResolution + rawYResolution) / 2 : 0; const DisplayViewport& newViewport = newViewportOpt.value_or(kUninitializedViewport); const bool viewportChanged = mViewport != newViewport; @@ -1017,8 +1020,9 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) : getInverseRotation(mViewport.orientation); // For orientation-aware devices that work in the un-rotated coordinate space, the // viewport update should be skipped if it is only a change in the orientation. - skipViewportUpdate = mParameters.orientationAware && mDisplayWidth == oldDisplayWidth && - mDisplayHeight == oldDisplayHeight && viewportOrientationChanged; + skipViewportUpdate = !viewportDisplayIdChanged && mParameters.orientationAware && + mDisplayWidth == oldDisplayWidth && mDisplayHeight == oldDisplayHeight && + viewportOrientationChanged; // Apply the input device orientation for the device. mInputDeviceOrientation = @@ -1033,8 +1037,6 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) mDisplayHeight = rawHeight; mInputDeviceOrientation = DISPLAY_ORIENTATION_0; } - // If displayId changed, do not skip viewport update. - skipViewportUpdate &= !viewportDisplayIdChanged; } // If moving between pointer modes, need to reset some state. @@ -1097,10 +1099,14 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; mPointerYZoomScale = mPointerXZoomScale; - // Max width between pointers to detect a swipe gesture is more than some fraction - // of the diagonal axis of the touch pad. Touches that are wider than this are - // translated into freeform gestures. - mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; + // Calculate the min freeform gesture width. It will be 0 when the resolution of any + // axis is non positive value. + const float minFreeformGestureWidth = + rawMeanResolution * MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER; + + mPointerGestureMaxSwipeWidth = + std::max(mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal, + minFreeformGestureWidth); } // Inform the dispatcher about the changes. @@ -1191,8 +1197,8 @@ void TouchInputMapper::parseCalibration() { // Size out.sizeCalibration = Calibration::SizeCalibration::DEFAULT; - String8 sizeCalibrationString; - if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { + std::string sizeCalibrationString; + if (in.tryGetProperty("touch.size.calibration", sizeCalibrationString)) { if (sizeCalibrationString == "none") { out.sizeCalibration = Calibration::SizeCalibration::NONE; } else if (sizeCalibrationString == "geometric") { @@ -1204,18 +1210,28 @@ void TouchInputMapper::parseCalibration() { } else if (sizeCalibrationString == "area") { out.sizeCalibration = Calibration::SizeCalibration::AREA; } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string()); + ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.c_str()); } } - out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale); - out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias); - out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed); + float sizeScale; + + if (in.tryGetProperty("touch.size.scale", sizeScale)) { + out.sizeScale = sizeScale; + } + float sizeBias; + if (in.tryGetProperty("touch.size.bias", sizeBias)) { + out.sizeBias = sizeBias; + } + bool sizeIsSummed; + if (in.tryGetProperty("touch.size.isSummed", sizeIsSummed)) { + out.sizeIsSummed = sizeIsSummed; + } // Pressure out.pressureCalibration = Calibration::PressureCalibration::DEFAULT; - String8 pressureCalibrationString; - if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { + std::string pressureCalibrationString; + if (in.tryGetProperty("touch.pressure.calibration", pressureCalibrationString)) { if (pressureCalibrationString == "none") { out.pressureCalibration = Calibration::PressureCalibration::NONE; } else if (pressureCalibrationString == "physical") { @@ -1224,16 +1240,19 @@ void TouchInputMapper::parseCalibration() { out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE; } else if (pressureCalibrationString != "default") { ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); + pressureCalibrationString.c_str()); } } - out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale); + float pressureScale; + if (in.tryGetProperty("touch.pressure.scale", pressureScale)) { + out.pressureScale = pressureScale; + } // Orientation out.orientationCalibration = Calibration::OrientationCalibration::DEFAULT; - String8 orientationCalibrationString; - if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { + std::string orientationCalibrationString; + if (in.tryGetProperty("touch.orientation.calibration", orientationCalibrationString)) { if (orientationCalibrationString == "none") { out.orientationCalibration = Calibration::OrientationCalibration::NONE; } else if (orientationCalibrationString == "interpolated") { @@ -1242,36 +1261,39 @@ void TouchInputMapper::parseCalibration() { out.orientationCalibration = Calibration::OrientationCalibration::VECTOR; } else if (orientationCalibrationString != "default") { ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); + orientationCalibrationString.c_str()); } } // Distance out.distanceCalibration = Calibration::DistanceCalibration::DEFAULT; - String8 distanceCalibrationString; - if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { + std::string distanceCalibrationString; + if (in.tryGetProperty("touch.distance.calibration", distanceCalibrationString)) { if (distanceCalibrationString == "none") { out.distanceCalibration = Calibration::DistanceCalibration::NONE; } else if (distanceCalibrationString == "scaled") { out.distanceCalibration = Calibration::DistanceCalibration::SCALED; } else if (distanceCalibrationString != "default") { ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); + distanceCalibrationString.c_str()); } } - out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale); + float distanceScale; + if (in.tryGetProperty("touch.distance.scale", distanceScale)) { + out.distanceScale = distanceScale; + } out.coverageCalibration = Calibration::CoverageCalibration::DEFAULT; - String8 coverageCalibrationString; - if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { + std::string coverageCalibrationString; + if (in.tryGetProperty("touch.coverage.calibration", coverageCalibrationString)) { if (coverageCalibrationString == "none") { out.coverageCalibration = Calibration::CoverageCalibration::NONE; } else if (coverageCalibrationString == "box") { out.coverageCalibration = Calibration::CoverageCalibration::BOX; } else if (coverageCalibrationString != "default") { ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); + coverageCalibrationString.c_str()); } } } @@ -1325,17 +1347,17 @@ void TouchInputMapper::dumpCalibration(std::string& dump) { dump += INDENT4 "touch.size.calibration: "; dump += ftl::enum_string(mCalibration.sizeCalibration) + "\n"; - if (mCalibration.haveSizeScale) { - dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale); + if (mCalibration.sizeScale) { + dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", *mCalibration.sizeScale); } - if (mCalibration.haveSizeBias) { - dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias); + if (mCalibration.sizeBias) { + dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", *mCalibration.sizeBias); } - if (mCalibration.haveSizeIsSummed) { + if (mCalibration.sizeIsSummed) { dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n", - toString(mCalibration.sizeIsSummed)); + toString(*mCalibration.sizeIsSummed)); } // Pressure @@ -1353,8 +1375,8 @@ void TouchInputMapper::dumpCalibration(std::string& dump) { ALOG_ASSERT(false); } - if (mCalibration.havePressureScale) { - dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale); + if (mCalibration.pressureScale) { + dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", *mCalibration.pressureScale); } // Orientation @@ -1384,8 +1406,8 @@ void TouchInputMapper::dumpCalibration(std::string& dump) { ALOG_ASSERT(false); } - if (mCalibration.haveDistanceScale) { - dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale); + if (mCalibration.distanceScale) { + dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", *mCalibration.distanceScale); } switch (mCalibration.coverageCalibration) { @@ -1502,14 +1524,13 @@ void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) { assignPointerIds(last, next); } - if (DEBUG_RAW_EVENTS) { - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x, canceled ids 0x%08x", - last.rawPointerData.pointerCount, next.rawPointerData.pointerCount, - last.rawPointerData.touchingIdBits.value, next.rawPointerData.touchingIdBits.value, - last.rawPointerData.hoveringIdBits.value, next.rawPointerData.hoveringIdBits.value, - next.rawPointerData.canceledIdBits.value); - } + ALOGD_IF(DEBUG_RAW_EVENTS, + "syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " + "hovering ids 0x%08x -> 0x%08x, canceled ids 0x%08x", + last.rawPointerData.pointerCount, next.rawPointerData.pointerCount, + last.rawPointerData.touchingIdBits.value, next.rawPointerData.touchingIdBits.value, + last.rawPointerData.hoveringIdBits.value, next.rawPointerData.hoveringIdBits.value, + next.rawPointerData.canceledIdBits.value); if (!next.rawPointerData.touchingIdBits.isEmpty() && !next.rawPointerData.hoveringIdBits.isEmpty() && @@ -1563,9 +1584,8 @@ void TouchInputMapper::processRawTouches(bool timeout) { nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; clearStylusDataPendingFlags(); mCurrentRawState.copyFrom(mLastRawState); - if (DEBUG_STYLUS_FUSION) { - ALOGD("Timeout expired, synthesizing event with new stylus data"); - } + ALOGD_IF(DEBUG_STYLUS_FUSION, + "Timeout expired, synthesizing event with new stylus data"); const nsecs_t readTime = when; // consider this synthetic event to be zero latency cookAndDispatch(when, readTime); } else if (mExternalStylusFusionTimeout == LLONG_MAX) { @@ -1751,24 +1771,18 @@ bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeou state.rawPointerData.pointerCount != 0; if (initialDown) { if (mExternalStylusState.pressure != 0.0f) { - if (DEBUG_STYLUS_FUSION) { - ALOGD("Have both stylus and touch data, beginning fusion"); - } + ALOGD_IF(DEBUG_STYLUS_FUSION, "Have both stylus and touch data, beginning fusion"); mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); } else if (timeout) { - if (DEBUG_STYLUS_FUSION) { - ALOGD("Timeout expired, assuming touch is not a stylus."); - } + ALOGD_IF(DEBUG_STYLUS_FUSION, "Timeout expired, assuming touch is not a stylus."); resetExternalStylus(); } else { if (mExternalStylusFusionTimeout == LLONG_MAX) { mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT; } - if (DEBUG_STYLUS_FUSION) { - ALOGD("No stylus data but stylus is connected, requesting timeout " - "(%" PRId64 "ms)", - mExternalStylusFusionTimeout); - } + ALOGD_IF(DEBUG_STYLUS_FUSION, + "No stylus data but stylus is connected, requesting timeout (%" PRId64 "ms)", + mExternalStylusFusionTimeout); getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); return true; } @@ -1776,9 +1790,7 @@ bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeou // Check if the stylus pointer has gone up. if (mExternalStylusId != -1 && !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { - if (DEBUG_STYLUS_FUSION) { - ALOGD("Stylus pointer is going up"); - } + ALOGD_IF(DEBUG_STYLUS_FUSION, "Stylus pointer is going up"); mExternalStylusId = -1; } @@ -1819,10 +1831,9 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_ // Pointer went up while virtual key was down. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { - if (DEBUG_VIRTUAL_KEYS) { - ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); - } + ALOGD_IF(DEBUG_VIRTUAL_KEYS, + "VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", + mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); } @@ -1846,10 +1857,8 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_ // into the main display surface. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { - if (DEBUG_VIRTUAL_KEYS) { - ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); - } + ALOGD_IF(DEBUG_VIRTUAL_KEYS, "VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", + mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | AKEY_EVENT_FLAG_CANCELED); @@ -1879,10 +1888,9 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_ virtualKey->scanCode); if (!mCurrentVirtualKey.ignored) { - if (DEBUG_VIRTUAL_KEYS) { - ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); - } + ALOGD_IF(DEBUG_VIRTUAL_KEYS, + "VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", + mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_DOWN, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); @@ -1942,7 +1950,8 @@ void TouchInputMapper::abortTouches(nsecs_t when, nsecs_t readTime, uint32_t pol mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); mCurrentMotionAborted = true; } } @@ -1962,7 +1971,8 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); } } else { // There may be pointers going up and pointers going down and pointers moving @@ -1997,7 +2007,8 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); dispatchedIdBits.clearBit(upId); mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId); } @@ -2012,7 +2023,8 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); } // Dispatch pointer down events using the new pointer locations. @@ -2030,7 +2042,8 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, - downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); + downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); } } } @@ -2046,7 +2059,7 @@ void TouchInputMapper::dispatchHoverExit(nsecs_t when, nsecs_t readTime, uint32_ mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, - mOrientedYPrecision, mDownTime); + mOrientedYPrecision, mDownTime, MotionClassification::NONE); mSentHoverEnter = false; } } @@ -2063,7 +2076,8 @@ void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, nsecs_t readTime, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); mSentHoverEnter = true; } @@ -2073,7 +2087,8 @@ void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, nsecs_t readTime, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); } } @@ -2090,7 +2105,8 @@ void TouchInputMapper::dispatchButtonRelease(nsecs_t when, nsecs_t readTime, uin mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); } } @@ -2107,7 +2123,8 @@ void TouchInputMapper::dispatchButtonPress(nsecs_t when, nsecs_t readTime, uint3 mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mOrientedXPrecision, mOrientedYPrecision, mDownTime, + MotionClassification::NONE); } } @@ -2178,7 +2195,7 @@ void TouchInputMapper::cookPointerData() { size = 0; } - if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { + if (mCalibration.sizeIsSummed && *mCalibration.sizeIsSummed) { uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count(); if (touchingCount > 1) { touchMajor /= touchingCount; @@ -2204,13 +2221,16 @@ void TouchInputMapper::cookPointerData() { toolMinor = toolMajor; } - mCalibration.applySizeScaleAndBias(&touchMajor); - mCalibration.applySizeScaleAndBias(&touchMinor); - mCalibration.applySizeScaleAndBias(&toolMajor); - mCalibration.applySizeScaleAndBias(&toolMinor); + mCalibration.applySizeScaleAndBias(touchMajor); + mCalibration.applySizeScaleAndBias(touchMinor); + mCalibration.applySizeScaleAndBias(toolMajor); + mCalibration.applySizeScaleAndBias(toolMinor); size *= mSizeScale; break; - default: + case Calibration::SizeCalibration::DEFAULT: + LOG_ALWAYS_FATAL("Resolution should not be 'DEFAULT' at this point"); + break; + case Calibration::SizeCalibration::NONE: touchMajor = 0; touchMinor = 0; toolMajor = 0; @@ -2307,10 +2327,9 @@ void TouchInputMapper::cookPointerData() { bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; orientation -= M_PI_2; - if (mOrientedRanges.haveOrientation && - orientation < mOrientedRanges.orientation.min) { + if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) { orientation += - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min); } break; case DISPLAY_ORIENTATION_180: @@ -2319,10 +2338,9 @@ void TouchInputMapper::cookPointerData() { bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; orientation -= M_PI; - if (mOrientedRanges.haveOrientation && - orientation < mOrientedRanges.orientation.min) { + if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) { orientation += - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min); } break; case DISPLAY_ORIENTATION_270: @@ -2331,10 +2349,9 @@ void TouchInputMapper::cookPointerData() { bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale; top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale; orientation += M_PI_2; - if (mOrientedRanges.haveOrientation && - orientation > mOrientedRanges.orientation.max) { + if (mOrientedRanges.orientation && orientation > mOrientedRanges.orientation->max) { orientation -= - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min); } break; default: @@ -2494,6 +2511,10 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // Send events! int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentCookedState.buttonState; + const MotionClassification classification = + mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE + ? MotionClassification::TWO_FINGER_SWIPE + : MotionClassification::NONE; uint32_t flags = 0; @@ -2534,7 +2555,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, - mPointerGesture.downTime); + mPointerGesture.downTime, classification); dispatchedGestureIdBits.clear(); } else { @@ -2553,7 +2574,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0, - 0, mPointerGesture.downTime); + 0, mPointerGesture.downTime, classification); dispatchedGestureIdBits.clearBit(id); } @@ -2567,7 +2588,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, - mPointerGesture.downTime); + mPointerGesture.downTime, classification); } // Send motion events for all pointers that went down. @@ -2587,7 +2608,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0, - 0, mPointerGesture.downTime); + 0, mPointerGesture.downTime, classification); } } @@ -2598,7 +2619,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime); + mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime, + MotionClassification::NONE); } else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) { // Synthesize a hover move event after all pointers go up to indicate that // the pointer is hovering again even if the user is not currently touching @@ -2645,6 +2667,10 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } void TouchInputMapper::abortPointerGestures(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) { + const MotionClassification classification = + mPointerGesture.lastGestureMode == PointerGesture::Mode::SWIPE + ? MotionClassification::TWO_FINGER_SWIPE + : MotionClassification::NONE; // Cancel previously dispatches pointers. if (!mPointerGesture.lastGestureIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); @@ -2653,7 +2679,7 @@ void TouchInputMapper::abortPointerGestures(nsecs_t when, nsecs_t readTime, uint metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); + 0, 0, mPointerGesture.downTime, classification); } // Reset the current pointer gesture. @@ -2674,9 +2700,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Handle TAP timeout. if (isTimeout) { - if (DEBUG_GESTURES) { - ALOGD("Gestures: Processing timeout"); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: Processing timeout"); if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { @@ -2685,9 +2709,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mConfig.pointerGestureTapDragInterval); } else { // The tap is finished. - if (DEBUG_GESTURES) { - ALOGD("Gestures: TAP finished"); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: TAP finished"); *outFinishPreviousGesture = true; mPointerGesture.activeGestureId = -1; @@ -2708,17 +2730,18 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Update the velocity tracker. { - std::vector<VelocityTracker::Position> positions; + std::vector<float> positionsX; + std::vector<float> positionsY; for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) { uint32_t id = idBits.clearFirstMarkedBit(); const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); - float x = pointer.x * mPointerXMovementScale; - float y = pointer.y * mPointerYMovementScale; - positions.push_back({x, y}); + positionsX.push_back(pointer.x * mPointerXMovementScale); + positionsY.push_back(pointer.y * mPointerYMovementScale); } mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits, - positions); + {{AMOTION_EVENT_AXIS_X, positionsX}, + {AMOTION_EVENT_AXIS_Y, positionsY}}); } // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning @@ -2783,11 +2806,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Switch states based on button and pointer state. if (isQuietTime) { // Case 1: Quiet time. (QUIET) - if (DEBUG_GESTURES) { - ALOGD("Gestures: QUIET for next %0.3fms", - (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * - 0.000001f); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: QUIET for next %0.3fms", + (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * + 0.000001f); if (mPointerGesture.lastGestureMode != PointerGesture::Mode::QUIET) { *outFinishPreviousGesture = true; } @@ -2811,11 +2832,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // active. If the user first puts one finger down to click then adds another // finger to drag then the active pointer should switch to the finger that is // being dragged. - if (DEBUG_GESTURES) { - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " - "currentFingerCount=%d", - activeTouchId, currentFingerCount); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, currentFingerCount=%d", + activeTouchId, currentFingerCount); // Reset state when just starting. if (mPointerGesture.lastGestureMode != PointerGesture::Mode::BUTTON_CLICK_OR_DRAG) { *outFinishPreviousGesture = true; @@ -2829,9 +2848,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) { uint32_t id = idBits.clearFirstMarkedBit(); - float vx, vy; - if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { - float speed = hypotf(vx, vy); + std::optional<float> vx = + mPointerGesture.velocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, id); + std::optional<float> vy = + mPointerGesture.velocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, id); + if (vx && vy) { + float speed = hypotf(*vx, *vy); if (speed > bestSpeed) { bestId = id; bestSpeed = speed; @@ -2840,30 +2862,17 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi } if (bestId >= 0 && bestId != activeTouchId) { mPointerGesture.activeTouchId = activeTouchId = bestId; - if (DEBUG_GESTURES) { - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " - "bestId=%d, bestSpeed=%0.3f", - bestId, bestSpeed); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: BUTTON_CLICK_OR_DRAG switched pointers, bestId=%d, " + "bestSpeed=%0.3f", + bestId, bestSpeed); } } - float deltaX = 0, deltaY = 0; if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawState.rawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawState.rawPointerData.pointerForId(activeTouchId); - deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); + moveMousePointerFromPointerDelta(when, activeTouchId); } else { mPointerVelocityControl.reset(); } @@ -2899,9 +2908,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { - if (DEBUG_GESTURES) { - ALOGD("Gestures: TAP"); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: TAP"); mPointerGesture.tapUpTime = when; getContext()->requestTimeoutAtTime(when + @@ -2927,10 +2934,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi tapped = true; } else { - if (DEBUG_GESTURES) { - ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", x - mPointerGesture.tapX, - y - mPointerGesture.tapY); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP, deltaX=%f, deltaY=%f", + x - mPointerGesture.tapX, y - mPointerGesture.tapY); } } else { if (DEBUG_GESTURES) { @@ -2947,9 +2952,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerVelocityControl.reset(); if (!tapped) { - if (DEBUG_GESTURES) { - ALOGD("Gestures: NEUTRAL"); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: NEUTRAL"); mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); @@ -2970,50 +2973,30 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG; } else { - if (DEBUG_GESTURES) { - ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, y - mPointerGesture.tapY); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", + x - mPointerGesture.tapX, y - mPointerGesture.tapY); } } else { - if (DEBUG_GESTURES) { - ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", - (when - mPointerGesture.tapUpTime) * 0.000001f); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP_DRAG, %0.3fms time since up", + (when - mPointerGesture.tapUpTime) * 0.000001f); } } else if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) { mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG; } - float deltaX = 0, deltaY = 0; if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawState.rawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawState.rawPointerData.pointerForId(activeTouchId); - deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. - mPointerController->move(deltaX, deltaY); + moveMousePointerFromPointerDelta(when, activeTouchId); } else { mPointerVelocityControl.reset(); } bool down; if (mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG) { - if (DEBUG_GESTURES) { - ALOGD("Gestures: TAP_DRAG"); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: TAP_DRAG"); down = true; } else { - if (DEBUG_GESTURES) { - ALOGD("Gestures: HOVER"); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: HOVER"); if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER) { *outFinishPreviousGesture = true; } @@ -3067,13 +3050,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi } else if (!settled && currentFingerCount > lastFingerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. - if (DEBUG_GESTURES) { - ALOGD("Gestures: Resetting gesture since additional pointers went down for " - "MULTITOUCH, settle time remaining %0.3fms", - (mPointerGesture.firstTouchTime + - mConfig.pointerGestureMultitouchSettleInterval - when) * - 0.000001f); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: Resetting gesture since additional pointers went down for " + "MULTITOUCH, settle time remaining %0.3fms", + (mPointerGesture.firstTouchTime + + mConfig.pointerGestureMultitouchSettleInterval - when) * + 0.000001f); *outCancelPreviousGesture = true; } else { // Continue previous gesture. @@ -3087,13 +3069,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerVelocityControl.reset(); // Use the centroid and pointer location as the reference points for the gesture. - if (DEBUG_GESTURES) { - ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " - "settle time remaining %0.3fms", - (mPointerGesture.firstTouchTime + - mConfig.pointerGestureMultitouchSettleInterval - when) * - 0.000001f); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: Using centroid as reference for MULTITOUCH, settle time remaining " + "%0.3fms", + (mPointerGesture.firstTouchTime + + mConfig.pointerGestureMultitouchSettleInterval - when) * + 0.000001f); mCurrentRawState.rawPointerData .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); @@ -3151,10 +3132,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi if (distOverThreshold >= 2) { if (currentFingerCount > 2) { // There are more than two pointers, switch to FREEFORM. - if (DEBUG_GESTURES) { - ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", + currentFingerCount); *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM; } else { @@ -3170,11 +3150,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi if (mutualDistance > mPointerGestureMaxSwipeWidth) { // There are two pointers but they are too far apart for a SWIPE, // switch to FREEFORM. - if (DEBUG_GESTURES) { - ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > " - "%0.3f", - mutualDistance, mPointerGestureMaxSwipeWidth); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", + mutualDistance, mPointerGestureMaxSwipeWidth); *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM; } else { @@ -3199,25 +3177,23 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi float cosine = dot / (dist1 * dist2); // denominator always > 0 if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { // Pointers are moving in the same direction. Switch to SWIPE. - if (DEBUG_GESTURES) { - ALOGD("Gestures: PRESS transitioned to SWIPE, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f >= %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, - mConfig.pointerGestureMultitouchMinDistance, cosine, - mConfig.pointerGestureSwipeTransitionAngleCosine); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: PRESS transitioned to SWIPE, " + "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " + "cosine %0.3f >= %0.3f", + dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, + mConfig.pointerGestureMultitouchMinDistance, cosine, + mConfig.pointerGestureSwipeTransitionAngleCosine); mPointerGesture.currentGestureMode = PointerGesture::Mode::SWIPE; } else { // Pointers are moving in different directions. Switch to FREEFORM. - if (DEBUG_GESTURES) { - ALOGD("Gestures: PRESS transitioned to FREEFORM, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f < %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, - mConfig.pointerGestureMultitouchMinDistance, cosine, - mConfig.pointerGestureSwipeTransitionAngleCosine); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: PRESS transitioned to FREEFORM, " + "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " + "cosine %0.3f < %0.3f", + dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, + mConfig.pointerGestureMultitouchMinDistance, cosine, + mConfig.pointerGestureSwipeTransitionAngleCosine); *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM; } @@ -3229,10 +3205,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Switch from SWIPE to FREEFORM if additional pointers go down. // Cancel previous gesture. if (currentFingerCount > 2) { - if (DEBUG_GESTURES) { - ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", + currentFingerCount); *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM; } @@ -3266,11 +3241,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS || mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) { // PRESS or SWIPE mode. - if (DEBUG_GESTURES) { - ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: PRESS or SWIPE activeTouchId=%d, activeGestureId=%d, " + "currentTouchPointerCount=%d", + activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); mPointerGesture.currentGestureIdBits.clear(); @@ -3287,11 +3261,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) { // FREEFORM mode. - if (DEBUG_GESTURES) { - ALOGD("Gestures: FREEFORM activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: FREEFORM activeTouchId=%d, activeGestureId=%d, " + "currentTouchPointerCount=%d", + activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); mPointerGesture.currentGestureIdBits.clear(); @@ -3330,13 +3303,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi } } - if (DEBUG_GESTURES) { - ALOGD("Gestures: FREEFORM follow up " - "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " - "activeGestureId=%d", - mappedTouchIdBits.value, usedGestureIdBits.value, - mPointerGesture.activeGestureId); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: FREEFORM follow up mappedTouchIdBits=0x%08x, " + "usedGestureIdBits=0x%08x, activeGestureId=%d", + mappedTouchIdBits.value, usedGestureIdBits.value, + mPointerGesture.activeGestureId); BitSet32 idBits(mCurrentCookedState.fingerIdBits); for (uint32_t i = 0; i < currentFingerCount; i++) { @@ -3345,18 +3316,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi if (!mappedTouchIdBits.hasBit(touchId)) { gestureId = usedGestureIdBits.markFirstUnmarkedBit(); mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; - if (DEBUG_GESTURES) { - ALOGD("Gestures: FREEFORM " - "new mapping for touch id %d -> gesture id %d", - touchId, gestureId); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: FREEFORM new mapping for touch id %d -> gesture id %d", + touchId, gestureId); } else { gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; - if (DEBUG_GESTURES) { - ALOGD("Gestures: FREEFORM " - "existing mapping for touch id %d -> gesture id %d", - touchId, gestureId); - } + ALOGD_IF(DEBUG_GESTURES, + "Gestures: FREEFORM existing mapping for touch id %d -> gesture id %d", + touchId, gestureId); } mPointerGesture.currentGestureIdBits.markBit(gestureId); mPointerGesture.currentGestureIdToIndex[gestureId] = i; @@ -3385,10 +3352,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi if (mPointerGesture.activeGestureId < 0) { mPointerGesture.activeGestureId = mPointerGesture.currentGestureIdBits.firstMarkedBit(); - if (DEBUG_GESTURES) { - ALOGD("Gestures: FREEFORM new activeGestureId=%d", - mPointerGesture.activeGestureId); - } + ALOGD_IF(DEBUG_GESTURES, "Gestures: FREEFORM new activeGestureId=%d", + mPointerGesture.activeGestureId); } } } @@ -3428,6 +3393,20 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi return true; } +void TouchInputMapper::moveMousePointerFromPointerDelta(nsecs_t when, uint32_t pointerId) { + const RawPointerData::Pointer& currentPointer = + mCurrentRawState.rawPointerData.pointerForId(pointerId); + const RawPointerData::Pointer& lastPointer = + mLastRawState.rawPointerData.pointerForId(pointerId); + float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; + float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; + + rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + mPointerController->move(deltaX, deltaY); +} + void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) { mPointerSimple.currentCoords.clear(); mPointerSimple.currentProperties.clear(); @@ -3471,21 +3450,8 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint bool down, hovering; if (!mCurrentCookedState.mouseIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; - float deltaX = 0, deltaY = 0; if (mLastCookedState.mouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; - deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x - - mLastRawState.rawPointerData.pointers[lastIndex].x) * - mPointerXMovementScale; - deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y - - mLastRawState.rawPointerData.pointers[lastIndex].y) * - mPointerYMovementScale; - - rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - mPointerController->move(deltaX, deltaY); + moveMousePointerFromPointerDelta(when, id); } else { mPointerVelocityControl.reset(); } @@ -3495,6 +3461,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint float x, y; mPointerController->getPosition(&x, &y); + uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3662,7 +3629,8 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, - float yPrecision, nsecs_t downTime) { + float yPrecision, nsecs_t downTime, + MotionClassification classification) { PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; @@ -3710,9 +3678,9 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p [this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); }); NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId, policyFlags, action, actionButton, flags, metaState, buttonState, - MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties, - pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition, - downTime, std::move(frames)); + classification, edgeFlags, pointerCount, pointerProperties, pointerCoords, + xPrecision, yPrecision, xCursorPosition, yCursorPosition, downTime, + std::move(frames)); getListener().notifyMotion(&args); } @@ -3798,12 +3766,11 @@ bool TouchInputMapper::isPointInsidePhysicalFrame(int32_t x, int32_t y) const { const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) { for (const VirtualKey& virtualKey : mVirtualKeys) { - if (DEBUG_VIRTUAL_KEYS) { - ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " - "left=%d, top=%d, right=%d, bottom=%d", - x, y, virtualKey.keyCode, virtualKey.scanCode, virtualKey.hitLeft, - virtualKey.hitTop, virtualKey.hitRight, virtualKey.hitBottom); - } + ALOGD_IF(DEBUG_VIRTUAL_KEYS, + "VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " + "left=%d, top=%d, right=%d, bottom=%d", + x, y, virtualKey.keyCode, virtualKey.scanCode, virtualKey.hitLeft, + virtualKey.hitTop, virtualKey.hitRight, virtualKey.hitBottom); if (virtualKey.isHit(x, y)) { return &virtualKey; @@ -3974,11 +3941,10 @@ void TouchInputMapper::assignPointerIds(const RawState& last, RawState& current) currentPointerIndex)); usedIdBits.markBit(id); - if (DEBUG_POINTER_ASSIGNMENT) { - ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 ", id=%" PRIu32 - ", distance=%" PRIu64, - lastPointerIndex, currentPointerIndex, id, heap[0].distance); - } + ALOGD_IF(DEBUG_POINTER_ASSIGNMENT, + "assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 ", id=%" PRIu32 + ", distance=%" PRIu64, + lastPointerIndex, currentPointerIndex, id, heap[0].distance); break; } } @@ -3993,10 +3959,9 @@ void TouchInputMapper::assignPointerIds(const RawState& last, RawState& current) current.rawPointerData.markIdBit(id, current.rawPointerData.isHovering(currentPointerIndex)); - if (DEBUG_POINTER_ASSIGNMENT) { - ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, - id); - } + ALOGD_IF(DEBUG_POINTER_ASSIGNMENT, + "assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, + id); } } @@ -4028,10 +3993,11 @@ int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode return AKEY_STATE_UNKNOWN; } -bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { +bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, + const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { for (const VirtualKey& virtualKey : mVirtualKeys) { - for (size_t i = 0; i < numCodes; i++) { + for (size_t i = 0; i < keyCodes.size(); i++) { if (virtualKey.keyCode == keyCodes[i]) { outFlags[i] = 1; } diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index c948f565d9..31806e12e3 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H -#define _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H +#pragma once #include <stdint.h> @@ -147,7 +146,7 @@ public: int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override; int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override; - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) override; void cancelTouch(nsecs_t when, nsecs_t readTime) override; @@ -197,7 +196,6 @@ protected: struct Parameters { enum class DeviceType { TOUCH_SCREEN, - TOUCH_PAD, TOUCH_NAVIGATION, POINTER, @@ -248,12 +246,9 @@ protected: SizeCalibration sizeCalibration; - bool haveSizeScale; - float sizeScale; - bool haveSizeBias; - float sizeBias; - bool haveSizeIsSummed; - bool sizeIsSummed; + std::optional<float> sizeScale; + std::optional<float> sizeBias; + std::optional<bool> sizeIsSummed; // Pressure enum class PressureCalibration { @@ -264,8 +259,7 @@ protected: }; PressureCalibration pressureCalibration; - bool havePressureScale; - float pressureScale; + std::optional<float> pressureScale; // Orientation enum class OrientationCalibration { @@ -285,8 +279,7 @@ protected: }; DistanceCalibration distanceCalibration; - bool haveDistanceScale; - float distanceScale; + std::optional<float> distanceScale; enum class CoverageCalibration { DEFAULT, @@ -296,15 +289,15 @@ protected: CoverageCalibration coverageCalibration; - inline void applySizeScaleAndBias(float* outSize) const { - if (haveSizeScale) { - *outSize *= sizeScale; + inline void applySizeScaleAndBias(float& outSize) const { + if (sizeScale) { + outSize *= *sizeScale; } - if (haveSizeBias) { - *outSize += sizeBias; + if (sizeBias) { + outSize += *sizeBias; } - if (*outSize < 0) { - *outSize = 0; + if (outSize < 0) { + outSize = 0; } } } mCalibration; @@ -475,35 +468,29 @@ private: InputDeviceInfo::MotionRange y; InputDeviceInfo::MotionRange pressure; - bool haveSize; - InputDeviceInfo::MotionRange size; + std::optional<InputDeviceInfo::MotionRange> size; - bool haveTouchSize; - InputDeviceInfo::MotionRange touchMajor; - InputDeviceInfo::MotionRange touchMinor; + std::optional<InputDeviceInfo::MotionRange> touchMajor; + std::optional<InputDeviceInfo::MotionRange> touchMinor; - bool haveToolSize; - InputDeviceInfo::MotionRange toolMajor; - InputDeviceInfo::MotionRange toolMinor; + std::optional<InputDeviceInfo::MotionRange> toolMajor; + std::optional<InputDeviceInfo::MotionRange> toolMinor; - bool haveOrientation; - InputDeviceInfo::MotionRange orientation; + std::optional<InputDeviceInfo::MotionRange> orientation; - bool haveDistance; - InputDeviceInfo::MotionRange distance; + std::optional<InputDeviceInfo::MotionRange> distance; - bool haveTilt; - InputDeviceInfo::MotionRange tilt; - - OrientedRanges() { clear(); } + std::optional<InputDeviceInfo::MotionRange> tilt; void clear() { - haveSize = false; - haveTouchSize = false; - haveToolSize = false; - haveOrientation = false; - haveDistance = false; - haveTilt = false; + size = std::nullopt; + touchMajor = std::nullopt; + touchMinor = std::nullopt; + toolMajor = std::nullopt; + toolMinor = std::nullopt; + orientation = std::nullopt; + distance = std::nullopt; + tilt = std::nullopt; } } mOrientedRanges; @@ -527,7 +514,9 @@ private: float mPointerXZoomScale; float mPointerYZoomScale; - // The maximum swipe width. + // The maximum swipe width between pointers to detect a swipe gesture + // in the number of pixels.Touches that are wider than this are translated + // into freeform gestures. float mPointerGestureMaxSwipeWidth; struct PointerDistanceHeapElement { @@ -764,6 +753,10 @@ private: bool preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout); + // Moves the on-screen mouse pointer based on the movement of the pointer of the given ID + // between the last and current events. Uses a relative motion. + void moveMousePointerFromPointerDelta(nsecs_t when, uint32_t pointerId); + void dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags); void abortPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags); @@ -786,7 +779,8 @@ private: int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); + int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime, + MotionClassification classification); // Updates pointer coords and properties for pointers with specified ids that have moved. // Returns true if any of them changed. @@ -811,5 +805,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h index d3c22b60a8..894c5739e4 100644 --- a/services/inputflinger/reader/mapper/VibratorInputMapper.h +++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H -#define _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H +#pragma once #include "InputMapper.h" @@ -50,5 +49,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h index 9e159064fa..ed4c789cfd 100644 --- a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H -#define _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H +#pragma once #include <stdint.h> @@ -48,5 +47,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h index 16495599d7..ae1b7a32f4 100644 --- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H -#define _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H +#pragma once #include <stdint.h> @@ -56,5 +55,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h index 4c011f16a7..93056f06e6 100644 --- a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H -#define _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H +#pragma once #include <stdint.h> @@ -53,5 +52,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h index 22ebb720d5..7b889be238 100644 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H -#define _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H +#pragma once #include <stdint.h> @@ -62,5 +61,3 @@ private: }; } // namespace android - -#endif // _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reporter/InputReporter.cpp b/services/inputflinger/reporter/InputReporter.cpp index b591d3f909..6f1eef653c 100644 --- a/services/inputflinger/reporter/InputReporter.cpp +++ b/services/inputflinger/reporter/InputReporter.cpp @@ -35,7 +35,7 @@ void InputReporter::reportDroppedKey(uint32_t sequenceNum) { } sp<InputReporterInterface> createInputReporter() { - return new InputReporter(); + return sp<InputReporter>::make(); } } // namespace android diff --git a/services/inputflinger/reporter/InputReporterInterface.h b/services/inputflinger/reporter/InputReporterInterface.h index e5d360609f..72a4aeb13b 100644 --- a/services/inputflinger/reporter/InputReporterInterface.h +++ b/services/inputflinger/reporter/InputReporterInterface.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_INPUT_REPORTER_INTERFACE_H -#define _UI_INPUT_REPORTER_INTERFACE_H +#pragma once #include <utils/RefBase.h> @@ -49,5 +48,3 @@ public: sp<InputReporterInterface> createInputReporter(); } // namespace android - -#endif // _UI_INPUT_REPORTER_INTERFACE_H diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 75cd9da782..76500c577d 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -41,8 +41,8 @@ cc_test { "EventHub_test.cpp", "FocusResolver_test.cpp", "IInputFlingerQuery.aidl", - "InputClassifier_test.cpp", - "InputClassifierConverter_test.cpp", + "InputProcessor_test.cpp", + "InputProcessorConverter_test.cpp", "InputDispatcher_test.cpp", "InputReader_test.cpp", "InputFlingerService_test.cpp", diff --git a/services/inputflinger/tests/AnrTracker_test.cpp b/services/inputflinger/tests/AnrTracker_test.cpp index b561da107d..f8be48af25 100644 --- a/services/inputflinger/tests/AnrTracker_test.cpp +++ b/services/inputflinger/tests/AnrTracker_test.cpp @@ -40,8 +40,8 @@ TEST(AnrTrackerTest, SingleEntry_First) { TEST(AnrTrackerTest, MultipleEntries_RemoveToken) { AnrTracker tracker; - sp<IBinder> token1 = new BBinder(); - sp<IBinder> token2 = new BBinder(); + sp<IBinder> token1 = sp<BBinder>::make(); + sp<IBinder> token2 = sp<BBinder>::make(); tracker.insert(1, token1); tracker.insert(2, token2); @@ -90,8 +90,8 @@ TEST(AnrTrackerTest, SingleToken_MaintainsOrder) { TEST(AnrTrackerTest, MultipleTokens_MaintainsOrder) { AnrTracker tracker; - sp<IBinder> token1 = new BBinder(); - sp<IBinder> token2 = new BBinder(); + sp<IBinder> token1 = sp<BBinder>::make(); + sp<IBinder> token2 = sp<BBinder>::make(); tracker.insert(2, token1); tracker.insert(5, token2); @@ -104,8 +104,8 @@ TEST(AnrTrackerTest, MultipleTokens_MaintainsOrder) { TEST(AnrTrackerTest, MultipleTokens_IdenticalTimes) { AnrTracker tracker; - sp<IBinder> token1 = new BBinder(); - sp<IBinder> token2 = new BBinder(); + sp<IBinder> token1 = sp<BBinder>::make(); + sp<IBinder> token2 = sp<BBinder>::make(); tracker.insert(2, token1); tracker.insert(2, token2); @@ -119,8 +119,8 @@ TEST(AnrTrackerTest, MultipleTokens_IdenticalTimes) { TEST(AnrTrackerTest, MultipleTokens_IdenticalTimesRemove) { AnrTracker tracker; - sp<IBinder> token1 = new BBinder(); - sp<IBinder> token2 = new BBinder(); + sp<IBinder> token1 = sp<BBinder>::make(); + sp<IBinder> token2 = sp<BBinder>::make(); tracker.insert(2, token1); tracker.insert(2, token2); @@ -152,12 +152,12 @@ TEST(AnrTrackerTest, RemoveInvalidItem_DoesntCrash) { ASSERT_EQ(nullptr, tracker.firstToken()); // Remove with non-matching token - tracker.erase(1, new BBinder()); + tracker.erase(1, sp<BBinder>::make()); ASSERT_EQ(1, tracker.firstTimeout()); ASSERT_EQ(nullptr, tracker.firstToken()); // Remove with both non-matching - tracker.erase(2, new BBinder()); + tracker.erase(2, sp<BBinder>::make()); ASSERT_EQ(1, tracker.firstTimeout()); ASSERT_EQ(nullptr, tracker.firstToken()); } diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp index 6ef6e4498c..9380c7142f 100644 --- a/services/inputflinger/tests/EventHub_test.cpp +++ b/services/inputflinger/tests/EventHub_test.cpp @@ -99,8 +99,6 @@ protected: }; std::vector<RawEvent> EventHubTest::getEvents(std::optional<size_t> expectedEvents) { - static constexpr size_t EVENT_BUFFER_SIZE = 256; - std::array<RawEvent, EVENT_BUFFER_SIZE> eventBuffer; std::vector<RawEvent> events; while (true) { @@ -108,12 +106,12 @@ std::vector<RawEvent> EventHubTest::getEvents(std::optional<size_t> expectedEven if (expectedEvents) { timeout = 2s; } - const size_t count = - mEventHub->getEvents(timeout.count(), eventBuffer.data(), eventBuffer.size()); - if (count == 0) { + + std::vector<RawEvent> newEvents = mEventHub->getEvents(timeout.count()); + if (newEvents.empty()) { break; } - events.insert(events.end(), eventBuffer.begin(), eventBuffer.begin() + count); + events.insert(events.end(), newEvents.begin(), newEvents.end()); if (expectedEvents && events.size() >= *expectedEvents) { break; } diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp index 91be4a30bf..5d5cf9c108 100644 --- a/services/inputflinger/tests/FocusResolver_test.cpp +++ b/services/inputflinger/tests/FocusResolver_test.cpp @@ -50,16 +50,16 @@ public: }; TEST(FocusResolverTest, SetFocusedWindow) { - sp<IBinder> focusableWindowToken = new BBinder(); - sp<IBinder> invisibleWindowToken = new BBinder(); - sp<IBinder> unfocusableWindowToken = new BBinder(); + sp<IBinder> focusableWindowToken = sp<BBinder>::make(); + sp<IBinder> invisibleWindowToken = sp<BBinder>::make(); + sp<IBinder> unfocusableWindowToken = sp<BBinder>::make(); std::vector<sp<WindowInfoHandle>> windows; - windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */, - true /* visible */)); - windows.push_back(new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */, - false /* visible */)); - windows.push_back(new FakeWindowHandle("unfocusable", unfocusableWindowToken, - false /* focusable */, true /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, + true /* focusable */, true /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken, + true /* focusable */, false /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("unfocusable", unfocusableWindowToken, + false /* focusable */, true /* visible */)); // focusable window can get focused FocusRequest request; @@ -85,10 +85,10 @@ TEST(FocusResolverTest, SetFocusedWindow) { } TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) { - sp<IBinder> focusableWindowToken = new BBinder(); + sp<IBinder> focusableWindowToken = sp<BBinder>::make(); std::vector<sp<WindowInfoHandle>> windows; - windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */, - true /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, + true /* focusable */, true /* visible */)); FocusRequest request; request.displayId = 42; @@ -109,24 +109,24 @@ TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) { } TEST(FocusResolverTest, SetFocusedMirroredWindow) { - sp<IBinder> focusableWindowToken = new BBinder(); - sp<IBinder> invisibleWindowToken = new BBinder(); - sp<IBinder> unfocusableWindowToken = new BBinder(); + sp<IBinder> focusableWindowToken = sp<BBinder>::make(); + sp<IBinder> invisibleWindowToken = sp<BBinder>::make(); + sp<IBinder> unfocusableWindowToken = sp<BBinder>::make(); std::vector<sp<WindowInfoHandle>> windows; - windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */, - true /* visible */)); - windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */, - true /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken, + true /* focusable */, true /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken, + true /* focusable */, true /* visible */)); - windows.push_back(new FakeWindowHandle("Mirror2Visible", invisibleWindowToken, - true /* focusable */, true /* visible */)); - windows.push_back(new FakeWindowHandle("Mirror2Invisible", invisibleWindowToken, - true /* focusable */, false /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Mirror2Visible", invisibleWindowToken, + true /* focusable */, true /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Mirror2Invisible", invisibleWindowToken, + true /* focusable */, false /* visible */)); - windows.push_back(new FakeWindowHandle("Mirror3Focusable", unfocusableWindowToken, - true /* focusable */, true /* visible */)); - windows.push_back(new FakeWindowHandle("Mirror3Unfocusable", unfocusableWindowToken, - false /* focusable */, true /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Mirror3Focusable", unfocusableWindowToken, + true /* focusable */, true /* visible */)); + windows.push_back(sp<FakeWindowHandle>::make("Mirror3Unfocusable", unfocusableWindowToken, + false /* focusable */, true /* visible */)); // mirrored window can get focused FocusRequest request; @@ -149,10 +149,11 @@ TEST(FocusResolverTest, SetFocusedMirroredWindow) { } TEST(FocusResolverTest, SetInputWindows) { - sp<IBinder> focusableWindowToken = new BBinder(); + sp<IBinder> focusableWindowToken = sp<BBinder>::make(); std::vector<sp<WindowInfoHandle>> windows; - sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken, - true /* focusable */, true /* visible */); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, true /* focusable */, + true /* visible */); windows.push_back(window); // focusable window can get focused @@ -171,12 +172,12 @@ TEST(FocusResolverTest, SetInputWindows) { } TEST(FocusResolverTest, FocusRequestsCanBePending) { - sp<IBinder> invisibleWindowToken = new BBinder(); + sp<IBinder> invisibleWindowToken = sp<BBinder>::make(); std::vector<sp<WindowInfoHandle>> windows; sp<FakeWindowHandle> invisibleWindow = - new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */, - false /* visible */); + sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken, true /* focusable */, + false /* visible */); windows.push_back(invisibleWindow); // invisible window cannot get focused @@ -195,11 +196,12 @@ TEST(FocusResolverTest, FocusRequestsCanBePending) { } TEST(FocusResolverTest, FocusRequestsArePersistent) { - sp<IBinder> windowToken = new BBinder(); + sp<IBinder> windowToken = sp<BBinder>::make(); std::vector<sp<WindowInfoHandle>> windows; - sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken, - false /* focusable */, true /* visible */); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make("Test Window", windowToken, false /* focusable */, + true /* visible */); windows.push_back(window); // non-focusable window cannot get focused @@ -236,17 +238,17 @@ TEST(FocusResolverTest, FocusRequestsArePersistent) { } TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) { - sp<IBinder> hostWindowToken = new BBinder(); + sp<IBinder> hostWindowToken = sp<BBinder>::make(); std::vector<sp<WindowInfoHandle>> windows; sp<FakeWindowHandle> hostWindow = - new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */, - true /* visible */); + sp<FakeWindowHandle>::make("Host Window", hostWindowToken, true /* focusable */, + true /* visible */); windows.push_back(hostWindow); - sp<IBinder> embeddedWindowToken = new BBinder(); + sp<IBinder> embeddedWindowToken = sp<BBinder>::make(); sp<FakeWindowHandle> embeddedWindow = - new FakeWindowHandle("Embedded Window", embeddedWindowToken, true /* focusable */, - true /* visible */); + sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, true /* focusable */, + true /* visible */); windows.push_back(embeddedWindow); FocusRequest request; @@ -287,11 +289,12 @@ TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) { ASSERT_FALSE(changes); } TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) { - sp<IBinder> windowToken = new BBinder(); + sp<IBinder> windowToken = sp<BBinder>::make(); std::vector<sp<WindowInfoHandle>> windows; - sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken, - true /* focusable */, true /* visible */); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make("Test Window", windowToken, true /* focusable */, + true /* visible */); windows.push_back(window); FocusRequest request; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index df1a230002..985c9c570c 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -58,13 +58,19 @@ static constexpr int32_t POINTER_1_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_2_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr int32_t POINTER_3_DOWN = + AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_1_UP = AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); -// The default pid and uid for windows created by the test. +// The default pid and uid for windows created on the primary display by the test. static constexpr int32_t WINDOW_PID = 999; static constexpr int32_t WINDOW_UID = 1001; +// The default pid and uid for the windows created on the secondary display by the test. +static constexpr int32_t SECONDARY_WINDOW_PID = 1010; +static constexpr int32_t SECONDARY_WINDOW_UID = 1012; + // The default policy flags to use for event injection by tests. static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER; @@ -412,7 +418,6 @@ private: void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {} - void notifyUntrustedTouch(const std::string& obscuringPackage) override {} void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy, nsecs_t timestamp, const std::vector<float>& values) override {} @@ -509,7 +514,7 @@ protected: std::unique_ptr<InputDispatcher> mDispatcher; void SetUp() override { - mFakePolicy = new FakeInputDispatcherPolicy(); + mFakePolicy = sp<FakeInputDispatcherPolicy>::make(); mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy, STALE_EVENT_TIMEOUT); mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); // Start InputDispatcher thread @@ -746,7 +751,7 @@ class FakeApplicationHandle : public InputApplicationHandle { public: FakeApplicationHandle() { mInfo.name = "Fake Application"; - mInfo.token = new BBinder(); + mInfo.token = sp<BBinder>::make(); mInfo.dispatchingTimeoutMillis = std::chrono::duration_cast<std::chrono::milliseconds>(DISPATCHING_TIMEOUT).count(); } @@ -1022,8 +1027,8 @@ public: const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle, const std::unique_ptr<InputDispatcher>& dispatcher, int32_t displayId) { sp<FakeWindowHandle> handle = - new FakeWindowHandle(inputApplicationHandle, dispatcher, mInfo.name + "(Mirror)", - displayId, mInfo.token); + sp<FakeWindowHandle>::make(inputApplicationHandle, dispatcher, + mInfo.name + "(Mirror)", displayId, mInfo.token); return handle; } @@ -1557,8 +1562,8 @@ static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs( TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Window that breaks its input channel", - ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, + "Window that breaks its input channel", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1569,8 +1574,8 @@ TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) { TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1583,8 +1588,8 @@ TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); // Inject a MotionEvent to an unknown display. @@ -1603,8 +1608,8 @@ TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay */ TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1622,8 +1627,8 @@ TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { */ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1641,9 +1646,9 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> windowTop = - new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> windowSecond = - new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1665,10 +1670,10 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> foregroundWindow = - new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); foregroundWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> wallpaperWindow = - new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1709,10 +1714,10 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> foregroundWindow = - new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); foregroundWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> wallpaperWindow = - new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1753,11 +1758,11 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); window->setDupTouchToWallpaper(true); sp<FakeWindowHandle> wallpaperWindow = - new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1808,17 +1813,17 @@ TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> leftWindow = - new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 200, 200)); leftWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> rightWindow = - new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); rightWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> wallpaperWindow = - new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = @@ -1895,7 +1900,7 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Window", DISPLAY_ID); + sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID); mDispatcher->setInputWindows({{DISPLAY_ID, {window}}}); NotifyMotionArgs args; @@ -1919,11 +1924,11 @@ TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) { TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window1 = - new FakeWindowHandle(application, mDispatcher, "Window1", DISPLAY_ID); + sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID); window1->setTouchableRegion(Region{{0, 0, 100, 100}}); window1->setTouchable(false); sp<FakeWindowHandle> window2 = - new FakeWindowHandle(application, mDispatcher, "Window2", DISPLAY_ID); + sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID); window2->setTouchableRegion(Region{{100, 0, 200, 100}}); mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}}); @@ -1942,13 +1947,84 @@ TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) { window2->consumeMotionDown(); } +/** + * When splitting touch events the downTime should be adjusted such that the downTime corresponds + * to the event time of the first ACTION_DOWN sent to the particular window. + */ +TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window1 = + sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID); + window1->setTouchableRegion(Region{{0, 0, 100, 100}}); + sp<FakeWindowHandle> window2 = + sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID); + window2->setTouchableRegion(Region{{100, 0, 200, 100}}); + + mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}}); + + NotifyMotionArgs args; + // Touch down on the first window + mDispatcher->notifyMotion(&(args = generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}))); + + mDispatcher->waitForIdle(); + InputEvent* inputEvent1 = window1->consume(); + window2->assertNoEvents(); + MotionEvent& motionEvent1 = static_cast<MotionEvent&>(*inputEvent1); + nsecs_t downTimeForWindow1 = motionEvent1.getDownTime(); + ASSERT_EQ(motionEvent1.getDownTime(), motionEvent1.getEventTime()); + + // Now touch down on the window with another pointer + mDispatcher->notifyMotion(&(args = generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent2 = window2->consume(); + MotionEvent& motionEvent2 = static_cast<MotionEvent&>(*inputEvent2); + nsecs_t downTimeForWindow2 = motionEvent2.getDownTime(); + ASSERT_NE(downTimeForWindow1, downTimeForWindow2); + ASSERT_EQ(motionEvent2.getDownTime(), motionEvent2.getEventTime()); + + // Now move the pointer on the second window + mDispatcher->notifyMotion( + &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent3 = window2->consume(); + MotionEvent& motionEvent3 = static_cast<MotionEvent&>(*inputEvent3); + ASSERT_EQ(motionEvent3.getDownTime(), downTimeForWindow2); + + // Now add new touch down on the second window + mDispatcher->notifyMotion( + &(args = generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent4 = window2->consume(); + MotionEvent& motionEvent4 = static_cast<MotionEvent&>(*inputEvent4); + ASSERT_EQ(motionEvent4.getDownTime(), downTimeForWindow2); + + // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line + window1->consumeMotionMove(); + window1->assertNoEvents(); + + // Now move the pointer on the first window + mDispatcher->notifyMotion( + &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent5 = window1->consume(); + MotionEvent& motionEvent5 = static_cast<MotionEvent&>(*inputEvent5); + ASSERT_EQ(motionEvent5.getDownTime(), downTimeForWindow1); + + mDispatcher->notifyMotion(&( + args = generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent6 = window1->consume(); + MotionEvent& motionEvent6 = static_cast<MotionEvent&>(*inputEvent6); + ASSERT_EQ(motionEvent6.getDownTime(), downTimeForWindow1); +} + TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> windowLeft = - new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); sp<FakeWindowHandle> windowRight = - new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2054,7 +2130,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 1200, 800)); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2135,10 +2211,10 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> windowLeft = - new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); sp<FakeWindowHandle> windowRight = - new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2156,8 +2232,8 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -2181,8 +2257,8 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) { TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -2204,8 +2280,8 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { TEST_F(InputDispatcherTest, InterceptKeyByPolicy) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -2226,8 +2302,8 @@ TEST_F(InputDispatcherTest, InterceptKeyByPolicy) { TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -2254,15 +2330,17 @@ TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) { TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) { // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH. std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "First Window", ADISPLAY_ID_DEFAULT); window->setWatchOutsideTouch(true); window->setFrame(Rect{0, 0, 100, 100}); sp<FakeWindowHandle> secondWindow = - new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect{100, 100, 200, 200}); sp<FakeWindowHandle> thirdWindow = - new FakeWindowHandle(application, mDispatcher, "Third Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window", + ADISPLAY_ID_DEFAULT); thirdWindow->setFrame(Rect{200, 200, 300, 300}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}}); @@ -2295,8 +2373,8 @@ TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) { TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->onWindowInfosChanged({*window->getInfo()}, {}); @@ -2364,13 +2442,14 @@ public: // Add two windows to the display. Their frames are represented in the display space. sp<FakeWindowHandle> firstWindow = - new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", + ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform); addWindow(firstWindow); sp<FakeWindowHandle> secondWindow = - new FakeWindowHandle(application, mDispatcher, "Second Window", - ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform); addWindow(secondWindow); return {std::move(firstWindow), std::move(secondWindow)}; @@ -2471,9 +2550,11 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { // Create a couple of windows sp<FakeWindowHandle> firstWindow = - new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", + ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> secondWindow = - new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2522,13 +2603,13 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) { // Create a couple of windows + a spy window sp<FakeWindowHandle> spyWindow = - new FakeWindowHandle(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); spyWindow->setTrustedOverlay(true); spyWindow->setSpy(true); sp<FakeWindowHandle> firstWindow = - new FakeWindowHandle(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> secondWindow = - new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, firstWindow, secondWindow}}}); @@ -2569,10 +2650,12 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { // Create a couple of windows sp<FakeWindowHandle> firstWindow = - new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", + ADISPLAY_ID_DEFAULT); firstWindow->setPreventSplitting(true); sp<FakeWindowHandle> secondWindow = - new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); secondWindow->setPreventSplitting(true); // Add the windows to the dispatcher @@ -2644,11 +2727,13 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> firstWindow = - new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", + ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); sp<FakeWindowHandle> secondWindow = - new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); // Add the windows to the dispatcher @@ -2708,11 +2793,13 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> firstWindow = - new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", + ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); sp<FakeWindowHandle> secondWindow = - new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); // Add the windows to the dispatcher @@ -2773,10 +2860,10 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> firstWindowInPrimary = - new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); sp<FakeWindowHandle> secondWindowInPrimary = - new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); sp<FakeWindowHandle> mirrorWindowInPrimary = @@ -2832,10 +2919,10 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> firstWindowInPrimary = - new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); sp<FakeWindowHandle> secondWindowInPrimary = - new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); sp<FakeWindowHandle> mirrorWindowInPrimary = @@ -2887,8 +2974,8 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -2905,8 +2992,8 @@ TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -2920,8 +3007,8 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) // If a window is touchable, but does not have focus, it should receive motion events, but not keys TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -2943,11 +3030,13 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> firstWindow = - new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", + ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); sp<FakeWindowHandle> secondWindow = - new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); // Add the windows to the dispatcher @@ -2998,7 +3087,7 @@ TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline; graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2; @@ -3088,7 +3177,7 @@ using InputDispatcherMonitorTest = InputDispatcherTest; TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); @@ -3128,8 +3217,8 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); @@ -3145,8 +3234,8 @@ TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -3170,8 +3259,8 @@ TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { TEST_F(InputDispatcherMonitorTest, NoWindowTransform) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->setWindowOffset(20, 40); window->setWindowTransform(0, 1, -1, 0); @@ -3199,8 +3288,8 @@ TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) { TEST_F(InputDispatcherTest, TestMoveEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -3230,8 +3319,8 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { */ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Test window", ADISPLAY_ID_DEFAULT); const WindowInfo& windowInfo = *window->getInfo(); // Set focused application. @@ -3250,7 +3339,7 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { SCOPED_TRACE("Disable touch mode"); mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid, - /* hasPermission */ true); + true /*hasPermission*/, ADISPLAY_ID_DEFAULT); window->consumeTouchModeEvent(false); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -3264,7 +3353,7 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { SCOPED_TRACE("Enable touch mode again"); mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid, - /* hasPermission */ true); + true /*hasPermission*/, ADISPLAY_ID_DEFAULT); window->consumeTouchModeEvent(true); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -3276,8 +3365,8 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Test window", ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); @@ -3315,8 +3404,8 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Test window", ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -3420,9 +3509,9 @@ TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) { TEST_F(InputDispatcherTest, SetFocusedWindow) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> windowTop = - new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> windowSecond = - new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); // Top window is also focusable but is not granted focus. @@ -3443,7 +3532,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow) { TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); @@ -3463,7 +3552,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) { TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); window->setFocusable(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -3481,9 +3570,9 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> windowTop = - new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> windowSecond = - new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); windowTop->setFocusable(true); @@ -3506,9 +3595,9 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) { TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestFocusTokenNotFocused) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> windowTop = - new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> windowSecond = - new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); windowTop->setFocusable(true); @@ -3527,10 +3616,10 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestFocusTokenNotFocused) { TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> previousFocusedWindow = - new FakeWindowHandle(application, mDispatcher, "previousFocusedWindow", - ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow", + ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); @@ -3565,7 +3654,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) { TEST_F(InputDispatcherTest, DisplayRemoved) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); // window is granted focus. @@ -3610,7 +3699,7 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); sp<FakeWindowHandle> slipperyExitWindow = - new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); slipperyExitWindow->setSlippery(true); // Make sure this one overlaps the bottom window slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); @@ -3619,7 +3708,7 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID); sp<FakeWindowHandle> slipperyEnterWindow = - new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); slipperyExitWindow->setFrame(Rect(0, 0, 100, 100)); mDispatcher->setInputWindows( @@ -3653,7 +3742,7 @@ protected: sp<FakeWindowHandle> mWindow; virtual void SetUp() override { - mFakePolicy = new FakeInputDispatcherPolicy(); + mFakePolicy = sp<FakeInputDispatcherPolicy>::make(); mFakePolicy->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY); mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy); mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); @@ -3664,7 +3753,7 @@ protected: void setUpWindow() { mApp = std::make_shared<FakeApplicationHandle>(); - mWindow = new FakeWindowHandle(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); mWindow->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); @@ -3801,7 +3890,7 @@ public: application1 = std::make_shared<FakeApplicationHandle>(); windowInPrimary = - new FakeWindowHandle(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT); // Set focus window for primary display, but focused display would be second one. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1); @@ -3812,7 +3901,7 @@ public: application2 = std::make_shared<FakeApplicationHandle>(); windowInSecondary = - new FakeWindowHandle(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID); + sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID); // Set focus to second display window. // Set focus display to second one. mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID); @@ -3941,7 +4030,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) { TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) { sp<FakeWindowHandle> secondWindowInPrimary = - new FakeWindowHandle(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary, secondWindowInPrimary}}}); setFocusedWindow(secondWindowInPrimary); @@ -4110,8 +4199,8 @@ protected: std::shared_ptr<InputApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - mWindow = - new FakeWindowHandle(application, mDispatcher, "Test Window", ADISPLAY_ID_DEFAULT); + mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window", + ADISPLAY_ID_DEFAULT); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mWindow->setFocusable(true); @@ -4215,11 +4304,11 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); mUnfocusedWindow = - new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); mFocusedWindow = - new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); // Set focused application. @@ -4325,12 +4414,12 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1", - ADISPLAY_ID_DEFAULT); + mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1", + ADISPLAY_ID_DEFAULT); mWindow1->setFrame(Rect(0, 0, 100, 100)); - mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2", - ADISPLAY_ID_DEFAULT, mWindow1->getToken()); + mWindow2 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 2", + ADISPLAY_ID_DEFAULT, mWindow1->getToken()); mWindow2->setFrame(Rect(100, 100, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); @@ -4512,8 +4601,8 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { mApplication = std::make_shared<FakeApplicationHandle>(); mApplication->setDispatchingTimeout(20ms); - mWindow = - new FakeWindowHandle(mApplication, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow", + ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 30, 30)); mWindow->setDispatchingTimeout(30ms); mWindow->setFocusable(true); @@ -4547,7 +4636,7 @@ protected: sp<FakeWindowHandle> addSpyWindow() { sp<FakeWindowHandle> spy = - new FakeWindowHandle(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); spy->setTrustedOverlay(true); spy->setFocusable(false); spy->setSpy(true); @@ -4993,14 +5082,14 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { mApplication = std::make_shared<FakeApplicationHandle>(); mApplication->setDispatchingTimeout(10ms); - mUnfocusedWindow = - new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT); + mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused", + ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped mUnfocusedWindow->setWatchOutsideTouch(true); - mFocusedWindow = - new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); + mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused", + ADISPLAY_ID_DEFAULT); mFocusedWindow->setDispatchingTimeout(30ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); @@ -5367,16 +5456,16 @@ class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest { InputDispatcherTest::SetUp(); mApplication = std::make_shared<FakeApplicationHandle>(); - mNoInputWindow = new FakeWindowHandle(mApplication, mDispatcher, - "Window without input channel", ADISPLAY_ID_DEFAULT, - std::make_optional<sp<IBinder>>(nullptr) /*token*/); - + mNoInputWindow = + sp<FakeWindowHandle>::make(mApplication, mDispatcher, + "Window without input channel", ADISPLAY_ID_DEFAULT, + std::make_optional<sp<IBinder>>(nullptr) /*token*/); mNoInputWindow->setNoInputChannel(true); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); // It's perfectly valid for this window to not have an associated input channel - mBottomWindow = new FakeWindowHandle(mApplication, mDispatcher, "Bottom window", - ADISPLAY_ID_DEFAULT); + mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window", + ADISPLAY_ID_DEFAULT); mBottomWindow->setFrame(Rect(0, 0, 100, 100)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}}); @@ -5409,9 +5498,9 @@ TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouc */ TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouchesWithValidChannel) { - mNoInputWindow = new FakeWindowHandle(mApplication, mDispatcher, - "Window with input channel and NO_INPUT_CHANNEL", - ADISPLAY_ID_DEFAULT); + mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, + "Window with input channel and NO_INPUT_CHANNEL", + ADISPLAY_ID_DEFAULT); mNoInputWindow->setNoInputChannel(true); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); @@ -5437,9 +5526,9 @@ protected: virtual void SetUp() override { InputDispatcherTest::SetUp(); mApp = std::make_shared<FakeApplicationHandle>(); - mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); - mMirror = new FakeWindowHandle(mApp, mDispatcher, "TestWindowMirror", ADISPLAY_ID_DEFAULT, - mWindow->getToken()); + mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + mMirror = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindowMirror", + ADISPLAY_ID_DEFAULT, mWindow->getToken()); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mWindow->setFocusable(true); mMirror->setFocusable(true); @@ -5581,9 +5670,10 @@ protected: void SetUp() override { InputDispatcherTest::SetUp(); mApp = std::make_shared<FakeApplicationHandle>(); - mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFocusable(true); - mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); + mSecondWindow = + sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFocusable(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); @@ -5744,7 +5834,6 @@ protected: virtual void SetUp() override { InputDispatcherTest::SetUp(); mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched"); - mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK); mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY); } @@ -5765,7 +5854,7 @@ protected: sp<FakeWindowHandle> getWindow(int32_t uid, std::string name) { std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(app, mDispatcher, name, ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT); // Generate an arbitrary PID based on the UID window->setOwnerInfo(1777 + (uid % 10000), uid); return window; @@ -6125,20 +6214,28 @@ protected: sp<FakeWindowHandle> mWindow; sp<FakeWindowHandle> mSecondWindow; sp<FakeWindowHandle> mDragWindow; + sp<FakeWindowHandle> mSpyWindow; // Mouse would force no-split, set the id as non-zero to verify if drag state could track it. static constexpr int32_t MOUSE_POINTER_ID = 1; void SetUp() override { InputDispatcherTest::SetUp(); mApp = std::make_shared<FakeApplicationHandle>(); - mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 100, 100)); - mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); + mSecondWindow = + sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); + mSpyWindow = + sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT); + mSpyWindow->setSpy(true); + mSpyWindow->setTrustedOverlay(true); + mSpyWindow->setFrame(Rect(0, 0, 200, 100)); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mSpyWindow, mWindow, mSecondWindow}}}); } void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) { @@ -6179,6 +6276,8 @@ protected: // Window should receive motion event. mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); + // Spy window should also receive motion event + mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); } // Start performing drag, we will create a drag window and transfer touch to it. @@ -6190,9 +6289,11 @@ protected: } // The drag window covers the entire display - mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT); + mDragWindow = + sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT); + mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}}); mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}}); + {{ADISPLAY_ID_DEFAULT, {mDragWindow, mSpyWindow, mWindow, mSecondWindow}}}); // Transfer touch focus to the drag window bool transferred = @@ -6244,6 +6345,30 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { mSecondWindow->assertNoEvents(); } +TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) { + startDrag(); + + // No cancel event after drag start + mSpyWindow->assertNoEvents(); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(60).y(60)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Receives cancel for first pointer after next pointer down + mSpyWindow->consumeMotionCancel(); + mSpyWindow->consumeMotionDown(); + + mSpyWindow->assertNoEvents(); +} + TEST_F(InputDispatcherDragTests, DragAndDrop) { startDrag(); @@ -6450,7 +6575,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // Update window of second display. sp<FakeWindowHandle> windowInSecondary = - new FakeWindowHandle(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID); + sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID); mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}}); // Let second display has a touch state. @@ -6550,8 +6675,8 @@ class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {}; TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Test window", ADISPLAY_ID_DEFAULT); window->setDropInput(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); @@ -6589,14 +6714,14 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { std::shared_ptr<FakeApplicationHandle> obscuringApplication = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> obscuringWindow = - new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow", - ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow", + ADISPLAY_ID_DEFAULT); obscuringWindow->setFrame(Rect(0, 0, 50, 50)); obscuringWindow->setOwnerInfo(111, 111); obscuringWindow->setTouchable(false); std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Test window", ADISPLAY_ID_DEFAULT); window->setDropInputIfObscured(true); window->setOwnerInfo(222, 222); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -6635,14 +6760,14 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { std::shared_ptr<FakeApplicationHandle> obscuringApplication = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> obscuringWindow = - new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow", - ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow", + ADISPLAY_ID_DEFAULT); obscuringWindow->setFrame(Rect(0, 0, 50, 50)); obscuringWindow->setOwnerInfo(111, 111); obscuringWindow->setTouchable(false); std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Test window", ADISPLAY_ID_DEFAULT); window->setDropInputIfObscured(true); window->setOwnerInfo(222, 222); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -6679,42 +6804,67 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { class InputDispatcherTouchModeChangedTests : public InputDispatcherTest { protected: std::shared_ptr<FakeApplicationHandle> mApp; + std::shared_ptr<FakeApplicationHandle> mSecondaryApp; sp<FakeWindowHandle> mWindow; sp<FakeWindowHandle> mSecondWindow; + sp<FakeWindowHandle> mThirdWindow; void SetUp() override { InputDispatcherTest::SetUp(); mApp = std::make_shared<FakeApplicationHandle>(); - mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + mSecondaryApp = std::make_shared<FakeApplicationHandle>(); + mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFocusable(true); setFocusedWindow(mWindow); - mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); + mSecondWindow = + sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFocusable(true); + mThirdWindow = + sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher, + "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID); + mThirdWindow->setFocusable(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}, + {SECOND_DISPLAY_ID, {mThirdWindow}}}); + mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID); mWindow->consumeFocusEvent(true); - // Set initial touch mode to InputDispatcher::kDefaultInTouchMode. + // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode. if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID, - WINDOW_UID, /* hasPermission */ true)) { + WINDOW_UID, true /* hasPermission */, + ADISPLAY_ID_DEFAULT)) { mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); + mThirdWindow->assertNoEvents(); + } + + // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode. + if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID, + SECONDARY_WINDOW_UID, true /* hasPermission */, + SECOND_DISPLAY_ID)) { + mWindow->assertNoEvents(); + mSecondWindow->assertNoEvents(); + mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); } } - void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) { - ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission)); + void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, int32_t pid, int32_t uid, + bool hasPermission) { + ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission, + ADISPLAY_ID_DEFAULT)); mWindow->consumeTouchModeEvent(inTouchMode); mSecondWindow->consumeTouchModeEvent(inTouchMode); + mThirdWindow->assertNoEvents(); } }; TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) { const WindowInfo& windowInfo = *mWindow->getInfo(); - changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid, - windowInfo.ownerUid, /* hasPermission */ false); + changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, + windowInfo.ownerPid, windowInfo.ownerUid, + false /* hasPermission */); } TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) { @@ -6723,7 +6873,8 @@ TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTo int32_t ownerUid = windowInfo.ownerUid; mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1); ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid, - ownerUid, /* hasPermission */ false)); + ownerUid, false /*hasPermission*/, + ADISPLAY_ID_DEFAULT)); mWindow->assertNoEvents(); mSecondWindow->assertNoEvents(); } @@ -6733,19 +6884,29 @@ TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnP int32_t ownerPid = windowInfo.ownerPid; int32_t ownerUid = windowInfo.ownerUid; mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1); - changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid, - /* hasPermission */ true); + changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid, + ownerUid, true /*hasPermission*/); } TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) { const WindowInfo& windowInfo = *mWindow->getInfo(); ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid, windowInfo.ownerUid, - /* hasPermission */ true)); + true /*hasPermission*/, ADISPLAY_ID_DEFAULT)); mWindow->assertNoEvents(); mSecondWindow->assertNoEvents(); } +TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) { + const WindowInfo& windowInfo = *mThirdWindow->getInfo(); + ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode, + windowInfo.ownerPid, windowInfo.ownerUid, + true /*hasPermission*/, SECOND_DISPLAY_ID)); + mWindow->assertNoEvents(); + mSecondWindow->assertNoEvents(); + mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode); +} + TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) { // Interact with the window first. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) @@ -6760,7 +6921,7 @@ TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInt const WindowInfo& windowInfo = *mWindow->getInfo(); ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid, windowInfo.ownerUid, - /* hasPermission= */ false)); + false /*hasPermission*/, ADISPLAY_ID_DEFAULT)); } class InputDispatcherSpyWindowTest : public InputDispatcherTest { @@ -6770,8 +6931,8 @@ public: std::make_shared<FakeApplicationHandle>(); std::string name = "Fake Spy "; name += std::to_string(mSpyCount++); - sp<FakeWindowHandle> spy = - new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher, + name.c_str(), ADISPLAY_ID_DEFAULT); spy->setSpy(true); spy->setTrustedOverlay(true); return spy; @@ -6781,7 +6942,8 @@ public: std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window", + ADISPLAY_ID_DEFAULT); window->setFocusable(true); return window; } @@ -6949,10 +7111,146 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { } /** - * A spy window can pilfer pointers. When this happens, touch gestures that are currently sent to - * any other windows - including other spy windows - will also be cancelled. + * Even when a spy window spans over multiple foreground windows, the spy should receive all + * pointers that are down within its bounds. + */ +TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { + auto windowLeft = createForeground(); + windowLeft->setFrame({0, 0, 100, 200}); + auto windowRight = createForeground(); + windowRight->setFrame({100, 0, 200, 200}); + auto spy = createSpy(); + spy->setFrame({0, 0, 200, 200}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + windowLeft->consumeMotionDown(); + spy->consumeMotionDown(); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer( + PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + windowRight->consumeMotionDown(); + spy->consumeMotionPointerDown(1 /*pointerIndex*/); +} + +/** + * When the first pointer lands outside the spy window and the second pointer lands inside it, the + * the spy should receive the second pointer with ACTION_DOWN. */ -TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { +TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { + auto window = createForeground(); + window->setFrame({0, 0, 200, 200}); + auto spyRight = createSpy(); + spyRight->setFrame({100, 0, 200, 200}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + spyRight->assertNoEvents(); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer( + PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionPointerDown(1 /*pointerIndex*/); + spyRight->consumeMotionDown(); +} + +/** + * The spy window should not be able to affect whether or not touches are split. Only the foreground + * windows should be allowed to control split touch. + */ +TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { + // This spy window prevents touch splitting. However, we still expect to split touches + // because a foreground window has not disabled splitting. + auto spy = createSpy(); + spy->setPreventSplitting(true); + + auto window = createForeground(); + window->setFrame(Rect(0, 0, 100, 100)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // First finger down, no window touched. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); + + // Second finger down on window, the window should receive touch down. + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + spy->consumeMotionPointerDown(1 /* pointerIndex */); +} + +/** + * A spy window will usually be implemented as an un-focusable window. Verify that these windows + * do not receive key events. + */ +TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { + auto spy = createSpy(); + spy->setFocusable(false); + + auto window = createForeground(); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeKeyDown(ADISPLAY_ID_NONE); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeKeyUp(ADISPLAY_ID_NONE); + + spy->assertNoEvents(); +} + +using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest; + +/** + * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that + * are currently sent to any other windows - including other spy windows - will also be cancelled. + */ +TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { auto window = createForeground(); auto spy1 = createSpy(); auto spy2 = createSpy(); @@ -6985,7 +7283,7 @@ TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { * A spy window can pilfer pointers for a gesture even after the foreground window has been removed * in the middle of the gesture. */ -TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { +TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) { auto window = createForeground(); auto spy = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -7010,7 +7308,7 @@ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to * the spy, but not to any other windows. */ -TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { +TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) { auto spy = createSpy(); auto window = createForeground(); @@ -7066,136 +7364,154 @@ TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { } /** - * Even when a spy window spans over multiple foreground windows, the spy should receive all - * pointers that are down within its bounds. + * After a spy window pilfers pointers, only the pointers used by the spy should be canceled */ -TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { - auto windowLeft = createForeground(); - windowLeft->setFrame({0, 0, 100, 200}); - auto windowRight = createForeground(); - windowRight->setFrame({100, 0, 200, 200}); +TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { auto spy = createSpy(); - spy->setFrame({0, 0, 200, 200}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}}); + spy->setFrame(Rect(0, 0, 100, 100)); + auto window = createForeground(); + window->setFrame(Rect(0, 0, 200, 200)); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // First finger down on the window only ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {50, 50})) + {150, 150})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - windowLeft->consumeMotionDown(); - spy->consumeMotionDown(); + window->consumeMotionDown(); + // Second finger down on the spy and window const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer( - PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - windowRight->consumeMotionDown(); - spy->consumeMotionPointerDown(1 /*pointerIndex*/); + spy->consumeMotionDown(); + window->consumeMotionPointerDown(1); + + // Third finger down on the spy and window + const MotionEvent thirdFingerDownEvent = + MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .pointer(PointerBuilder(/* id */ 2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + spy->consumeMotionPointerDown(1); + window->consumeMotionPointerDown(2); + + // Spy window pilfers the pointers. + EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); + window->consumeMotionPointerUp(/* idx */ 2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); + window->consumeMotionPointerUp(/* idx */ 1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); + + spy->assertNoEvents(); + window->assertNoEvents(); } /** - * When the first pointer lands outside the spy window and the second pointer lands inside it, the - * the spy should receive the second pointer with ACTION_DOWN. + * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to + * other windows should be canceled. If this results in the cancellation of all pointers for some + * window, then that window should receive ACTION_CANCEL. */ -TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { +TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { + auto spy = createSpy(); + spy->setFrame(Rect(0, 0, 100, 100)); auto window = createForeground(); - window->setFrame({0, 0, 200, 200}); - auto spyRight = createSpy(); - spyRight->setFrame({100, 0, 200, 200}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}}); + window->setFrame(Rect(0, 0, 200, 200)); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // First finger down on both spy and window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {50, 50})) + {10, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); - spyRight->assertNoEvents(); + spy->consumeMotionDown(); + // Second finger down on the spy and window const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer( - PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionPointerDown(1 /*pointerIndex*/); - spyRight->consumeMotionDown(); + spy->consumeMotionPointerDown(1); + window->consumeMotionPointerDown(1); + + // Spy window pilfers the pointers. + EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); + window->consumeMotionCancel(); + + spy->assertNoEvents(); + window->assertNoEvents(); } /** - * The spy window should not be able to affect whether or not touches are split. Only the foreground - * windows should be allowed to control split touch. + * After a spy window pilfers pointers, new pointers that are not touching the spy window can still + * be sent to other windows */ -TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { - // This spy window prevents touch splitting. However, we still expect to split touches - // because a foreground window has not disabled splitting. +TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { auto spy = createSpy(); - spy->setPreventSplitting(true); - + spy->setFrame(Rect(0, 0, 100, 100)); auto window = createForeground(); - window->setFrame(Rect(0, 0, 100, 100)); + window->setFrame(Rect(0, 0, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); - // First finger down, no window touched. + // First finger down on both window and spy ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {100, 200})) + {10, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); - window->assertNoEvents(); + window->consumeMotionDown(); + spy->consumeMotionDown(); - // Second finger down on window, the window should receive touch down. + // Spy window pilfers the pointers. + EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); + window->consumeMotionCancel(); + + // Second finger down on the window only const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) - .x(100) - .y(200)) - .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + window->assertNoEvents(); - window->consumeMotionDown(ADISPLAY_ID_DEFAULT); - spy->consumeMotionPointerDown(1 /* pointerIndex */); -} - -/** - * A spy window will usually be implemented as an un-focusable window. Verify that these windows - * do not receive key events. - */ -TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { - auto spy = createSpy(); - spy->setFocusable(false); - - auto window = createForeground(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); - setFocusedWindow(window); - window->consumeFocusEvent(true); - - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeKeyDown(ADISPLAY_ID_NONE); - - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeKeyUp(ADISPLAY_ID_NONE); - + // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line + spy->consumeMotionMove(); spy->assertNoEvents(); } @@ -7205,8 +7521,8 @@ public: std::shared_ptr<FakeApplicationHandle> overlayApplication = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> overlay = - new FakeWindowHandle(overlayApplication, mDispatcher, "Stylus interceptor window", - ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(overlayApplication, mDispatcher, + "Stylus interceptor window", ADISPLAY_ID_DEFAULT); overlay->setFocusable(false); overlay->setOwnerInfo(111, 111); overlay->setTouchable(false); @@ -7216,8 +7532,8 @@ public: std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Application window", - ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle>::make(application, mDispatcher, "Application window", + ADISPLAY_ID_DEFAULT); window->setFocusable(true); window->setOwnerInfo(222, 222); @@ -7357,8 +7673,9 @@ struct User { sp<FakeWindowHandle> createWindow() const { std::shared_ptr<FakeApplicationHandle> overlayApplication = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = new FakeWindowHandle(overlayApplication, mDispatcher, - "Owned Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make(overlayApplication, mDispatcher, "Owned Window", + ADISPLAY_ID_DEFAULT); window->setOwnerInfo(mPid, mUid); return window; } diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp index 454e531af6..ca548bec3e 100644 --- a/services/inputflinger/tests/InputFlingerService_test.cpp +++ b/services/inputflinger/tests/InputFlingerService_test.cpp @@ -33,8 +33,6 @@ #include <inttypes.h> #include <linux/uinput.h> #include <log/log.h> -#include <ui/Rect.h> -#include <ui/Region.h> #include <chrono> #include <thread> #include <unordered_map> @@ -223,8 +221,10 @@ int main(int argc, char** argv) { if (forkPid == 0) { // Server process - android::sp<android::TestInputManager> manager = new android::TestInputManager(); - android::sp<android::TestInputQuery> query = new android::TestInputQuery(manager); + android::sp<android::TestInputManager> manager = + android::sp<android::TestInputManager>::make(); + android::sp<android::TestInputQuery> query = + android::sp<android::TestInputQuery>::make(manager); android::defaultServiceManager()->addService(android::kTestServiceName, manager, false /*allowIsolated*/); diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputProcessorConverter_test.cpp index 81ef9b95f0..040c8da309 100644 --- a/services/inputflinger/tests/InputClassifierConverter_test.cpp +++ b/services/inputflinger/tests/InputProcessorConverter_test.cpp @@ -24,7 +24,7 @@ using namespace aidl::android::hardware::input; namespace android { -// --- InputClassifierConverterTest --- +// --- InputProcessorConverterTest --- static NotifyMotionArgs generateBasicMotionArgs() { // Create a basic motion event for testing @@ -52,7 +52,7 @@ static NotifyMotionArgs generateBasicMotionArgs() { static float getMotionEventAxis(common::PointerCoords coords, common::Axis axis) { uint32_t index = BitSet64::getIndexOfBit(static_cast<uint64_t>(coords.bits), - static_cast<uint64_t>(axis)); + static_cast<uint64_t>(axis)); return coords.values[index]; } @@ -60,7 +60,7 @@ static float getMotionEventAxis(common::PointerCoords coords, common::Axis axis) * Check that coordinates get converted properly from the framework's PointerCoords * to the hidl PointerCoords in input::common. */ -TEST(InputClassifierConverterTest, PointerCoordsAxes) { +TEST(InputProcessorConverterTest, PointerCoordsAxes) { const NotifyMotionArgs motionArgs = generateBasicMotionArgs(); ASSERT_EQ(1, motionArgs.pointerCoords[0].getX()); ASSERT_EQ(2, motionArgs.pointerCoords[0].getY()); @@ -76,7 +76,7 @@ TEST(InputClassifierConverterTest, PointerCoordsAxes) { ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::SIZE), motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE)); ASSERT_EQ(BitSet64::count(motionArgs.pointerCoords[0].bits), - BitSet64::count(motionEvent.pointerCoords[0].bits)); + BitSet64::count(motionEvent.pointerCoords[0].bits)); } } // namespace android diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputProcessor_test.cpp index 3a7712727a..380001c83a 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputProcessor_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "../InputClassifier.h" +#include "../InputProcessor.h" #include <gtest/gtest.h> #include <gui/constants.h> @@ -31,7 +31,7 @@ using aidl::android::hardware::input::processor::IInputProcessor; namespace android { -// --- InputClassifierTest --- +// --- InputProcessorTest --- static NotifyMotionArgs generateBasicMotionArgs() { // Create a basic motion event for testing @@ -56,105 +56,104 @@ static NotifyMotionArgs generateBasicMotionArgs() { return motionArgs; } -class InputClassifierTest : public testing::Test { +class InputProcessorTest : public testing::Test { protected: TestInputListener mTestListener; - std::unique_ptr<InputClassifierInterface> mClassifier; + std::unique_ptr<InputProcessorInterface> mProcessor; - void SetUp() override { mClassifier = std::make_unique<InputClassifier>(mTestListener); } + void SetUp() override { mProcessor = std::make_unique<InputProcessor>(mTestListener); } }; /** - * Create a basic configuration change and send it to input classifier. + * Create a basic configuration change and send it to input processor. * Expect that the event is received by the next input stage, unmodified. */ -TEST_F(InputClassifierTest, SendToNextStage_NotifyConfigurationChangedArgs) { - // Create a basic configuration change and send to classifier - NotifyConfigurationChangedArgs args(1/*sequenceNum*/, 2/*eventTime*/); +TEST_F(InputProcessorTest, SendToNextStage_NotifyConfigurationChangedArgs) { + // Create a basic configuration change and send to processor + NotifyConfigurationChangedArgs args(1 /*sequenceNum*/, 2 /*eventTime*/); - mClassifier->notifyConfigurationChanged(&args); + mProcessor->notifyConfigurationChanged(&args); NotifyConfigurationChangedArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyConfigurationChangedWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); } -TEST_F(InputClassifierTest, SendToNextStage_NotifyKeyArgs) { - // Create a basic key event and send to classifier +TEST_F(InputProcessorTest, SendToNextStage_NotifyKeyArgs) { + // Create a basic key event and send to processor NotifyKeyArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 21 /*readTime*/, 3 /*deviceId*/, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, 0 /*policyFlags*/, AKEY_EVENT_ACTION_DOWN, 4 /*flags*/, AKEYCODE_HOME, 5 /*scanCode*/, AMETA_NONE, 6 /*downTime*/); - mClassifier->notifyKey(&args); + mProcessor->notifyKey(&args); NotifyKeyArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyKeyWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); } - /** - * Create a basic motion event and send it to input classifier. + * Create a basic motion event and send it to input processor. * Expect that the event is received by the next input stage, unmodified. */ -TEST_F(InputClassifierTest, SendToNextStage_NotifyMotionArgs) { +TEST_F(InputProcessorTest, SendToNextStage_NotifyMotionArgs) { NotifyMotionArgs motionArgs = generateBasicMotionArgs(); - mClassifier->notifyMotion(&motionArgs); + mProcessor->notifyMotion(&motionArgs); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyMotionWasCalled(&args)); ASSERT_EQ(motionArgs, args); } /** - * Create a basic switch event and send it to input classifier. + * Create a basic switch event and send it to input processor. * Expect that the event is received by the next input stage, unmodified. */ -TEST_F(InputClassifierTest, SendToNextStage_NotifySwitchArgs) { - NotifySwitchArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*policyFlags*/, 4/*switchValues*/, - 5/*switchMask*/); +TEST_F(InputProcessorTest, SendToNextStage_NotifySwitchArgs) { + NotifySwitchArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*policyFlags*/, 4 /*switchValues*/, + 5 /*switchMask*/); - mClassifier->notifySwitch(&args); + mProcessor->notifySwitch(&args); NotifySwitchArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifySwitchWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); } /** - * Create a basic device reset event and send it to input classifier. + * Create a basic device reset event and send it to input processor. * Expect that the event is received by the next input stage, unmodified. */ -TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) { - NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/); +TEST_F(InputProcessorTest, SendToNextStage_NotifyDeviceResetArgs) { + NotifyDeviceResetArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*deviceId*/); - mClassifier->notifyDeviceReset(&args); + mProcessor->notifyDeviceReset(&args); NotifyDeviceResetArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyDeviceResetWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); } -TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) { - mClassifier->setMotionClassifierEnabled(true); +TEST_F(InputProcessorTest, SetMotionClassifier_Enabled) { + mProcessor->setMotionClassifierEnabled(true); } -TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) { - mClassifier->setMotionClassifierEnabled(false); +TEST_F(InputProcessorTest, SetMotionClassifier_Disabled) { + mProcessor->setMotionClassifierEnabled(false); } /** * Try to break it by calling setMotionClassifierEnabled multiple times. */ -TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) { - mClassifier->setMotionClassifierEnabled(true); - mClassifier->setMotionClassifierEnabled(true); - mClassifier->setMotionClassifierEnabled(true); - mClassifier->setMotionClassifierEnabled(false); - mClassifier->setMotionClassifierEnabled(false); - mClassifier->setMotionClassifierEnabled(true); - mClassifier->setMotionClassifierEnabled(true); - mClassifier->setMotionClassifierEnabled(true); +TEST_F(InputProcessorTest, SetMotionClassifier_Multiple) { + mProcessor->setMotionClassifierEnabled(true); + mProcessor->setMotionClassifierEnabled(true); + mProcessor->setMotionClassifierEnabled(true); + mProcessor->setMotionClassifierEnabled(false); + mProcessor->setMotionClassifierEnabled(false); + mProcessor->setMotionClassifierEnabled(true); + mProcessor->setMotionClassifierEnabled(true); + mProcessor->setMotionClassifierEnabled(true); } /** - * A minimal implementation of IInputClassifier. + * A minimal implementation of IInputProcessor. */ class TestHal : public aidl::android::hardware::input::processor::BnInputProcessor { ::ndk::ScopedAStatus classify( @@ -212,7 +211,7 @@ TEST_F(MotionClassifierTest, Classify_OneVideoFrame) { NotifyMotionArgs motionArgs = generateBasicMotionArgs(); std::vector<int16_t> videoData = {1, 2, 3, 4}; - timeval timestamp = { 1, 1}; + timeval timestamp = {1, 1}; TouchVideoFrame frame(2, 2, std::move(videoData), timestamp); motionArgs.videoFrames = {frame}; @@ -228,11 +227,11 @@ TEST_F(MotionClassifierTest, Classify_TwoVideoFrames) { NotifyMotionArgs motionArgs = generateBasicMotionArgs(); std::vector<int16_t> videoData1 = {1, 2, 3, 4}; - timeval timestamp1 = { 1, 1}; + timeval timestamp1 = {1, 1}; TouchVideoFrame frame1(2, 2, std::move(videoData1), timestamp1); std::vector<int16_t> videoData2 = {6, 6, 6, 6}; - timeval timestamp2 = { 1, 2}; + timeval timestamp2 = {1, 2}; TouchVideoFrame frame2(2, 2, std::move(videoData2), timestamp2); motionArgs.videoFrames = {frame1, frame2}; @@ -253,7 +252,7 @@ TEST_F(MotionClassifierTest, Reset_DoesNotCrash) { * Make sure MotionClassifier does not crash when a device is reset. */ TEST_F(MotionClassifierTest, DeviceReset_DoesNotCrash) { - NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/); + NotifyDeviceResetArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*deviceId*/); ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args)); } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 575d950c9b..78ea692085 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -31,6 +31,7 @@ #include <SingleTouchInputMapper.h> #include <SwitchInputMapper.h> #include <TestInputListener.h> +#include <TestInputListenerMatchers.h> #include <TouchInputMapper.h> #include <UinputDevice.h> #include <VibratorInputMapper.h> @@ -38,13 +39,16 @@ #include <gtest/gtest.h> #include <gui/constants.h> +#include "android/hardware/input/InputDeviceCountryCode.h" #include "input/DisplayViewport.h" #include "input/Input.h" +using android::hardware::input::InputDeviceCountryCode; + namespace android { using namespace ftl::flag_operators; - +using testing::AllOf; using std::chrono_literals::operator""ms; // Timeout for waiting for an expected event @@ -77,6 +81,7 @@ static constexpr int32_t THIRD_TRACKING_ID = 2; static constexpr int32_t DEFAULT_BATTERY = 1; static constexpr int32_t BATTERY_STATUS = 4; static constexpr int32_t BATTERY_CAPACITY = 66; +static const std::string BATTERY_DEVPATH = "/sys/devices/mydevice/power_supply/mybattery"; static constexpr int32_t LIGHT_BRIGHTNESS = 0x55000000; static constexpr int32_t LIGHT_COLOR = 0x7F448866; static constexpr int32_t LIGHT_PLAYER_ID = 2; @@ -93,24 +98,6 @@ static constexpr int32_t ACTION_POINTER_1_UP = // Error tolerance for floating point assertions. static const float EPSILON = 0.001f; -using ::testing::AllOf; - -MATCHER_P(WithAction, action, "InputEvent with specified action") { - return arg.action == action; -} - -MATCHER_P(WithSource, source, "InputEvent with specified source") { - return arg.source == source; -} - -MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") { - return arg.displayId == displayId; -} - -MATCHER_P2(WithCoords, x, y, "MotionEvent with specified action") { - return arg.pointerCoords[0].getX() == x && arg.pointerCoords[0].getY(); -} - template<typename T> static inline T min(T a, T b) { return a < b ? a : b; @@ -393,8 +380,12 @@ public: mConfig.defaultPointerDisplayId = pointerDisplayId; } + void setPointerGestureEnabled(bool enabled) { mConfig.pointerGesturesEnabled = enabled; } + float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; } + float getPointerGestureZoomSpeedRatio() { return mConfig.pointerGestureZoomSpeedRatio; } + void setVelocityControlParams(const VelocityControlParameters& params) { mConfig.pointerVelocityControlParameters = params; mConfig.wheelVelocityControlParameters = params; @@ -471,6 +462,7 @@ class FakeEventHub : public EventHubInterface { BitArray<MSC_MAX> mscBitmask; std::vector<VirtualKeyDefinition> virtualKeys; bool enabled; + InputDeviceCountryCode countryCode; status_t enable() { enabled = true; @@ -525,7 +517,7 @@ public: enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0); } - bool isDeviceEnabled(int32_t deviceId) { + bool isDeviceEnabled(int32_t deviceId) const override { Device* device = getDevice(deviceId); if (device == nullptr) { ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); @@ -534,7 +526,7 @@ public: return device->enabled; } - status_t enableDevice(int32_t deviceId) { + status_t enableDevice(int32_t deviceId) override { status_t result; Device* device = getDevice(deviceId); if (device == nullptr) { @@ -549,7 +541,7 @@ public: return result; } - status_t disableDevice(int32_t deviceId) { + status_t disableDevice(int32_t deviceId) override { Device* device = getDevice(deviceId); if (device == nullptr) { ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); @@ -566,7 +558,7 @@ public: enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); } - void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) { + void addConfigurationProperty(int32_t deviceId, const char* key, const char* value) { Device* device = getDevice(deviceId); device->configuration.addProperty(key, value); } @@ -600,6 +592,11 @@ public: device->keyCodeStates.replaceValueFor(keyCode, state); } + void setCountryCode(int32_t deviceId, InputDeviceCountryCode countryCode) { + Device* device = getDevice(deviceId); + device->countryCode = countryCode; + } + void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { Device* device = getDevice(deviceId); device->scanCodeStates.replaceValueFor(scanCode, state); @@ -811,8 +808,8 @@ private: status_t mapAxis(int32_t, int32_t, AxisInfo*) const override { return NAME_NOT_FOUND; } - base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId, - int32_t absCode) { + base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor( + int32_t deviceId, int32_t absCode) const override { Device* device = getDevice(deviceId); if (!device) { return Errorf("Sensor device not found."); @@ -829,15 +826,14 @@ private: mExcludedDevices = devices; } - size_t getEvents(int, RawEvent* buffer, size_t bufferSize) override { + std::vector<RawEvent> getEvents(int) override { std::scoped_lock lock(mLock); - const size_t filledSize = std::min(mEvents.size(), bufferSize); - std::copy(mEvents.begin(), mEvents.begin() + filledSize, buffer); + std::vector<RawEvent> buffer; + std::swap(buffer, mEvents); - mEvents.erase(mEvents.begin(), mEvents.begin() + filledSize); mEventsCondition.notify_all(); - return filledSize; + return buffer; } std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override { @@ -861,6 +857,14 @@ private: return AKEY_STATE_UNKNOWN; } + InputDeviceCountryCode getCountryCode(int32_t deviceId) const override { + Device* device = getDevice(deviceId); + if (device) { + return device->countryCode; + } + return InputDeviceCountryCode::INVALID; + } + int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override { Device* device = getDevice(deviceId); if (device) { @@ -907,13 +911,13 @@ private: } // Return true if the device has non-empty key layout. - bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const override { bool result = false; Device* device = getDevice(deviceId); if (device) { result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0; - for (size_t i = 0; i < numCodes; i++) { + for (size_t i = 0; i < keyCodes.size(); i++) { for (size_t j = 0; j < device->keysByScanCode.size(); j++) { if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) { outFlags[i] = 1; @@ -997,7 +1001,7 @@ private: void cancelVibrate(int32_t) override {} - std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; }; + std::vector<int32_t> getVibratorIds(int32_t deviceId) const override { return mVibrators; }; std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override { return BATTERY_CAPACITY; @@ -1007,15 +1011,21 @@ private: return BATTERY_STATUS; } - const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) override { + std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override { return {DEFAULT_BATTERY}; } - std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, int32_t batteryId) { - return std::nullopt; + std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, + int32_t batteryId) const override { + if (batteryId != DEFAULT_BATTERY) return {}; + static const auto BATTERY_INFO = RawBatteryInfo{.id = DEFAULT_BATTERY, + .name = "default battery", + .flags = InputBatteryClass::CAPACITY, + .path = BATTERY_DEVPATH}; + return BATTERY_INFO; } - const std::vector<int32_t> getRawLightIds(int32_t deviceId) override { + std::vector<int32_t> getRawLightIds(int32_t deviceId) const override { std::vector<int32_t> ids; for (const auto& [rawId, info] : mRawLightInfos) { ids.push_back(rawId); @@ -1023,7 +1033,7 @@ private: return ids; } - std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override { + std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) const override { auto it = mRawLightInfos.find(lightId); if (it == mRawLightInfos.end()) { return std::nullopt; @@ -1040,7 +1050,7 @@ private: mLightIntensities.emplace(lightId, intensities); }; - std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) override { + std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override { auto lightIt = mLightBrightness.find(lightId); if (lightIt == mLightBrightness.end()) { return std::nullopt; @@ -1049,7 +1059,7 @@ private: } std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( - int32_t deviceId, int32_t lightId) override { + int32_t deviceId, int32_t lightId) const override { auto lightIt = mLightIntensities.find(lightId); if (lightIt == mLightIntensities.end()) { return std::nullopt; @@ -1057,13 +1067,9 @@ private: return lightIt->second; }; - virtual bool isExternal(int32_t) const { - return false; - } - - void dump(std::string&) override {} + void dump(std::string&) const override {} - void monitor() override {} + void monitor() const override {} void requestReopenDevices() override {} @@ -1231,9 +1237,9 @@ private: } // Return true if the device has non-empty key layout. - bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(uint32_t, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) override { - for (size_t i = 0; i < numCodes; i++) { + for (size_t i = 0; i < keyCodes.size(); i++) { for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) { if (keyCodes[i] == mSupportedKeyCodes[j]) { outFlags[i] = 1; @@ -1350,7 +1356,7 @@ class InputReaderPolicyTest : public testing::Test { protected: sp<FakeInputReaderPolicy> mFakePolicy; - void SetUp() override { mFakePolicy = new FakeInputReaderPolicy(); } + void SetUp() override { mFakePolicy = sp<FakeInputReaderPolicy>::make(); } void TearDown() override { mFakePolicy.clear(); } }; @@ -1588,7 +1594,7 @@ protected: void SetUp() override { mFakeEventHub = std::make_unique<FakeEventHub>(); - mFakePolicy = new FakeInputReaderPolicy(); + mFakePolicy = sp<FakeInputReaderPolicy>::make(); mFakeListener = std::make_unique<TestInputListener>(); mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy, @@ -1877,34 +1883,37 @@ TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { mapper.addSupportedKeyCode(AKEYCODE_A); mapper.addSupportedKeyCode(AKEYCODE_B); - const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; + const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2}; uint8_t flags[4] = { 0, 0, 0, 1 }; - ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags)) + ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, keyCodes, flags)) << "Should return false when device id is >= 0 but unknown."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(deviceId, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + ASSERT_FALSE(mReader->hasKeys(deviceId, AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) << "Should return false when device id is valid but the sources are not supported by " "the device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, + ASSERT_TRUE(mReader->hasKeys(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) << "Should return value provided by mapper when device id is valid and the device " "supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return false when the device id is < 0 but the sources are not supported by any device."; + ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) + << "Should return false when the device id is < 0 but the sources are not supported by " + "any device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; + ASSERT_TRUE( + mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) + << "Should return value provided by mapper when device id is < 0 and one of the " + "devices supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); } @@ -2231,6 +2240,21 @@ TEST_F(InputReaderTest, BatteryGetStatus) { ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS); } +TEST_F(InputReaderTest, BatteryGetDevicePath) { + constexpr int32_t deviceId = END_RESERVED_ID + 1000; + ftl::Flags<InputDeviceClass> deviceClass = + InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; + constexpr int32_t eventHubId = 1; + const char* DEVICE_LOCATION = "BLUETOOTH"; + std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); + device->addController<FakePeripheralController>(eventHubId); + mReader->pushNextDevice(device); + + ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); + + ASSERT_EQ(mReader->getBatteryDevicePath(deviceId), BATTERY_DEVPATH); +} + TEST_F(InputReaderTest, LightGetColor) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT; @@ -2272,7 +2296,7 @@ protected: std::shared_ptr<FakePointerController> mFakePointerController; void SetUp() override { - mFakePolicy = new FakeInputReaderPolicy(); + mFakePolicy = sp<FakeInputReaderPolicy>::make(); mFakePointerController = std::make_shared<FakePointerController>(); mFakePolicy->setPointerController(mFakePointerController); mTestListener = std::make_unique<TestInputListener>(2000ms /*eventHappenedTimeout*/, @@ -2671,7 +2695,7 @@ protected: void SetUp() override { mFakeEventHub = std::make_unique<FakeEventHub>(); - mFakePolicy = new FakeInputReaderPolicy(); + mFakePolicy = sp<FakeInputReaderPolicy>::make(); mFakeListener = std::make_unique<TestInputListener>(); mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy, *mFakeListener); @@ -2706,6 +2730,17 @@ TEST_F(InputDeviceTest, ImmutableProperties) { ASSERT_EQ(ftl::Flags<InputDeviceClass>(0), mDevice->getClasses()); } +TEST_F(InputDeviceTest, CountryCodeCorrectlyMapped) { + mFakeEventHub->setCountryCode(EVENTHUB_ID, InputDeviceCountryCode::INTERNATIONAL); + + // Configuration + mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD); + InputReaderConfiguration config; + mDevice->configure(ARBITRARY_TIME, &config, 0); + + ASSERT_EQ(InputDeviceCountryCode::INTERNATIONAL, mDevice->getDeviceInfo().getCountryCode()); +} + TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) { ASSERT_EQ(mDevice->isEnabled(), false); } @@ -2743,9 +2778,9 @@ TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0)) << "Ignored device should return unknown switch state."; - const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; + const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B}; uint8_t flags[2] = { 0, 1 }; - ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags)) + ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, keyCodes, flags)) << "Ignored device should never mark any key codes."; ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged."; ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged."; @@ -2753,7 +2788,7 @@ TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { // Configuration. - mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8("key"), String8("value")); + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "key", "value"); FakeInputMapper& mapper1 = mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD); @@ -2774,10 +2809,10 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe InputReaderConfiguration config; mDevice->configure(ARBITRARY_TIME, &config, 0); - String8 propertyValue; - ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) + std::string propertyValue; + ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty("key", propertyValue)) << "Device should have read configuration during configuration phase."; - ASSERT_STREQ("value", propertyValue.string()); + ASSERT_EQ("value", propertyValue); ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled()); @@ -2820,16 +2855,16 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4)) << "Should query mapper when source is supported."; - const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; + const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2}; uint8_t flags[4] = { 0, 0, 0, 1 }; - ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) << "Should do nothing when source is unsupported."; ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported."; - ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags)) + ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, keyCodes, flags)) << "Should query mapper when source is supported."; ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set."; ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set."; @@ -2936,6 +2971,21 @@ TEST_F(InputDeviceTest, Configure_UniqueId_CorrectlyMatches) { ASSERT_EQ(DISPLAY_UNIQUE_ID, mDevice->getAssociatedDisplayUniqueId()); } +/** + * This test reproduces a crash caused by a dangling reference that remains after device is added + * and removed. The reference is accessed in InputDevice::dump(..); + */ +TEST_F(InputDeviceTest, DumpDoesNotCrash) { + constexpr int32_t TEST_EVENTHUB_ID = 10; + mFakeEventHub->addDevice(TEST_EVENTHUB_ID, "Test EventHub device", InputDeviceClass::BATTERY); + + InputDevice device(mReader->getContext(), 1 /*id*/, 2 /*generation*/, {} /*identifier*/); + device.addEventHubDevice(TEST_EVENTHUB_ID, true /*populateMappers*/); + device.removeEventHubDevice(TEST_EVENTHUB_ID); + std::string dumpStr, eventHubDevStr; + device.dump(dumpStr, eventHubDevStr); +} + // --- InputMapperTest --- class InputMapperTest : public testing::Test { @@ -2956,7 +3006,7 @@ protected: virtual void SetUp(ftl::Flags<InputDeviceClass> classes) { mFakeEventHub = std::make_unique<FakeEventHub>(); - mFakePolicy = new FakeInputReaderPolicy(); + mFakePolicy = sp<FakeInputReaderPolicy>::make(); mFakeListener = std::make_unique<TestInputListener>(); mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy, *mFakeListener); @@ -2975,7 +3025,7 @@ protected: } void addConfigurationProperty(const char* key, const char* value) { - mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value)); + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, key, value); } void configureDevice(uint32_t changes) { @@ -3756,9 +3806,8 @@ TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0); - const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); + ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, {AKEYCODE_A, AKEYCODE_B}, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } @@ -4108,6 +4157,37 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) { ASSERT_EQ(AMETA_NONE, mapper2.getMetaState()); } +TEST_F(KeyboardInputMapperTest, Process_DisabledDevice) { + const int32_t USAGE_A = 0x070004; + mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); + mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE); + + KeyboardInputMapper& mapper = + addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); + // Key down by scan code. + process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1); + NotifyKeyArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); + ASSERT_EQ(ARBITRARY_TIME, args.eventTime); + ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); + ASSERT_EQ(AKEYCODE_HOME, args.keyCode); + ASSERT_EQ(KEY_HOME, args.scanCode); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); + + // Disable device, it should synthesize cancellation events for down events. + mFakePolicy->addDisabledDevice(DEVICE_ID); + configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); + ASSERT_EQ(AKEYCODE_HOME, args.keyCode); + ASSERT_EQ(KEY_HOME, args.scanCode); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED, args.flags); +} + // --- KeyboardInputMapperTest_ExternalDevice --- class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest { @@ -5071,8 +5151,9 @@ TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) { process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE), - WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithSource(AINPUT_SOURCE_MOUSE), WithDisplayId(SECONDARY_DISPLAY_ID), + WithCoords(110.0f, 220.0f)))); ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f)); } @@ -5097,8 +5178,9 @@ TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) { process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE), - WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithSource(AINPUT_SOURCE_MOUSE), WithDisplayId(SECONDARY_DISPLAY_ID), + WithCoords(110.0f, 220.0f)))); ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f)); } @@ -5395,25 +5477,6 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNot ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); } -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) { - mFakeEventHub->addRelativeAxis(EVENTHUB_ID, REL_X); - mFakeEventHub->addRelativeAxis(EVENTHUB_ID, REL_Y); - prepareButtons(); - prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); - - ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); -} - -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) { - prepareButtons(); - prepareAxes(POSITION); - addConfigurationProperty("touch.deviceType", "touchPad"); - SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); - - ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); -} - TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) { prepareButtons(); prepareAxes(POSITION); @@ -5487,9 +5550,9 @@ TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { prepareVirtualKeys(); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); - const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A }; uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); + ASSERT_TRUE( + mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, {AKEYCODE_HOME, AKEYCODE_A}, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } @@ -6782,9 +6845,7 @@ TEST_F(SingleTouchInputMapperTest, NotifyMotionArgs motionArgs; // Down. - int32_t x = 100; - int32_t y = 200; - processDown(mapper, x, y); + processDown(mapper, 100, 200); processSync(mapper); // We should receive a down event @@ -9633,6 +9694,266 @@ TEST_F(MultiTouchInputMapperTest, WhenCapturedAndNotCaptured_GetSources) { ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); } +class MultiTouchPointerModeTest : public MultiTouchInputMapperTest { +protected: + float mPointerMovementScale; + float mPointerXZoomScale; + void preparePointerMode(int xAxisResolution, int yAxisResolution) { + addConfigurationProperty("touch.deviceType", "pointer"); + std::shared_ptr<FakePointerController> fakePointerController = + std::make_shared<FakePointerController>(); + fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1); + fakePointerController->setPosition(0, 0); + fakePointerController->setButtonState(0); + prepareDisplay(DISPLAY_ORIENTATION_0); + + prepareAxes(POSITION); + prepareAbsoluteAxisResolution(xAxisResolution, yAxisResolution); + // In order to enable swipe and freeform gesture in pointer mode, pointer capture + // needs to be disabled, and the pointer gesture needs to be enabled. + mFakePolicy->setPointerCapture(false); + mFakePolicy->setPointerGestureEnabled(true); + mFakePolicy->setPointerController(fakePointerController); + + float rawDiagonal = hypotf(RAW_X_MAX - RAW_X_MIN, RAW_Y_MAX - RAW_Y_MIN); + float displayDiagonal = hypotf(DISPLAY_WIDTH, DISPLAY_HEIGHT); + mPointerMovementScale = + mFakePolicy->getPointerGestureMovementSpeedRatio() * displayDiagonal / rawDiagonal; + mPointerXZoomScale = + mFakePolicy->getPointerGestureZoomSpeedRatio() * displayDiagonal / rawDiagonal; + } + + void prepareAbsoluteAxisResolution(int xAxisResolution, int yAxisResolution) { + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, + /*flat*/ 0, + /*fuzz*/ 0, /*resolution*/ xAxisResolution); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, + /*flat*/ 0, + /*fuzz*/ 0, /*resolution*/ yAxisResolution); + } +}; + +/** + * Two fingers down on a pointer mode touch pad. The width + * of the two finger is larger than 1/4 of the touch pack diagnal length. However, it + * is smaller than the fixed min physical length 30mm. Two fingers' distance must + * be greater than the both value to be freeform gesture, so that after two + * fingers start to move downwards, the gesture should be swipe. + */ +TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthSwipe) { + // The min freeform gesture width is 25units/mm x 30mm = 750 + // which is greater than fraction of the diagnal length of the touchpad (349). + // Thus, MaxSwipWidth is 750. + preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + NotifyMotionArgs motionArgs; + + // Two fingers down at once. + // The two fingers are 450 units apart, expects the current gesture to be PRESS + // Pointer's initial position is used the [0,0] coordinate. + int32_t x1 = 100, y1 = 125, x2 = 550, y2 = 125; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); + ASSERT_NO_FATAL_FAILURE( + assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); + + // It should be recognized as a SWIPE gesture when two fingers start to move down, + // that there should be 1 pointer. + int32_t movingDistance = 200; + y1 += movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(MotionClassification::TWO_FINGER_SWIPE, motionArgs.classification); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0, + movingDistance * mPointerMovementScale, 1, 0, 0, 0, + 0, 0, 0, 0)); +} + +/** + * Two fingers down on a pointer mode touch pad. The width of the two finger is larger + * than the minimum freeform gesture width, 30mm. However, it is smaller than 1/4 of + * the touch pack diagnal length. Two fingers' distance must be greater than the both + * value to be freeform gesture, so that after two fingers start to move downwards, + * the gesture should be swipe. + */ +TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) { + // The min freeform gesture width is 5units/mm x 30mm = 150 + // which is greater than fraction of the diagnal length of the touchpad (349). + // Thus, MaxSwipWidth is the fraction of the diagnal length, 349. + preparePointerMode(5 /*xResolution*/, 5 /*yResolution*/); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + NotifyMotionArgs motionArgs; + + // Two fingers down at once. + // The two fingers are 250 units apart, expects the current gesture to be PRESS + // Pointer's initial position is used the [0,0] coordinate. + int32_t x1 = 100, y1 = 125, x2 = 350, y2 = 125; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); + ASSERT_NO_FATAL_FAILURE( + assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); + + // It should be recognized as a SWIPE gesture when two fingers start to move down, + // and there should be 1 pointer. + int32_t movingDistance = 200; + y1 += movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(MotionClassification::TWO_FINGER_SWIPE, motionArgs.classification); + // New coordinate is the scaled relative coordinate from the initial coordinate. + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0, + movingDistance * mPointerMovementScale, 1, 0, 0, 0, + 0, 0, 0, 0)); +} + +/** + * Touch the touch pad with two fingers with a distance wider than the minimum freeform + * gesture width and 1/4 of the diagnal length of the touchpad. Expect to receive + * freeform gestures after two fingers start to move downwards. + */ +TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { + preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + NotifyMotionArgs motionArgs; + + // Two fingers down at once. Wider than the max swipe width. + // The gesture is expected to be PRESS, then transformed to FREEFORM + int32_t x1 = 100, y1 = 125, x2 = 900, y2 = 125; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); + // One pointer for PRESS, and its coordinate is used as the origin for pointer coordinates. + ASSERT_NO_FATAL_FAILURE( + assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); + + int32_t movingDistance = 200; + + // Move two fingers down, expect a cancel event because gesture is changing to freeform, + // then two down events for two pointers. + y1 += movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + // The previous PRESS gesture is cancelled, because it is transformed to freeform + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); + ASSERT_EQ(2U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN, motionArgs.action & AMOTION_EVENT_ACTION_MASK); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); + // Two pointers' scaled relative coordinates from their initial centroid. + // Initial y coordinates are 0 as y1 and y2 have the same value. + float cookedX1 = (x1 - x2) / 2 * mPointerXZoomScale; + float cookedX2 = (x2 - x1) / 2 * mPointerXZoomScale; + // When pointers move, the new coordinates equal to the initial coordinates plus + // scaled moving distance. + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], cookedX1, + movingDistance * mPointerMovementScale, 1, 0, 0, 0, + 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], cookedX2, + movingDistance * mPointerMovementScale, 1, 0, 0, 0, + 0, 0, 0, 0)); + + // Move two fingers down again, expect one MOVE motion event. + y1 += movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(2U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], cookedX1, + movingDistance * 2 * mPointerMovementScale, 1, 0, 0, + 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], cookedX2, + movingDistance * 2 * mPointerMovementScale, 1, 0, 0, + 0, 0, 0, 0, 0)); +} + // --- JoystickInputMapperTest --- class JoystickInputMapperTest : public InputMapperTest { @@ -9714,7 +10035,7 @@ protected: virtual void SetUp(ftl::Flags<InputDeviceClass> classes) { mFakeEventHub = std::make_unique<FakeEventHub>(); - mFakePolicy = new FakeInputReaderPolicy(); + mFakePolicy = sp<FakeInputReaderPolicy>::make(); mFakeListener = std::make_unique<TestInputListener>(); mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy, *mFakeListener); @@ -9800,7 +10121,7 @@ protected: TEST_F(LightControllerTest, MonoLight) { RawLightInfo infoMono = {.id = 1, - .name = "Mono", + .name = "mono_light", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS, .path = ""}; @@ -9811,7 +10132,29 @@ TEST_F(LightControllerTest, MonoLight) { controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); - ASSERT_EQ(InputDeviceLightType::MONO, lights[0].type); + ASSERT_EQ(InputDeviceLightType::INPUT, lights[0].type); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS)); + + ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_BRIGHTNESS)); + ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_BRIGHTNESS); +} + +TEST_F(LightControllerTest, MonoKeyboardBacklight) { + RawLightInfo infoMono = {.id = 1, + .name = "mono_keyboard_backlight", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | + InputLightClass::KEYBOARD_BACKLIGHT, + .path = ""}; + mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); + + PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); + InputDeviceInfo info; + controller.populateDeviceInfo(&info); + std::vector<InputDeviceLightInfo> lights = info.getLights(); + ASSERT_EQ(1U, lights.size()); + ASSERT_EQ(InputDeviceLightType::KEYBOARD_BACKLIGHT, lights[0].type); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS)); ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_BRIGHTNESS)); ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_BRIGHTNESS); @@ -9842,7 +10185,85 @@ TEST_F(LightControllerTest, RGBLight) { controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); - ASSERT_EQ(InputDeviceLightType::RGB, lights[0].type); + ASSERT_EQ(InputDeviceLightType::INPUT, lights[0].type); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS)); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB)); + + ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR)); + ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR); +} + +TEST_F(LightControllerTest, CorrectRGBKeyboardBacklight) { + RawLightInfo infoRed = {.id = 1, + .name = "red_keyboard_backlight", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::RED | + InputLightClass::KEYBOARD_BACKLIGHT, + .path = ""}; + RawLightInfo infoGreen = {.id = 2, + .name = "green_keyboard_backlight", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::GREEN | + InputLightClass::KEYBOARD_BACKLIGHT, + .path = ""}; + RawLightInfo infoBlue = {.id = 3, + .name = "blue_keyboard_backlight", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::BLUE | + InputLightClass::KEYBOARD_BACKLIGHT, + .path = ""}; + mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed)); + mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen)); + mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue)); + + PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); + InputDeviceInfo info; + controller.populateDeviceInfo(&info); + std::vector<InputDeviceLightInfo> lights = info.getLights(); + ASSERT_EQ(1U, lights.size()); + ASSERT_EQ(InputDeviceLightType::KEYBOARD_BACKLIGHT, lights[0].type); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS)); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB)); + + ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR)); + ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR); +} + +TEST_F(LightControllerTest, IncorrectRGBKeyboardBacklight) { + RawLightInfo infoRed = {.id = 1, + .name = "red", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::RED, + .path = ""}; + RawLightInfo infoGreen = {.id = 2, + .name = "green", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::GREEN, + .path = ""}; + RawLightInfo infoBlue = {.id = 3, + .name = "blue", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::BLUE, + .path = ""}; + RawLightInfo infoGlobal = {.id = 3, + .name = "global_keyboard_backlight", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::GLOBAL | + InputLightClass::KEYBOARD_BACKLIGHT, + .path = ""}; + mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed)); + mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen)); + mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue)); + mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoGlobal)); + + PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); + InputDeviceInfo info; + controller.populateDeviceInfo(&info); + std::vector<InputDeviceLightInfo> lights = info.getLights(); + ASSERT_EQ(1U, lights.size()); + ASSERT_EQ(InputDeviceLightType::INPUT, lights[0].type); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS)); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB)); ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR)); ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR); @@ -9850,7 +10271,7 @@ TEST_F(LightControllerTest, RGBLight) { TEST_F(LightControllerTest, MultiColorRGBLight) { RawLightInfo infoColor = {.id = 1, - .name = "red", + .name = "multi_color", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS | InputLightClass::MULTI_INTENSITY | @@ -9864,7 +10285,34 @@ TEST_F(LightControllerTest, MultiColorRGBLight) { controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); - ASSERT_EQ(InputDeviceLightType::MULTI_COLOR, lights[0].type); + ASSERT_EQ(InputDeviceLightType::INPUT, lights[0].type); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS)); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB)); + + ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR)); + ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR); +} + +TEST_F(LightControllerTest, MultiColorRGBKeyboardBacklight) { + RawLightInfo infoColor = {.id = 1, + .name = "multi_color_keyboard_backlight", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | + InputLightClass::MULTI_INTENSITY | + InputLightClass::MULTI_INDEX | + InputLightClass::KEYBOARD_BACKLIGHT, + .path = ""}; + + mFakeEventHub->addRawLightInfo(infoColor.id, std::move(infoColor)); + + PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); + InputDeviceInfo info; + controller.populateDeviceInfo(&info); + std::vector<InputDeviceLightInfo> lights = info.getLights(); + ASSERT_EQ(1U, lights.size()); + ASSERT_EQ(InputDeviceLightType::KEYBOARD_BACKLIGHT, lights[0].type); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS)); + ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB)); ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR)); ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR); @@ -9902,6 +10350,8 @@ TEST_F(LightControllerTest, PlayerIdLight) { std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(InputDeviceLightType::PLAYER_ID, lights[0].type); + ASSERT_FALSE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS)); + ASSERT_FALSE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB)); ASSERT_FALSE(controller.setLightColor(lights[0].id, LIGHT_COLOR)); ASSERT_TRUE(controller.setLightPlayerId(lights[0].id, LIGHT_PLAYER_ID)); diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp index 89c0741dfd..1f4b2486bd 100644 --- a/services/inputflinger/tests/LatencyTracker_test.cpp +++ b/services/inputflinger/tests/LatencyTracker_test.cpp @@ -44,7 +44,7 @@ InputEventTimeline getTestTimeline() { graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 9; graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 10; expectedCT.setGraphicsTimeline(std::move(graphicsTimeline)); - t.connectionTimelines.emplace(new BBinder(), std::move(expectedCT)); + t.connectionTimelines.emplace(sp<BBinder>::make(), std::move(expectedCT)); return t; } @@ -56,8 +56,8 @@ protected: sp<IBinder> connection2; void SetUp() override { - connection1 = new BBinder(); - connection2 = new BBinder(); + connection1 = sp<BBinder>::make(); + connection2 = sp<BBinder>::make(); mTracker = std::make_unique<LatencyTracker>(this); } diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h index 0bdfc6b9fb..cad698fd36 100644 --- a/services/inputflinger/tests/TestInputListener.h +++ b/services/inputflinger/tests/TestInputListener.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_TEST_INPUT_LISTENER_H -#define _UI_TEST_INPUT_LISTENER_H +#pragma once #include <android-base/thread_annotations.h> #include <gmock/gmock.h> @@ -103,4 +102,3 @@ private: }; } // namespace android -#endif diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h new file mode 100644 index 0000000000..03736a33af --- /dev/null +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#pragma once + +#include <android/input.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +namespace android { + +MATCHER_P(WithMotionAction, action, "InputEvent with specified action") { + if (action == AMOTION_EVENT_ACTION_CANCEL) { + *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set"; + return (arg.flags & AMOTION_EVENT_FLAG_CANCELED) != 0; + } + *result_listener << "expected action " << MotionEvent::actionToString(action) << ", but got " + << MotionEvent::actionToString(arg.action); + return action == arg.action; +} + +MATCHER_P(WithSource, source, "InputEvent with specified source") { + *result_listener << "expected source " << source << ", but got " << arg.source; + return arg.source == source; +} + +MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") { + *result_listener << "expected displayId " << displayId << ", but got " << arg.displayId; + return arg.displayId == displayId; +} + +MATCHER_P2(WithCoords, x, y, "InputEvent with specified coords") { + const auto argX = arg.pointerCoords[0].getX(); + const auto argY = arg.pointerCoords[0].getY(); + *result_listener << "expected coords (" << x << ", " << y << "), but got (" << argX << ", " + << argY << ")"; + return argX == x && argY == y; +} + +MATCHER_P(WithFlags, flags, "InputEvent with specified flags") { + *result_listener << "expected flags " << flags << ", but got " << arg.flags; + return arg.flags == flags; +} + +} // namespace android diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index a37fc2b790..e0ff8c3d4c 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _UI_TEST_INPUT_UINPUT_INJECTOR_H -#define _UI_TEST_INPUT_UINPUT_INJECTOR_H +#pragma once #include <android-base/unique_fd.h> #include <gtest/gtest.h> @@ -155,5 +154,3 @@ private: }; } // namespace android - -#endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp index 29fa001185..4c84160a1d 100644 --- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp +++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp @@ -24,6 +24,7 @@ #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h" #include "TestInputListener.h" +#include "TestInputListenerMatchers.h" using ::testing::AllOf; @@ -55,21 +56,6 @@ constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL; constexpr int32_t FLAG_CANCELED = AMOTION_EVENT_FLAG_CANCELED; -MATCHER_P(WithAction, action, "MotionEvent with specified action") { - bool result = true; - if (action == CANCEL) { - result &= (arg.flags & FLAG_CANCELED) != 0; - } - result &= arg.action == action; - *result_listener << "expected to receive " << MotionEvent::actionToString(action) - << " but received " << MotionEvent::actionToString(arg.action) << " instead."; - return result; -} - -MATCHER_P(WithFlags, flags, "MotionEvent with specified flags") { - return arg.flags == flags; -} - static nsecs_t toNs(std::chrono::nanoseconds duration) { return duration.count(); } @@ -428,11 +414,11 @@ protected: }; /** - * Create a basic configuration change and send it to input classifier. + * Create a basic configuration change and send it to input processor. * Expect that the event is received by the next input stage, unmodified. */ TEST_F(UnwantedInteractionBlockerTest, ConfigurationChangedIsPassedToNextListener) { - // Create a basic configuration change and send to classifier + // Create a basic configuration change and send to blocker NotifyConfigurationChangedArgs args(1 /*sequenceNum*/, 2 /*eventTime*/); mBlocker->notifyConfigurationChanged(&args); @@ -446,7 +432,7 @@ TEST_F(UnwantedInteractionBlockerTest, ConfigurationChangedIsPassedToNextListene * to next stage unmodified. */ TEST_F(UnwantedInteractionBlockerTest, KeyIsPassedToNextListener) { - // Create a basic key event and send to classifier + // Create a basic key event and send to blocker NotifyKeyArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 21 /*readTime*/, 3 /*deviceId*/, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, 0 /*policyFlags*/, AKEY_EVENT_ACTION_DOWN, 4 /*flags*/, AKEYCODE_HOME, 5 /*scanCode*/, @@ -605,19 +591,19 @@ TEST_F(UnwantedInteractionBlockerTest, HeuristicFilterWorks) { // Small touch down NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}}); mBlocker->notifyMotion(&args1); - mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN)); // Large touch oval on the next move NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}}); mBlocker->notifyMotion(&args2); - mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the touch to force the model to decide on whether it's a palm NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}}); mBlocker->notifyMotion(&args3); - mTestListener.assertNotifyMotionWasCalled(WithAction(CANCEL)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(CANCEL)); } /** @@ -633,14 +619,14 @@ TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) { NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}}); args1.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; mBlocker->notifyMotion(&args1); - mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN)); // Move the stylus, setting large TOUCH_MAJOR/TOUCH_MINOR dimensions NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}}); args2.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; mBlocker->notifyMotion(&args2); - mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the stylus. If it were a touch event, this would force the model to decide on whether // it's a palm. @@ -648,7 +634,7 @@ TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) { generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}}); args3.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; mBlocker->notifyMotion(&args3); - mTestListener.assertNotifyMotionWasCalled(WithAction(UP)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(UP)); } /** @@ -664,21 +650,21 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { // Touch down NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}}); mBlocker->notifyMotion(&args1); - mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN)); // Stylus pointer down NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, POINTER_1_DOWN, {{1, 2, 3}, {10, 20, 30}}); args2.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; mBlocker->notifyMotion(&args2); - mTestListener.assertNotifyMotionWasCalled(WithAction(POINTER_1_DOWN)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(POINTER_1_DOWN)); // Large touch oval on the next finger move NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, MOVE, {{1, 2, 300}, {11, 21, 30}}); args3.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; mBlocker->notifyMotion(&args3); - mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the finger pointer. It should be canceled due to the heuristic filter. NotifyMotionArgs args4 = generateMotionArgs(0 /*downTime*/, 3 * RESAMPLE_PERIOD, POINTER_0_UP, @@ -686,14 +672,14 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { args4.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; mBlocker->notifyMotion(&args4); mTestListener.assertNotifyMotionWasCalled( - AllOf(WithAction(POINTER_0_UP), WithFlags(FLAG_CANCELED))); + AllOf(WithMotionAction(POINTER_0_UP), WithFlags(FLAG_CANCELED))); NotifyMotionArgs args5 = generateMotionArgs(0 /*downTime*/, 4 * RESAMPLE_PERIOD, MOVE, {{12, 22, 30}}); args5.pointerProperties[0].id = args4.pointerProperties[1].id; args5.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; mBlocker->notifyMotion(&args5); - mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the stylus pointer NotifyMotionArgs args6 = @@ -701,7 +687,7 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { args6.pointerProperties[0].id = args4.pointerProperties[1].id; args6.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; mBlocker->notifyMotion(&args6); - mTestListener.assertNotifyMotionWasCalled(WithAction(UP)); + mTestListener.assertNotifyMotionWasCalled(WithMotionAction(UP)); } using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest; diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp index 455a1e2133..55c2db6c91 100644 --- a/services/inputflinger/tests/fuzzers/Android.bp +++ b/services/inputflinger/tests/fuzzers/Android.bp @@ -21,7 +21,6 @@ package { default_applicable_licenses: ["frameworks_native_license"], } - cc_fuzz { name: "inputflinger_latencytracker_fuzzer", defaults: [ @@ -34,7 +33,6 @@ cc_fuzz { "libbase", "libbinder", "liblog", - "libui", "libutils", "libinput", "libinputflinger", @@ -43,6 +41,107 @@ cc_fuzz { "LatencyTrackerFuzzer.cpp", ], fuzz_config: { - cc: ["android-framework-input@google.com"], + cc: ["android-framework-input@google.com"], }, } + +cc_defaults { + name: "inputflinger_fuzz_defaults", + defaults: [ + "inputflinger_defaults", + ], + include_dirs: [ + "frameworks/native/services/inputflinger", + ], + shared_libs: [ + "android.hardware.input.classifier@1.0", + "android.hardware.input.processor-V1-ndk", + "libbase", + "libbinder", + "libcutils", + "liblog", + "libutils", + "libinput", + "libinputflinger", + "libinputreader", + "libinputflinger_base", + "libstatslog", + ], + header_libs: [ + "libbatteryservice_headers", + "libinputreader_headers", + ], + fuzz_config: { + cc: ["android-framework-input@google.com"], + }, +} + +cc_fuzz { + name: "inputflinger_cursor_input_fuzzer", + defaults: [ + "inputflinger_fuzz_defaults", + ], + srcs: [ + "CursorInputFuzzer.cpp", + ], +} + +cc_fuzz { + name: "inputflinger_keyboard_input_fuzzer", + defaults: [ + "inputflinger_fuzz_defaults", + ], + srcs: [ + "KeyboardInputFuzzer.cpp", + ], +} + +cc_fuzz { + name: "inputflinger_multitouch_input_fuzzer", + defaults: [ + "inputflinger_fuzz_defaults", + ], + srcs: [ + "MultiTouchInputFuzzer.cpp", + ], +} + +cc_fuzz { + name: "inputflinger_switch_input_fuzzer", + defaults: [ + "inputflinger_fuzz_defaults", + ], + srcs: [ + "SwitchInputFuzzer.cpp", + ], +} + +cc_fuzz { + name: "inputflinger_input_reader_fuzzer", + defaults: [ + "inputflinger_fuzz_defaults", + ], + srcs: [ + "InputReaderFuzzer.cpp", + ], +} + +cc_fuzz { + name: "inputflinger_blocking_queue_fuzzer", + defaults: [ + "inputflinger_fuzz_defaults", + ], + srcs: [ + "BlockingQueueFuzzer.cpp", + ], +} + +cc_fuzz { + name: "inputflinger_input_classifier_fuzzer", + defaults: [ + "inputflinger_fuzz_defaults", + ], + srcs: [ + "InputClassifierFuzzer.cpp", + ], +} diff --git a/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp b/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp new file mode 100644 index 0000000000..d2595bfc9d --- /dev/null +++ b/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp @@ -0,0 +1,69 @@ +/* + * 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 <fuzzer/FuzzedDataProvider.h> +#include <thread> +#include "BlockingQueue.h" + +// Chosen to be a number large enough for variation in fuzzer runs, but not consume too much memory. +static constexpr size_t MAX_CAPACITY = 1024; + +namespace android { + +extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { + FuzzedDataProvider fdp(data, size); + size_t capacity = fdp.ConsumeIntegralInRange<size_t>(1, MAX_CAPACITY); + size_t filled = 0; + BlockingQueue<int32_t> queue(capacity); + + while (fdp.remaining_bytes() > 0) { + fdp.PickValueInArray<std::function<void()>>({ + [&]() -> void { + size_t numPushes = fdp.ConsumeIntegralInRange<size_t>(0, capacity + 1); + for (size_t i = 0; i < numPushes; i++) { + queue.push(fdp.ConsumeIntegral<int32_t>()); + } + filled = std::min(capacity, filled + numPushes); + }, + [&]() -> void { + // Pops blocks if it is empty, so only pop up to num elements inserted. + size_t numPops = fdp.ConsumeIntegralInRange<size_t>(0, filled); + for (size_t i = 0; i < numPops; i++) { + queue.pop(); + } + filled > numPops ? filled -= numPops : filled = 0; + }, + [&]() -> void { + queue.clear(); + filled = 0; + }, + [&]() -> void { + int32_t eraseElement = fdp.ConsumeIntegral<int32_t>(); + queue.erase([&](int32_t element) { + if (element == eraseElement) { + filled--; + return true; + } + return false; + }); + }, + })(); + } + + return 0; +} + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp new file mode 100644 index 0000000000..4b542aab19 --- /dev/null +++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp @@ -0,0 +1,96 @@ +/* + * 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 <CursorInputMapper.h> +#include <FuzzContainer.h> +#include <fuzzer/FuzzedDataProvider.h> + +namespace android { + +static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) { + // Pick a random property to set for the mapper to have set. + fdp->PickValueInArray<std::function<void()>>( + {[&]() -> void { fuzzer.addProperty("cursor.mode", "pointer"); }, + [&]() -> void { fuzzer.addProperty("cursor.mode", "navigation"); }, + [&]() -> void { + fuzzer.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data()); + }, + [&]() -> void { + fuzzer.addProperty("cursor.orientationAware", + fdp->ConsumeRandomLengthString(100).data()); + }})(); +} + +extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { + std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size); + FuzzContainer fuzzer(fdp); + + CursorInputMapper& mapper = fuzzer.getMapper<CursorInputMapper>(); + auto policyConfig = fuzzer.getPolicyConfig(); + + // Loop through mapper operations until randomness is exhausted. + while (fdp->remaining_bytes() > 0) { + fdp->PickValueInArray<std::function<void()>>({ + [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + std::string dump; + mapper.dump(dump); + }, + [&]() -> void { mapper.getSources(); }, + [&]() -> void { + mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + // Need to reconfigure with 0 or you risk a NPE. + mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0); + InputDeviceInfo info; + mapper.populateDeviceInfo(&info); + }, + [&]() -> void { + int32_t type, code; + type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes) + : fdp->ConsumeIntegral<int32_t>(); + code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes) + : fdp->ConsumeIntegral<int32_t>(); + + // Need to reconfigure with 0 or you risk a NPE. + mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0); + RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<int32_t>(), + type, + code, + fdp->ConsumeIntegral<int32_t>()}; + mapper.process(&rawEvent); + }, + [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); }, + [&]() -> void { + mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + // Need to reconfigure with 0 or you risk a NPE. + mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0); + mapper.getAssociatedDisplayId(); + }, + })(); + } + + return 0; +} + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h new file mode 100644 index 0000000000..62615d0116 --- /dev/null +++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#pragma once + +#include <InputDevice.h> +#include <InputMapper.h> +#include <InputReader.h> +#include <MapperHelpers.h> +#include <fuzzer/FuzzedDataProvider.h> + +namespace android { + +class FuzzContainer { + std::shared_ptr<FuzzEventHub> mFuzzEventHub; + sp<FuzzInputReaderPolicy> mFuzzPolicy; + std::unique_ptr<FuzzInputListener> mFuzzListener; + std::unique_ptr<FuzzInputReaderContext> mFuzzContext; + std::unique_ptr<InputDevice> mFuzzDevice; + InputReaderConfiguration mPolicyConfig; + std::shared_ptr<FuzzedDataProvider> mFdp; + +public: + FuzzContainer(std::shared_ptr<FuzzedDataProvider> fdp) : mFdp(fdp) { + // Setup parameters. + std::string deviceName = mFdp->ConsumeRandomLengthString(16); + std::string deviceLocation = mFdp->ConsumeRandomLengthString(12); + int32_t deviceID = mFdp->ConsumeIntegralInRange<int32_t>(0, 5); + int32_t deviceGeneration = mFdp->ConsumeIntegralInRange<int32_t>(/*from*/ 0, /*to*/ 5); + + // Create mocked objects. + mFuzzEventHub = std::make_shared<FuzzEventHub>(mFdp); + mFuzzPolicy = sp<FuzzInputReaderPolicy>::make(mFdp); + mFuzzListener = std::make_unique<FuzzInputListener>(); + mFuzzContext = std::make_unique<FuzzInputReaderContext>(mFuzzEventHub, mFuzzPolicy, + *mFuzzListener, mFdp); + + InputDeviceIdentifier identifier; + identifier.name = deviceName; + identifier.location = deviceLocation; + mFuzzDevice = std::make_unique<InputDevice>(mFuzzContext.get(), deviceID, deviceGeneration, + identifier); + mFuzzPolicy->getReaderConfiguration(&mPolicyConfig); + } + + ~FuzzContainer() {} + + void configureDevice() { + nsecs_t arbitraryTime = mFdp->ConsumeIntegral<nsecs_t>(); + mFuzzDevice->configure(arbitraryTime, &mPolicyConfig, 0); + mFuzzDevice->reset(arbitraryTime); + } + + void addProperty(std::string key, std::string value) { + mFuzzEventHub->addProperty(key, value); + configureDevice(); + } + + InputReaderConfiguration& getPolicyConfig() { return mPolicyConfig; } + + template <class T, typename... Args> + T& getMapper(Args... args) { + T& mapper = mFuzzDevice->addMapper<T>(mFdp->ConsumeIntegral<int32_t>(), args...); + configureDevice(); + return mapper; + } +}; + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp new file mode 100644 index 0000000000..c407cffdbf --- /dev/null +++ b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp @@ -0,0 +1,126 @@ +/* + * 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 <MapperHelpers.h> +#include <fuzzer/FuzzedDataProvider.h> +#include "InputCommonConverter.h" +#include "InputProcessor.h" + +namespace android { + +static constexpr int32_t MAX_AXES = 64; + +// Used by two fuzz operations and a bit lengthy, so pulled out into a function. +NotifyMotionArgs generateFuzzedMotionArgs(FuzzedDataProvider &fdp) { + // Create a basic motion event for testing + PointerProperties properties; + properties.id = 0; + properties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + PointerCoords coords; + coords.clear(); + for (int32_t i = 0; i < fdp.ConsumeIntegralInRange<int32_t>(0, MAX_AXES); i++) { + coords.setAxisValue(fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeFloatingPoint<float>()); + } + + const nsecs_t downTime = 2; + const nsecs_t readTime = downTime + fdp.ConsumeIntegralInRange<nsecs_t>(0, 1E8); + NotifyMotionArgs motionArgs(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/, + downTime /*eventTime*/, readTime, + fdp.ConsumeIntegral<int32_t>() /*deviceId*/, AINPUT_SOURCE_ANY, + ADISPLAY_ID_DEFAULT, + fdp.ConsumeIntegral<uint32_t>() /*policyFlags*/, + AMOTION_EVENT_ACTION_DOWN, + fdp.ConsumeIntegral<int32_t>() /*actionButton*/, + fdp.ConsumeIntegral<int32_t>() /*flags*/, AMETA_NONE, + fdp.ConsumeIntegral<int32_t>() /*buttonState*/, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + 1 /*pointerCount*/, &properties, &coords, + fdp.ConsumeFloatingPoint<float>() /*xPrecision*/, + fdp.ConsumeFloatingPoint<float>() /*yPrecision*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, + {} /*videoFrames*/); + return motionArgs; +} + +extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { + FuzzedDataProvider fdp(data, size); + + std::unique_ptr<FuzzInputListener> mFuzzListener = std::make_unique<FuzzInputListener>(); + std::unique_ptr<InputProcessorInterface> mClassifier = + std::make_unique<InputProcessor>(*mFuzzListener); + + while (fdp.remaining_bytes() > 0) { + fdp.PickValueInArray<std::function<void()>>({ + [&]() -> void { + // SendToNextStage_NotifyConfigurationChangedArgs + NotifyConfigurationChangedArgs + args(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/, + fdp.ConsumeIntegral<nsecs_t>() /*eventTime*/); + mClassifier->notifyConfigurationChanged(&args); + }, + [&]() -> void { + // SendToNextStage_NotifyKeyArgs + const nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>(); + const nsecs_t readTime = + eventTime + fdp.ConsumeIntegralInRange<nsecs_t>(0, 1E8); + NotifyKeyArgs keyArgs(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/, + eventTime, readTime, + fdp.ConsumeIntegral<int32_t>() /*deviceId*/, + AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, + fdp.ConsumeIntegral<uint32_t>() /*policyFlags*/, + AKEY_EVENT_ACTION_DOWN, + fdp.ConsumeIntegral<int32_t>() /*flags*/, AKEYCODE_HOME, + fdp.ConsumeIntegral<int32_t>() /*scanCode*/, AMETA_NONE, + fdp.ConsumeIntegral<nsecs_t>() /*downTime*/); + + mClassifier->notifyKey(&keyArgs); + }, + [&]() -> void { + // SendToNextStage_NotifyMotionArgs + NotifyMotionArgs motionArgs = generateFuzzedMotionArgs(fdp); + mClassifier->notifyMotion(&motionArgs); + }, + [&]() -> void { + // SendToNextStage_NotifySwitchArgs + NotifySwitchArgs switchArgs(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/, + fdp.ConsumeIntegral<nsecs_t>() /*eventTime*/, + fdp.ConsumeIntegral<uint32_t>() /*policyFlags*/, + fdp.ConsumeIntegral<uint32_t>() /*switchValues*/, + fdp.ConsumeIntegral<uint32_t>() /*switchMask*/); + + mClassifier->notifySwitch(&switchArgs); + }, + [&]() -> void { + // SendToNextStage_NotifyDeviceResetArgs + NotifyDeviceResetArgs resetArgs(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/, + fdp.ConsumeIntegral<nsecs_t>() /*eventTime*/, + fdp.ConsumeIntegral<int32_t>() /*deviceId*/); + + mClassifier->notifyDeviceReset(&resetArgs); + }, + [&]() -> void { + // InputClassifierConverterTest + const NotifyMotionArgs motionArgs = generateFuzzedMotionArgs(fdp); + aidl::android::hardware::input::common::MotionEvent motionEvent = + notifyMotionArgsToHalMotionEvent(motionArgs); + }, + })(); + } + return 0; +} + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp new file mode 100644 index 0000000000..a9f5a3ac86 --- /dev/null +++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp @@ -0,0 +1,283 @@ +/* + * 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 <InputReader.h> +#include <MapperHelpers.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <input/InputDevice.h> +#include <chrono> +#include <thread> + +namespace android { + +constexpr InputDeviceSensorType kInputDeviceSensorType[] = { + InputDeviceSensorType::ACCELEROMETER, + InputDeviceSensorType::MAGNETIC_FIELD, + InputDeviceSensorType::ORIENTATION, + InputDeviceSensorType::GYROSCOPE, + InputDeviceSensorType::LIGHT, + InputDeviceSensorType::PRESSURE, + InputDeviceSensorType::TEMPERATURE, + InputDeviceSensorType::PROXIMITY, + InputDeviceSensorType::GRAVITY, + InputDeviceSensorType::LINEAR_ACCELERATION, + InputDeviceSensorType::ROTATION_VECTOR, + InputDeviceSensorType::RELATIVE_HUMIDITY, + InputDeviceSensorType::AMBIENT_TEMPERATURE, + InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED, + InputDeviceSensorType::GAME_ROTATION_VECTOR, + InputDeviceSensorType::GYROSCOPE_UNCALIBRATED, + InputDeviceSensorType::SIGNIFICANT_MOTION, +}; + +class FuzzInputReader : public InputReaderInterface { +public: + FuzzInputReader(std::shared_ptr<EventHubInterface> fuzzEventHub, + const sp<InputReaderPolicyInterface>& fuzzPolicy, + InputListenerInterface& fuzzListener) { + reader = std::make_unique<InputReader>(fuzzEventHub, fuzzPolicy, fuzzListener); + } + + void dump(std::string& dump) { reader->dump(dump); } + + void monitor() { reader->monitor(); } + + bool isInputDeviceEnabled(int32_t deviceId) { return reader->isInputDeviceEnabled(deviceId); } + + status_t start() { return reader->start(); } + + status_t stop() { return reader->stop(); } + + std::vector<InputDeviceInfo> getInputDevices() const { return reader->getInputDevices(); } + + int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) { + return reader->getScanCodeState(deviceId, sourceMask, scanCode); + } + + int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) { + return reader->getKeyCodeState(deviceId, sourceMask, keyCode); + } + + int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) { + return reader->getSwitchState(deviceId, sourceMask, sw); + } + + void toggleCapsLockState(int32_t deviceId) { reader->toggleCapsLockState(deviceId); } + + bool hasKeys(int32_t deviceId, uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { + return reader->hasKeys(deviceId, sourceMask, keyCodes, outFlags); + } + + void requestRefreshConfiguration(uint32_t changes) { + reader->requestRefreshConfiguration(changes); + } + + void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat, + int32_t token) { + reader->vibrate(deviceId, sequence, repeat, token); + } + + void cancelVibrate(int32_t deviceId, int32_t token) { reader->cancelVibrate(deviceId, token); } + + bool isVibrating(int32_t deviceId) { return reader->isVibrating(deviceId); } + + std::vector<int32_t> getVibratorIds(int32_t deviceId) { + return reader->getVibratorIds(deviceId); + } + + std::optional<int32_t> getBatteryCapacity(int32_t deviceId) { + return reader->getBatteryCapacity(deviceId); + } + + std::optional<int32_t> getBatteryStatus(int32_t deviceId) { + return reader->getBatteryStatus(deviceId); + } + + std::optional<std::string> getBatteryDevicePath(int32_t deviceId) { + return reader->getBatteryDevicePath(deviceId); + } + + std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) { + return reader->getLights(deviceId); + } + + std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) { + return reader->getSensors(deviceId); + } + + bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) { + return reader->canDispatchToDisplay(deviceId, displayId); + } + + bool enableSensor(int32_t deviceId, InputDeviceSensorType sensorType, + std::chrono::microseconds samplingPeriod, + std::chrono::microseconds maxBatchReportLatency) { + return reader->enableSensor(deviceId, sensorType, samplingPeriod, maxBatchReportLatency); + } + + void disableSensor(int32_t deviceId, InputDeviceSensorType sensorType) { + return reader->disableSensor(deviceId, sensorType); + } + + void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) { + return reader->flushSensor(deviceId, sensorType); + } + + bool setLightColor(int32_t deviceId, int32_t lightId, int32_t color) { + return reader->setLightColor(deviceId, lightId, color); + } + + bool setLightPlayerId(int32_t deviceId, int32_t lightId, int32_t playerId) { + return reader->setLightPlayerId(deviceId, lightId, playerId); + } + + std::optional<int32_t> getLightColor(int32_t deviceId, int32_t lightId) { + return reader->getLightColor(deviceId, lightId); + } + + std::optional<int32_t> getLightPlayerId(int32_t deviceId, int32_t lightId) { + return reader->getLightPlayerId(deviceId, lightId); + } + + int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const { + return reader->getKeyCodeForKeyLocation(deviceId, locationKeyCode); + } + +private: + std::unique_ptr<InputReaderInterface> reader; +}; + +extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { + std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size); + + FuzzInputListener fuzzListener; + sp<FuzzInputReaderPolicy> fuzzPolicy = sp<FuzzInputReaderPolicy>::make(fdp); + std::shared_ptr<FuzzEventHub> fuzzEventHub = std::make_shared<FuzzEventHub>(fdp); + std::unique_ptr<FuzzInputReader> reader = + std::make_unique<FuzzInputReader>(fuzzEventHub, fuzzPolicy, fuzzListener); + size_t patternCount = fdp->ConsumeIntegralInRange<size_t>(1, 260); + VibrationSequence pattern(patternCount); + for (size_t i = 0; i < patternCount; ++i) { + VibrationElement element(i); + element.addChannel(fdp->ConsumeIntegral<int32_t>() /* vibratorId */, + fdp->ConsumeIntegral<uint8_t>() /* amplitude */); + pattern.addElement(element); + } + reader->vibrate(fdp->ConsumeIntegral<int32_t>(), pattern, + fdp->ConsumeIntegral<ssize_t>() /*repeat*/, + fdp->ConsumeIntegral<int32_t>() /*token*/); + reader->start(); + + // Loop through mapper operations until randomness is exhausted. + while (fdp->remaining_bytes() > 0) { + fdp->PickValueInArray<std::function<void()>>({ + [&]() -> void { + std::string dump; + reader->dump(dump); + }, + [&]() -> void { reader->monitor(); }, + [&]() -> void { reader->getInputDevices(); }, + [&]() -> void { reader->isInputDeviceEnabled(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { + reader->getScanCodeState(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + reader->getKeyCodeState(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + reader->getSwitchState(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { reader->toggleCapsLockState(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { + size_t count = fdp->ConsumeIntegralInRange<size_t>(1, 1024); + std::vector<uint8_t> outFlags(count); + std::vector<int32_t> keyCodes; + for (size_t i = 0; i < count; ++i) { + keyCodes.push_back(fdp->ConsumeIntegral<int32_t>()); + } + reader->hasKeys(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<uint32_t>(), keyCodes, outFlags.data()); + }, + [&]() -> void { + reader->requestRefreshConfiguration(fdp->ConsumeIntegral<uint32_t>()); + }, + [&]() -> void { + reader->cancelVibrate(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + reader->canDispatchToDisplay(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + reader->getKeyCodeForKeyLocation(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { reader->getBatteryCapacity(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { reader->getBatteryStatus(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { reader->getBatteryDevicePath(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { reader->getLights(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { reader->getSensors(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { + reader->getLightPlayerId(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + reader->getLightColor(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + reader->setLightPlayerId(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + reader->setLightColor(fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + reader->flushSensor(fdp->ConsumeIntegral<int32_t>(), + fdp->PickValueInArray<InputDeviceSensorType>( + kInputDeviceSensorType)); + }, + [&]() -> void { + reader->disableSensor(fdp->ConsumeIntegral<int32_t>(), + fdp->PickValueInArray<InputDeviceSensorType>( + kInputDeviceSensorType)); + }, + [&]() -> void { + reader->enableSensor(fdp->ConsumeIntegral<int32_t>(), + fdp->PickValueInArray<InputDeviceSensorType>( + kInputDeviceSensorType), + std::chrono::microseconds(fdp->ConsumeIntegral<size_t>()), + std::chrono::microseconds(fdp->ConsumeIntegral<size_t>())); + }, + })(); + } + + reader->stop(); + return 0; +} + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp new file mode 100644 index 0000000000..c48a099bca --- /dev/null +++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp @@ -0,0 +1,110 @@ +/* + * 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 <FuzzContainer.h> +#include <KeyboardInputMapper.h> +#include <fuzzer/FuzzedDataProvider.h> + +namespace android { + +const int32_t kMaxKeycodes = 100; + +static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) { + // Pick a random property to set for the mapper to have set. + fdp->PickValueInArray<std::function<void()>>( + {[&]() -> void { fuzzer.addProperty("keyboard.orientationAware", "1"); }, + [&]() -> void { + fuzzer.addProperty("keyboard.orientationAware", + fdp->ConsumeRandomLengthString(100).data()); + }, + [&]() -> void { + fuzzer.addProperty("keyboard.doNotWakeByDefault", + fdp->ConsumeRandomLengthString(100).data()); + }, + [&]() -> void { + fuzzer.addProperty("keyboard.handlesKeyRepeat", + fdp->ConsumeRandomLengthString(100).data()); + }})(); +} + +extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { + std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size); + FuzzContainer fuzzer(fdp); + + KeyboardInputMapper& mapper = + fuzzer.getMapper<KeyboardInputMapper>(fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + auto policyConfig = fuzzer.getPolicyConfig(); + + // Loop through mapper operations until randomness is exhausted. + while (fdp->remaining_bytes() > 0) { + fdp->PickValueInArray<std::function<void()>>({ + [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + std::string dump; + mapper.dump(dump); + }, + [&]() -> void { + InputDeviceInfo info; + mapper.populateDeviceInfo(&info); + }, + [&]() -> void { mapper.getSources(); }, + [&]() -> void { + mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, + fdp->ConsumeIntegral<uint32_t>()); + }, + [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); }, + [&]() -> void { + int32_t type, code; + type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes) + : fdp->ConsumeIntegral<int32_t>(); + code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes) + : fdp->ConsumeIntegral<int32_t>(); + RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<int32_t>(), + type, + code, + fdp->ConsumeIntegral<int32_t>()}; + mapper.process(&rawEvent); + }, + [&]() -> void { + mapper.getKeyCodeState(fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + std::vector<int32_t> keyCodes; + int32_t numBytes = fdp->ConsumeIntegralInRange<int32_t>(0, kMaxKeycodes); + for (int32_t i = 0; i < numBytes; ++i) { + keyCodes.push_back(fdp->ConsumeIntegral<int32_t>()); + } + mapper.markSupportedKeyCodes(fdp->ConsumeIntegral<uint32_t>(), keyCodes, + nullptr); + }, + [&]() -> void { mapper.getMetaState(); }, + [&]() -> void { mapper.updateMetaState(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { mapper.getAssociatedDisplayId(); }, + })(); + } + + return 0; +} + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp index 4f066ad513..72780fb363 100644 --- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp @@ -42,7 +42,7 @@ static sp<IBinder> getConnectionToken(FuzzedDataProvider& fdp, if (useExistingToken) { return tokens[fdp.ConsumeIntegralInRange<size_t>(0ul, tokens.size() - 1)]; } - return new BBinder(); + return sp<BBinder>::make(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { @@ -54,7 +54,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { // Make some pre-defined tokens to ensure that some timelines are complete. std::array<sp<IBinder> /*token*/, 10> predefinedTokens; for (size_t i = 0; i < predefinedTokens.size(); i++) { - predefinedTokens[i] = new BBinder(); + predefinedTokens[i] = sp<BBinder>::make(); } // Randomly invoke LatencyTracker api's until randomness is exhausted. diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h new file mode 100644 index 0000000000..03c226600e --- /dev/null +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -0,0 +1,368 @@ +/* + * 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. + */ + +#pragma once + +#include <InputDevice.h> +#include <InputMapper.h> +#include <InputReader.h> +#include <fuzzer/FuzzedDataProvider.h> +#include "android/hardware/input/InputDeviceCountryCode.h" + +using android::hardware::input::InputDeviceCountryCode; + +constexpr size_t kValidTypes[] = {EV_SW, + EV_SYN, + SYN_REPORT, + EV_ABS, + EV_KEY, + EV_MSC, + EV_REL, + android::EventHubInterface::DEVICE_ADDED, + android::EventHubInterface::DEVICE_REMOVED, + android::EventHubInterface::FINISHED_DEVICE_SCAN}; + +constexpr size_t kValidCodes[] = { + SYN_REPORT, + ABS_MT_SLOT, + SYN_MT_REPORT, + ABS_MT_POSITION_X, + ABS_MT_POSITION_Y, + ABS_MT_TOUCH_MAJOR, + ABS_MT_TOUCH_MINOR, + ABS_MT_WIDTH_MAJOR, + ABS_MT_WIDTH_MINOR, + ABS_MT_ORIENTATION, + ABS_MT_TRACKING_ID, + ABS_MT_PRESSURE, + ABS_MT_DISTANCE, + ABS_MT_TOOL_TYPE, + SYN_MT_REPORT, + MSC_SCAN, + REL_X, + REL_Y, + REL_WHEEL, + REL_HWHEEL, + BTN_LEFT, + BTN_RIGHT, + BTN_MIDDLE, + BTN_BACK, + BTN_SIDE, + BTN_FORWARD, + BTN_EXTRA, + BTN_TASK, +}; + +constexpr InputDeviceCountryCode kCountryCodes[] = { + InputDeviceCountryCode::INVALID, + InputDeviceCountryCode::NOT_SUPPORTED, + InputDeviceCountryCode::ARABIC, + InputDeviceCountryCode::BELGIAN, + InputDeviceCountryCode::CANADIAN_BILINGUAL, + InputDeviceCountryCode::CANADIAN_FRENCH, + InputDeviceCountryCode::CZECH_REPUBLIC, + InputDeviceCountryCode::DANISH, + InputDeviceCountryCode::FINNISH, + InputDeviceCountryCode::FRENCH, + InputDeviceCountryCode::GERMAN, + InputDeviceCountryCode::GREEK, + InputDeviceCountryCode::HEBREW, + InputDeviceCountryCode::HUNGARY, + InputDeviceCountryCode::INTERNATIONAL, + InputDeviceCountryCode::ITALIAN, + InputDeviceCountryCode::JAPAN, + InputDeviceCountryCode::KOREAN, + InputDeviceCountryCode::LATIN_AMERICAN, + InputDeviceCountryCode::DUTCH, + InputDeviceCountryCode::NORWEGIAN, + InputDeviceCountryCode::PERSIAN, + InputDeviceCountryCode::POLAND, + InputDeviceCountryCode::PORTUGUESE, + InputDeviceCountryCode::RUSSIA, + InputDeviceCountryCode::SLOVAKIA, + InputDeviceCountryCode::SPANISH, + InputDeviceCountryCode::SWEDISH, + InputDeviceCountryCode::SWISS_FRENCH, + InputDeviceCountryCode::SWISS_GERMAN, + InputDeviceCountryCode::SWITZERLAND, + InputDeviceCountryCode::TAIWAN, + InputDeviceCountryCode::TURKISH_Q, + InputDeviceCountryCode::UK, + InputDeviceCountryCode::US, + InputDeviceCountryCode::YUGOSLAVIA, + InputDeviceCountryCode::TURKISH_F, +}; + +constexpr size_t kMaxSize = 256; + +namespace android { + +class FuzzEventHub : public EventHubInterface { + InputDeviceIdentifier mIdentifier; + std::vector<TouchVideoFrame> mVideoFrames; + PropertyMap mFuzzConfig; + std::shared_ptr<FuzzedDataProvider> mFdp; + +public: + FuzzEventHub(std::shared_ptr<FuzzedDataProvider> fdp) : mFdp(std::move(fdp)) {} + ~FuzzEventHub() {} + void addProperty(std::string key, std::string value) { mFuzzConfig.addProperty(key, value); } + + ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override { + return ftl::Flags<InputDeviceClass>(mFdp->ConsumeIntegral<uint32_t>()); + } + InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override { + return mIdentifier; + } + int32_t getDeviceControllerNumber(int32_t deviceId) const override { + return mFdp->ConsumeIntegral<int32_t>(); + } + void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override { + *outConfiguration = mFuzzConfig; + } + status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, + RawAbsoluteAxisInfo* outAxisInfo) const override { + return mFdp->ConsumeIntegral<status_t>(); + } + bool hasRelativeAxis(int32_t deviceId, int axis) const override { return mFdp->ConsumeBool(); } + bool hasInputProperty(int32_t deviceId, int property) const override { + return mFdp->ConsumeBool(); + } + bool hasMscEvent(int32_t deviceId, int mscEvent) const override { return mFdp->ConsumeBool(); } + status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, + int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override { + return mFdp->ConsumeIntegral<status_t>(); + } + status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const override { + return mFdp->ConsumeIntegral<status_t>(); + } + void setExcludedDevices(const std::vector<std::string>& devices) override {} + std::vector<RawEvent> getEvents(int timeoutMillis) override { + std::vector<RawEvent> events; + const size_t count = mFdp->ConsumeIntegralInRange<size_t>(0, kMaxSize); + for (size_t i = 0; i < count; ++i) { + int32_t type = mFdp->ConsumeBool() ? mFdp->PickValueInArray(kValidTypes) + : mFdp->ConsumeIntegral<int32_t>(); + int32_t code = mFdp->ConsumeBool() ? mFdp->PickValueInArray(kValidCodes) + : mFdp->ConsumeIntegral<int32_t>(); + events.push_back({ + .when = mFdp->ConsumeIntegral<nsecs_t>(), + .readTime = mFdp->ConsumeIntegral<nsecs_t>(), + .deviceId = mFdp->ConsumeIntegral<int32_t>(), + .type = type, + .code = code, + .value = mFdp->ConsumeIntegral<int32_t>(), + }); + } + return events; + } + std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override { return mVideoFrames; } + + base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor( + int32_t deviceId, int32_t absCode) const override { + return base::ResultError("Fuzzer", UNKNOWN_ERROR); + }; + // Raw batteries are sysfs power_supply nodes we found from the EventHub device sysfs node, + // containing the raw info of the sysfs node structure. + std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override { return {}; } + std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, + int32_t BatteryId) const override { + return std::nullopt; + }; + + std::vector<int32_t> getRawLightIds(int32_t deviceId) const override { return {}; }; + std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) const override { + return std::nullopt; + }; + std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override { + return std::nullopt; + }; + void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override{}; + std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( + int32_t deviceId, int32_t lightId) const override { + return std::nullopt; + }; + void setLightIntensities(int32_t deviceId, int32_t lightId, + std::unordered_map<LightColor, int32_t> intensities) override{}; + + InputDeviceCountryCode getCountryCode(int32_t deviceId) const override { + return mFdp->PickValueInArray<InputDeviceCountryCode>(kCountryCodes); + }; + + int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override { + return mFdp->ConsumeIntegral<int32_t>(); + } + int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override { + return mFdp->ConsumeIntegral<int32_t>(); + } + int32_t getSwitchState(int32_t deviceId, int32_t sw) const override { + return mFdp->ConsumeIntegral<int32_t>(); + } + int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override { + return mFdp->ConsumeIntegral<int32_t>(); + } + status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, + int32_t* outValue) const override { + return mFdp->ConsumeIntegral<status_t>(); + } + bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) const override { + return mFdp->ConsumeBool(); + } + bool hasScanCode(int32_t deviceId, int32_t scanCode) const override { + return mFdp->ConsumeBool(); + } + bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override { + return mFdp->ConsumeBool(); + } + bool hasLed(int32_t deviceId, int32_t led) const override { return mFdp->ConsumeBool(); } + void setLedState(int32_t deviceId, int32_t led, bool on) override {} + void getVirtualKeyDefinitions( + int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override {} + const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const override { + return nullptr; + } + bool setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) override { + return mFdp->ConsumeBool(); + } + void vibrate(int32_t deviceId, const VibrationElement& effect) override {} + void cancelVibrate(int32_t deviceId) override {} + + std::vector<int32_t> getVibratorIds(int32_t deviceId) const override { return {}; }; + + /* Query battery level. */ + std::optional<int32_t> getBatteryCapacity(int32_t deviceId, int32_t batteryId) const override { + return std::nullopt; + }; + + /* Query battery status. */ + std::optional<int32_t> getBatteryStatus(int32_t deviceId, int32_t batteryId) const override { + return std::nullopt; + }; + + void requestReopenDevices() override {} + void wake() override {} + void dump(std::string& dump) const override {} + void monitor() const override {} + bool isDeviceEnabled(int32_t deviceId) const override { return mFdp->ConsumeBool(); } + status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); } + status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); } +}; + +class FuzzPointerController : public PointerControllerInterface { + std::shared_ptr<FuzzedDataProvider> mFdp; + +public: + FuzzPointerController(std::shared_ptr<FuzzedDataProvider> mFdp) : mFdp(mFdp) {} + ~FuzzPointerController() {} + bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override { + return mFdp->ConsumeBool(); + } + void move(float deltaX, float deltaY) override {} + void setButtonState(int32_t buttonState) override {} + int32_t getButtonState() const override { return mFdp->ConsumeIntegral<int32_t>(); } + void setPosition(float x, float y) override {} + void getPosition(float* outX, float* outY) const override {} + void fade(Transition transition) override {} + void unfade(Transition transition) override {} + void setPresentation(Presentation presentation) override {} + void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits, int32_t displayId) override {} + void clearSpots() override {} + int32_t getDisplayId() const override { return mFdp->ConsumeIntegral<int32_t>(); } + void setDisplayViewport(const DisplayViewport& displayViewport) override {} +}; + +class FuzzInputReaderPolicy : public InputReaderPolicyInterface { + TouchAffineTransformation mTransform; + std::shared_ptr<FuzzPointerController> mPointerController; + std::shared_ptr<FuzzedDataProvider> mFdp; + +protected: + ~FuzzInputReaderPolicy() {} + +public: + FuzzInputReaderPolicy(std::shared_ptr<FuzzedDataProvider> mFdp) : mFdp(mFdp) { + mPointerController = std::make_shared<FuzzPointerController>(mFdp); + } + void getReaderConfiguration(InputReaderConfiguration* outConfig) override {} + std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override { + return mPointerController; + } + void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {} + std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( + const InputDeviceIdentifier& identifier) override { + return nullptr; + } + std::string getDeviceAlias(const InputDeviceIdentifier& identifier) { + return mFdp->ConsumeRandomLengthString(32); + } + TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor, + int32_t surfaceRotation) override { + return mTransform; + } + void setTouchAffineTransformation(const TouchAffineTransformation t) { mTransform = t; } +}; + +class FuzzInputListener : public virtual InputListenerInterface { +public: + void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override {} + void notifyKey(const NotifyKeyArgs* args) override {} + void notifyMotion(const NotifyMotionArgs* args) override {} + void notifySwitch(const NotifySwitchArgs* args) override {} + void notifySensor(const NotifySensorArgs* args) override{}; + void notifyVibratorState(const NotifyVibratorStateArgs* args) override{}; + void notifyDeviceReset(const NotifyDeviceResetArgs* args) override {} + void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override{}; +}; + +class FuzzInputReaderContext : public InputReaderContext { + std::shared_ptr<EventHubInterface> mEventHub; + sp<InputReaderPolicyInterface> mPolicy; + InputListenerInterface& mListener; + std::shared_ptr<FuzzedDataProvider> mFdp; + +public: + FuzzInputReaderContext(std::shared_ptr<EventHubInterface> eventHub, + const sp<InputReaderPolicyInterface>& policy, + InputListenerInterface& listener, + std::shared_ptr<FuzzedDataProvider> mFdp) + : mEventHub(eventHub), mPolicy(policy), mListener(listener), mFdp(mFdp) {} + ~FuzzInputReaderContext() {} + void updateGlobalMetaState() override {} + int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); } + void disableVirtualKeysUntil(nsecs_t time) override {} + bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override { + return mFdp->ConsumeBool(); + } + void fadePointer() override {} + std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) override { + return mPolicy->obtainPointerController(0); + } + void requestTimeoutAtTime(nsecs_t when) override {} + int32_t bumpGeneration() override { return mFdp->ConsumeIntegral<int32_t>(); } + void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override {} + void dispatchExternalStylusState(const StylusState& outState) override {} + InputReaderPolicyInterface* getPolicy() override { return mPolicy.get(); } + InputListenerInterface& getListener() override { return mListener; } + EventHubInterface* getEventHub() override { return mEventHub.get(); } + int32_t getNextId() override { return mFdp->ConsumeIntegral<int32_t>(); } + + void updateLedMetaState(int32_t metaState) override{}; + int32_t getLedMetaState() override { return mFdp->ConsumeIntegral<int32_t>(); }; +}; + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp new file mode 100644 index 0000000000..59b064249a --- /dev/null +++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp @@ -0,0 +1,134 @@ +/* + * 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 <FuzzContainer.h> +#include <MultiTouchInputMapper.h> +#include <fuzzer/FuzzedDataProvider.h> + +namespace android { + +const int32_t kMaxKeycodes = 100; + +static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) { + // Pick a random property to set for the mapper to have set. + fdp->PickValueInArray<std::function<void()>>( + {[&]() -> void { fuzzer.addProperty("touch.deviceType", "touchScreen"); }, + [&]() -> void { + fuzzer.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data()); + }, + [&]() -> void { + fuzzer.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data()); + }, + [&]() -> void { + fuzzer.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data()); + }, + [&]() -> void { + fuzzer.addProperty("touch.size.isSummed", + fdp->ConsumeRandomLengthString(8).data()); + }, + [&]() -> void { + fuzzer.addProperty("touch.size.calibration", + fdp->ConsumeRandomLengthString(8).data()); + }, + [&]() -> void { + fuzzer.addProperty("touch.pressure.scale", + fdp->ConsumeRandomLengthString(8).data()); + }, + [&]() -> void { + fuzzer.addProperty("touch.size.calibration", + fdp->ConsumeBool() ? "diameter" : "area"); + }, + [&]() -> void { + fuzzer.addProperty("touch.pressure.calibration", + fdp->ConsumeRandomLengthString(8).data()); + }})(); +} + +extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { + std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size); + FuzzContainer fuzzer(fdp); + + MultiTouchInputMapper& mapper = fuzzer.getMapper<MultiTouchInputMapper>(); + auto policyConfig = fuzzer.getPolicyConfig(); + + // Loop through mapper operations until randomness is exhausted. + while (fdp->remaining_bytes() > 0) { + fdp->PickValueInArray<std::function<void()>>({ + [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + std::string dump; + mapper.dump(dump); + }, + [&]() -> void { + InputDeviceInfo info; + mapper.populateDeviceInfo(&info); + }, + [&]() -> void { mapper.getSources(); }, + [&]() -> void { + mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, + fdp->ConsumeIntegral<uint32_t>()); + }, + [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); }, + [&]() -> void { + int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes) + : fdp->ConsumeIntegral<int32_t>(); + int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes) + : fdp->ConsumeIntegral<int32_t>(); + RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<int32_t>(), + type, + code, + fdp->ConsumeIntegral<int32_t>()}; + mapper.process(&rawEvent); + }, + [&]() -> void { + mapper.getKeyCodeState(fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + [&]() -> void { + std::vector<int32_t> keyCodes; + int32_t numBytes = fdp->ConsumeIntegralInRange<int32_t>(0, kMaxKeycodes); + for (int32_t i = 0; i < numBytes; ++i) { + keyCodes.push_back(fdp->ConsumeIntegral<int32_t>()); + } + mapper.markSupportedKeyCodes(fdp->ConsumeIntegral<uint32_t>(), keyCodes, + nullptr); + }, + [&]() -> void { + mapper.cancelTouch(fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<nsecs_t>()); + }, + [&]() -> void { mapper.timeoutExpired(fdp->ConsumeIntegral<nsecs_t>()); }, + [&]() -> void { + StylusState state{fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeFloatingPoint<float>(), + fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()}; + mapper.updateExternalStylusState(state); + }, + [&]() -> void { mapper.getAssociatedDisplayId(); }, + })(); + } + + return 0; +} + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp new file mode 100644 index 0000000000..e76bd728b8 --- /dev/null +++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp @@ -0,0 +1,61 @@ +/* + * 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 <FuzzContainer.h> +#include <SwitchInputMapper.h> +#include <fuzzer/FuzzedDataProvider.h> + +namespace android { + +extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { + std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size); + FuzzContainer fuzzer(fdp); + + SwitchInputMapper& mapper = fuzzer.getMapper<SwitchInputMapper>(); + auto policyConfig = fuzzer.getPolicyConfig(); + + // Loop through mapper operations until randomness is exhausted. + while (fdp->remaining_bytes() > 0) { + fdp->PickValueInArray<std::function<void()>>({ + [&]() -> void { + std::string dump; + mapper.dump(dump); + }, + [&]() -> void { mapper.getSources(); }, + [&]() -> void { + int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes) + : fdp->ConsumeIntegral<int32_t>(); + int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes) + : fdp->ConsumeIntegral<int32_t>(); + RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<nsecs_t>(), + fdp->ConsumeIntegral<int32_t>(), + type, + code, + fdp->ConsumeIntegral<int32_t>()}; + mapper.process(&rawEvent); + }, + [&]() -> void { + mapper.getSwitchState(fdp->ConsumeIntegral<uint32_t>(), + fdp->ConsumeIntegral<int32_t>()); + }, + })(); + } + + return 0; +} + +} // namespace android diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index 3c4f8d9bae..5ad4815a89 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -7,7 +7,7 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library_shared { +cc_library { name: "libsensorservice", srcs: [ @@ -90,6 +90,12 @@ cc_library_shared { afdo: true, } +cc_library_headers { + name: "libsensorservice_headers", + export_include_dirs: ["."], + visibility: ["//frameworks/native/services/sensorservice/fuzzer"], +} + cc_binary { name: "sensorservice", diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index de050e02d0..10ca990f87 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -39,7 +39,6 @@ #include <thread> using namespace android::hardware::sensors; -using android::hardware::Return; using android::util::ProtoOutputStream; namespace android { diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp index 2dd12e9446..291c770692 100644 --- a/services/sensorservice/SensorDirectConnection.cpp +++ b/services/sensorservice/SensorDirectConnection.cpp @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "SensorDevice.h" #include "SensorDirectConnection.h" #include <android/util/ProtoOutputStream.h> #include <frameworks/base/core/proto/android/service/sensor_service.proto.h> #include <hardware/sensors.h> +#include "SensorDevice.h" #define UNUSED(x) (void)(x) @@ -51,7 +51,7 @@ void SensorService::SensorDirectConnection::destroy() { stopAll(); mService->cleanupConnection(this); if (mMem.handle != nullptr) { - native_handle_close(mMem.handle); + native_handle_close_with_tag(mMem.handle); native_handle_delete(const_cast<struct native_handle*>(mMem.handle)); } mDestroyed = true; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index e0a4f034cb..21d6b6b16f 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -16,7 +16,6 @@ #include <android-base/strings.h> #include <android/content/pm/IPackageManagerNative.h> #include <android/util/ProtoOutputStream.h> -#include <frameworks/base/core/proto/android/service/sensor_service.proto.h> #include <binder/ActivityManager.h> #include <binder/BinderService.h> #include <binder/IServiceManager.h> @@ -25,6 +24,7 @@ #include <cutils/ashmem.h> #include <cutils/misc.h> #include <cutils/properties.h> +#include <frameworks/base/core/proto/android/service/sensor_service.proto.h> #include <hardware/sensors.h> #include <hardware_legacy/power.h> #include <log/log.h> @@ -1475,6 +1475,7 @@ sp<ISensorEventConnection> SensorService::createSensorDirectConnection( if (!clone) { return nullptr; } + native_handle_set_fdsan_tag(clone); sp<SensorDirectConnection> conn; SensorDevice& dev(SensorDevice::getInstance()); @@ -1488,7 +1489,7 @@ sp<ISensorEventConnection> SensorService::createSensorDirectConnection( } if (conn == nullptr) { - native_handle_close(clone); + native_handle_close_with_tag(clone); native_handle_delete(clone); } else { // add to list of direct connections diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp index caf7f03361..b00d1a761b 100644 --- a/services/sensorservice/tests/sensorservicetest.cpp +++ b/services/sensorservice/tests/sensorservicetest.cpp @@ -89,6 +89,17 @@ void testInvalidSharedMem_NoCrash(SensorManager &mgr) { // Should print -22 (BAD_VALUE) and the device runtime shouldn't restart printf("createInvalidDirectChannel=%d\n", ret); + + // Secondary test: correct channel creation & destruction (should print 0) + ret = mgr.createDirectChannel(kMemSize, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER, + resourceHandle); + printf("createValidDirectChannel=%d\n", ret); + + // Third test: double-destroy (should not crash) + mgr.destroyDirectChannel(ret); + AHardwareBuffer_release(hardwareBuffer); + printf("duplicate destroyDirectChannel...\n"); + mgr.destroyDirectChannel(ret); } int main() { diff --git a/services/stats/Android.bp b/services/stats/Android.bp index 7fea6161ff..7d358e1bd2 100644 --- a/services/stats/Android.bp +++ b/services/stats/Android.bp @@ -13,10 +13,13 @@ cc_library_shared { "StatsAidl.cpp", "StatsHal.cpp", ], - cflags: ["-Wall", "-Werror"], + cflags: [ + "-Wall", + "-Werror", + ], shared_libs: [ "android.frameworks.stats@1.0", - "android.frameworks.stats-V1-ndk", + "android.frameworks.stats-V2-ndk", "libbinder_ndk", "libhidlbase", "liblog", @@ -29,10 +32,12 @@ cc_library_shared { ], export_shared_lib_headers: [ "android.frameworks.stats@1.0", - "android.frameworks.stats-V1-ndk", + "android.frameworks.stats-V2-ndk", ], local_include_dirs: [ "include/stats", ], - vintf_fragments: ["android.frameworks.stats@1.0-service.xml"] + vintf_fragments: [ + "android.frameworks.stats-service.xml", + ], } diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp index a3b68f1dab..3de51a437d 100644 --- a/services/stats/StatsAidl.cpp +++ b/services/stats/StatsAidl.cpp @@ -62,6 +62,65 @@ ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) { AStatsEvent_writeString(event, atomValue.get<VendorAtomValue::stringValue>().c_str()); break; + case VendorAtomValue::boolValue: + AStatsEvent_writeBool(event, + atomValue.get<VendorAtomValue::boolValue>()); + break; + case VendorAtomValue::repeatedIntValue: { + const std::optional<std::vector<int>>& repeatedIntValue = + atomValue.get<VendorAtomValue::repeatedIntValue>(); + AStatsEvent_writeInt32Array(event, repeatedIntValue->data(), + repeatedIntValue->size()); + break; + } + case VendorAtomValue::repeatedLongValue: { + const std::optional<std::vector<int64_t>>& repeatedLongValue = + atomValue.get<VendorAtomValue::repeatedLongValue>(); + AStatsEvent_writeInt64Array(event, repeatedLongValue->data(), + repeatedLongValue->size()); + break; + } + case VendorAtomValue::repeatedFloatValue: { + const std::optional<std::vector<float>>& repeatedFloatValue = + atomValue.get<VendorAtomValue::repeatedFloatValue>(); + AStatsEvent_writeFloatArray(event, repeatedFloatValue->data(), + repeatedFloatValue->size()); + break; + } + case VendorAtomValue::repeatedStringValue: { + const std::optional<std::vector<std::optional<std::string>>>& repeatedStringValue = + atomValue.get<VendorAtomValue::repeatedStringValue>(); + const std::vector<std::optional<std::string>>& repeatedStringVector = + *repeatedStringValue; + const char* cStringArray[repeatedStringVector.size()]; + + for (int i = 0; i < repeatedStringVector.size(); ++i) { + cStringArray[i] = repeatedStringVector[i]->c_str(); + } + + AStatsEvent_writeStringArray(event, cStringArray, repeatedStringVector.size()); + break; + } + case VendorAtomValue::repeatedBoolValue: { + const std::optional<std::vector<bool>>& repeatedBoolValue = + atomValue.get<VendorAtomValue::repeatedBoolValue>(); + const std::vector<bool>& repeatedBoolVector = *repeatedBoolValue; + bool boolArray[repeatedBoolValue->size()]; + + for (int i = 0; i < repeatedBoolVector.size(); ++i) { + boolArray[i] = repeatedBoolVector[i]; + } + + AStatsEvent_writeBoolArray(event, boolArray, repeatedBoolVector.size()); + break; + } + case VendorAtomValue::byteArrayValue: { + const std::optional<std::vector<uint8_t>>& byteArrayValue = + atomValue.get<VendorAtomValue::byteArrayValue>(); + + AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size()); + break; + } } } AStatsEvent_build(event); diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats-service.xml index c564b7be53..7e2635e406 100644 --- a/services/stats/android.frameworks.stats@1.0-service.xml +++ b/services/stats/android.frameworks.stats-service.xml @@ -11,7 +11,7 @@ <hal format="aidl"> <name>android.frameworks.stats</name> - <version>1</version> + <version>2</version> <fqname>IStats/default</fqname> </hal> </manifest> diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index cbb95f963c..b911ae75d4 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -18,12 +18,14 @@ cc_defaults { "-Wunused", "-Wunreachable-code", "-Wconversion", + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", ], } cc_defaults { name: "libsurfaceflinger_defaults", defaults: [ + "android.hardware.graphics.composer3-ndk_shared", "surfaceflinger_defaults", "skia_renderengine_deps", ], @@ -45,7 +47,6 @@ cc_defaults { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.graphics.composer3-V1-ndk", "android.hardware.power@1.0", "android.hardware.power@1.3", "android.hardware.power-V2-cpp", @@ -105,7 +106,6 @@ cc_defaults { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.graphics.composer3-V1-ndk", "android.hardware.power@1.3", "libhidlbase", "libtimestats", @@ -141,21 +141,16 @@ filegroup { name: "libsurfaceflinger_sources", srcs: [ "BackgroundExecutor.cpp", - "BufferLayer.cpp", - "BufferLayerConsumer.cpp", - "BufferQueueLayer.cpp", - "BufferStateLayer.cpp", - "ClientCache.cpp", "Client.cpp", - "EffectLayer.cpp", - "ContainerLayer.cpp", + "ClientCache.cpp", + "Display/DisplaySnapshot.cpp", "DisplayDevice.cpp", "DisplayHardware/AidlComposerHal.cpp", - "DisplayHardware/HidlComposerHal.cpp", "DisplayHardware/ComposerHal.cpp", "DisplayHardware/FramebufferSurface.cpp", "DisplayHardware/HWC2.cpp", "DisplayHardware/HWComposer.cpp", + "DisplayHardware/HidlComposerHal.cpp", "DisplayHardware/PowerAdvisor.cpp", "DisplayHardware/VirtualDisplaySurface.cpp", "DisplayRenderArea.cpp", @@ -166,13 +161,12 @@ filegroup { "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", "HdrLayerInfoReporter.cpp", + "HwcSlotGenerator.cpp", "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerProtoHelper.cpp", - "LayerRejecter.cpp", "LayerRenderArea.cpp", "LayerVector.cpp", - "MonitoredProducer.cpp", "NativeWindowSurface.cpp", "RefreshRateOverlay.cpp", "RegionSamplingThread.cpp", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp deleted file mode 100644 index d9c89cd821..0000000000 --- a/services/surfaceflinger/BufferLayer.cpp +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -//#define LOG_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "BufferLayer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "BufferLayer.h" - -#include <compositionengine/CompositionEngine.h> -#include <compositionengine/LayerFECompositionState.h> -#include <compositionengine/OutputLayer.h> -#include <compositionengine/impl/OutputLayerCompositionState.h> -#include <cutils/compiler.h> -#include <cutils/native_handle.h> -#include <cutils/properties.h> -#include <gui/BufferItem.h> -#include <gui/BufferQueue.h> -#include <gui/GLConsumer.h> -#include <gui/LayerDebugInfo.h> -#include <gui/Surface.h> -#include <renderengine/RenderEngine.h> -#include <ui/DebugUtils.h> -#include <utils/Errors.h> -#include <utils/Log.h> -#include <utils/NativeHandle.h> -#include <utils/StopWatch.h> -#include <utils/Trace.h> - -#include <cmath> -#include <cstdlib> -#include <mutex> -#include <sstream> - -#include "Colorizer.h" -#include "DisplayDevice.h" -#include "FrameTracer/FrameTracer.h" -#include "LayerRejecter.h" -#include "TimeStats/TimeStats.h" - -namespace android { - -using gui::WindowInfo; - -static constexpr float defaultMaxLuminance = 1000.0; - -BufferLayer::BufferLayer(const LayerCreationArgs& args) - : Layer(args), - mTextureName(args.textureName), - mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} { - ALOGV("Creating Layer %s", getDebugName()); - - mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); - - mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; - mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp; -} - -BufferLayer::~BufferLayer() { - if (!isClone()) { - // The original layer and the clone layer share the same texture. Therefore, only one of - // the layers, in this case the original layer, needs to handle the deletion. The original - // layer and the clone should be removed at the same time so there shouldn't be any issue - // with the clone layer trying to use the deleted texture. - mFlinger->deleteTextureAsync(mTextureName); - } - const int32_t layerId = getSequence(); - mFlinger->mTimeStats->onDestroy(layerId); - mFlinger->mFrameTracer->onDestroy(layerId); -} - -void BufferLayer::useSurfaceDamage() { - if (mFlinger->mForceFullDamage) { - surfaceDamageRegion = Region::INVALID_REGION; - } else { - surfaceDamageRegion = mBufferInfo.mSurfaceDamage; - } -} - -void BufferLayer::useEmptyDamage() { - surfaceDamageRegion.clear(); -} - -bool BufferLayer::isOpaque(const Layer::State& s) const { - // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the - // layer's opaque flag. - if ((mSidebandStream == nullptr) && (mBufferInfo.mBuffer == nullptr)) { - return false; - } - - // if the layer has the opaque flag, then we're always opaque, - // otherwise we use the current buffer's format. - return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat()); -} - -bool BufferLayer::canReceiveInput() const { - return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f); -} - -bool BufferLayer::isVisible() const { - return !isHiddenByPolicy() && getAlpha() > 0.0f && - (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr); -} - -bool BufferLayer::isFixedSize() const { - return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE; -} - -bool BufferLayer::usesSourceCrop() const { - return true; -} - -static constexpr mat4 inverseOrientation(uint32_t transform) { - const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); - const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); - const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); - mat4 tr; - - if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - tr = tr * rot90; - } - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - tr = tr * flipH; - } - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - tr = tr * flipV; - } - return inverse(tr); -} - -std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { - ATRACE_CALL(); - - std::optional<compositionengine::LayerFE::LayerSettings> result = - Layer::prepareClientComposition(targetSettings); - if (!result) { - return result; - } - - if (CC_UNLIKELY(mBufferInfo.mBuffer == 0) && mSidebandStream != nullptr) { - // For surfaceview of tv sideband, there is no activeBuffer - // in bufferqueue, we need return LayerSettings. - return result; - } - const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || - ((isSecure() || isProtected()) && !targetSettings.isSecure); - const bool bufferCanBeUsedAsHwTexture = - mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; - compositionengine::LayerFE::LayerSettings& layer = *result; - if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { - ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", - mName.c_str()); - prepareClearClientComposition(layer, true /* blackout */); - return layer; - } - - const State& s(getDrawingState()); - layer.source.buffer.buffer = mBufferInfo.mBuffer; - layer.source.buffer.isOpaque = isOpaque(s); - layer.source.buffer.fence = mBufferInfo.mFence; - layer.source.buffer.textureName = mTextureName; - layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); - layer.source.buffer.isY410BT2020 = isHdrY410(); - bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; - bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; - float maxLuminance = 0.f; - if (hasSmpte2086 && hasCta861_3) { - maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance, - mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel); - } else if (hasSmpte2086) { - maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance; - } else if (hasCta861_3) { - maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel; - } else { - switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - case HAL_DATASPACE_TRANSFER_HLG: - // Behavior-match previous releases for HDR content - maxLuminance = defaultMaxLuminance; - break; - } - } - layer.source.buffer.maxLuminanceNits = maxLuminance; - layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; - - const bool useFiltering = - targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); - - // Query the texture matrix given our current filtering mode. - float textureMatrix[16]; - getDrawingTransformMatrix(useFiltering, textureMatrix); - - if (getTransformToDisplayInverse()) { - /* - * the code below applies the primary display's inverse transform to - * the texture transform - */ - uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags(); - mat4 tr = inverseOrientation(transform); - - /** - * TODO(b/36727915): This is basically a hack. - * - * Ensure that regardless of the parent transformation, - * this buffer is always transformed from native display - * orientation to display orientation. For example, in the case - * of a camera where the buffer remains in native orientation, - * we want the pixels to always be upright. - */ - sp<Layer> p = mDrawingParent.promote(); - if (p != nullptr) { - const auto parentTransform = p->getTransform(); - tr = tr * inverseOrientation(parentTransform.getOrientation()); - } - - // and finally apply it to the original texture matrix - const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr); - memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); - } - - const Rect win{getBounds()}; - float bufferWidth = getBufferSize(s).getWidth(); - float bufferHeight = getBufferSize(s).getHeight(); - - // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has - // been set and there is no parent layer bounds. In that case, the scale is meaningless so - // ignore them. - if (!getBufferSize(s).isValid()) { - bufferWidth = float(win.right) - float(win.left); - bufferHeight = float(win.bottom) - float(win.top); - } - - const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; - const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; - const float translateY = float(win.top) / bufferHeight; - const float translateX = float(win.left) / bufferWidth; - - // Flip y-coordinates because GLConsumer expects OpenGL convention. - mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) * - mat4::translate(vec4(-.5, -.5, 0, 1)) * - mat4::translate(vec4(translateX, translateY, 0, 1)) * - mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0)); - - layer.source.buffer.useTextureFiltering = useFiltering; - layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr; - - return layer; -} - -bool BufferLayer::isHdrY410() const { - // pixel format is HDR Y410 masquerading as RGBA_1010102 - return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ && - mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA && - mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102); -} - -sp<compositionengine::LayerFE> BufferLayer::getCompositionEngineLayerFE() const { - return asLayerFE(); -} - -compositionengine::LayerFECompositionState* BufferLayer::editCompositionState() { - return mCompositionState.get(); -} - -const compositionengine::LayerFECompositionState* BufferLayer::getCompositionState() const { - return mCompositionState.get(); -} - -void BufferLayer::preparePerFrameCompositionState() { - Layer::preparePerFrameCompositionState(); - - // Sideband layers - auto* compositionState = editCompositionState(); - if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) { - compositionState->compositionType = - aidl::android::hardware::graphics::composer3::Composition::SIDEBAND; - return; - } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) { - compositionState->compositionType = - aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION; - } else { - // Normal buffer layers - compositionState->hdrMetadata = mBufferInfo.mHdrMetadata; - compositionState->compositionType = mPotentialCursor - ? aidl::android::hardware::graphics::composer3::Composition::CURSOR - : aidl::android::hardware::graphics::composer3::Composition::DEVICE; - } - - compositionState->buffer = getBuffer(); - compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) - ? 0 - : mBufferInfo.mBufferSlot; - compositionState->acquireFence = mBufferInfo.mFence; - compositionState->frameNumber = mBufferInfo.mFrameNumber; - compositionState->sidebandStreamHasFrame = false; -} - -bool BufferLayer::onPreComposition(nsecs_t) { - return hasReadyFrame(); -} -namespace { -TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { - using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; - using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; - const auto frameRateCompatibility = [frameRate] { - switch (frameRate.type) { - case Layer::FrameRateCompatibility::Default: - return FrameRateCompatibility::Default; - case Layer::FrameRateCompatibility::ExactOrMultiple: - return FrameRateCompatibility::ExactOrMultiple; - default: - return FrameRateCompatibility::Undefined; - } - }(); - - const auto seamlessness = [frameRate] { - switch (frameRate.seamlessness) { - case scheduler::Seamlessness::OnlySeamless: - return Seamlessness::ShouldBeSeamless; - case scheduler::Seamlessness::SeamedAndSeamless: - return Seamlessness::NotRequired; - default: - return Seamlessness::Undefined; - } - }(); - - return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), - .frameRateCompatibility = frameRateCompatibility, - .seamlessness = seamlessness}; -} -} // namespace - -void BufferLayer::onPostComposition(const DisplayDevice* display, - const std::shared_ptr<FenceTime>& glDoneFence, - const std::shared_ptr<FenceTime>& presentFence, - const CompositorTiming& compositorTiming) { - // mFrameLatencyNeeded is true when a new frame was latched for the - // composition. - if (!mBufferInfo.mFrameLatencyNeeded) return; - - // Update mFrameEventHistory. - finalizeFrameEventHistory(glDoneFence, compositorTiming); - - // Update mFrameTracker. - nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; - mFrameTracker.setDesiredPresentTime(desiredPresentTime); - - const int32_t layerId = getSequence(); - mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime); - - const auto outputLayer = findOutputLayerForDisplay(display); - if (outputLayer && outputLayer->requiresClientComposition()) { - nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp; - mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, - clientCompositionTimestamp, - FrameTracer::FrameEvent::FALLBACK_COMPOSITION); - // Update the SurfaceFrames in the drawing state - if (mDrawingState.bufferSurfaceFrameTX) { - mDrawingState.bufferSurfaceFrameTX->setGpuComposition(); - } - for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { - surfaceFrame->setGpuComposition(); - } - } - - std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime; - if (frameReadyFence->isValid()) { - mFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); - } else { - // There was no fence for this frame, so assume that it was ready - // to be presented at the desired present time. - mFrameTracker.setFrameReadyTime(desiredPresentTime); - } - - if (display) { - const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); - const std::optional<Fps> renderRate = - mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); - - const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate); - const auto gameMode = getGameMode(); - - if (presentFence->isValid()) { - mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, - refreshRate, renderRate, vote, gameMode); - mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, - presentFence, - FrameTracer::FrameEvent::PRESENT_FENCE); - mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); - } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); - displayId && mFlinger->getHwComposer().isConnected(*displayId)) { - // The HWC doesn't support present fences, so use the refresh - // timestamp instead. - const nsecs_t actualPresentTime = display->getRefreshTimestamp(); - mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, - refreshRate, renderRate, vote, gameMode); - mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), - mCurrentFrameNumber, actualPresentTime, - FrameTracer::FrameEvent::PRESENT_FENCE); - mFrameTracker.setActualPresentTime(actualPresentTime); - } - } - - mFrameTracker.advanceFrame(); - mBufferInfo.mFrameLatencyNeeded = false; -} - -void BufferLayer::gatherBufferInfo() { - mBufferInfo.mPixelFormat = - !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat(); - mBufferInfo.mFrameLatencyNeeded = true; -} - -bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { - // If this is not a valid vsync for the layer's uid, return and try again later - const bool isVsyncValidForUid = - mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid); - if (!isVsyncValidForUid) { - ATRACE_NAME("!isVsyncValidForUid"); - return false; - } - - // AutoRefresh layers and sideband streams should always be presented - if (getSidebandStreamChanged() || getAutoRefresh()) { - return true; - } - - // If this layer doesn't have a frame is shouldn't be presented - if (!hasFrameUpdate()) { - return false; - } - - // Defer to the derived class to decide whether the next buffer is due for - // presentation. - return isBufferDue(expectedPresentTime); -} - -bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) { - ATRACE_CALL(); - - bool refreshRequired = latchSidebandStream(recomputeVisibleRegions); - - if (refreshRequired) { - return refreshRequired; - } - - // If the head buffer's acquire fence hasn't signaled yet, return and - // try again later - if (!fenceHasSignaled()) { - ATRACE_NAME("!fenceHasSignaled()"); - mFlinger->onLayerUpdate(); - return false; - } - - // Capture the old state of the layer for comparisons later - const State& s(getDrawingState()); - const bool oldOpacity = isOpaque(s); - - BufferInfo oldBufferInfo = mBufferInfo; - - status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime); - if (err != NO_ERROR) { - return false; - } - - err = updateActiveBuffer(); - if (err != NO_ERROR) { - return false; - } - - err = updateFrameNumber(); - if (err != NO_ERROR) { - return false; - } - - gatherBufferInfo(); - - if (oldBufferInfo.mBuffer == nullptr) { - // the first time we receive a buffer, we need to trigger a - // geometry invalidation. - recomputeVisibleRegions = true; - } - - if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) || - (mBufferInfo.mTransform != oldBufferInfo.mTransform) || - (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) || - (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) { - recomputeVisibleRegions = true; - } - - if (oldBufferInfo.mBuffer != nullptr) { - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - if (bufWidth != oldBufferInfo.mBuffer->getWidth() || - bufHeight != oldBufferInfo.mBuffer->getHeight()) { - recomputeVisibleRegions = true; - } - } - - if (oldOpacity != isOpaque(s)) { - recomputeVisibleRegions = true; - } - - return true; -} - -bool BufferLayer::hasReadyFrame() const { - return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh(); -} - -uint32_t BufferLayer::getEffectiveScalingMode() const { - return mBufferInfo.mScaleMode; -} - -bool BufferLayer::isProtected() const { - return (mBufferInfo.mBuffer != nullptr) && - (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); -} - -// As documented in libhardware header, formats in the range -// 0x100 - 0x1FF are specific to the HAL implementation, and -// are known to have no alpha channel -// TODO: move definition for device-specific range into -// hardware.h, instead of using hard-coded values here. -#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) - -bool BufferLayer::getOpacityForFormat(PixelFormat format) { - if (HARDWARE_IS_DEVICE_FORMAT(format)) { - return true; - } - switch (format) { - case PIXEL_FORMAT_RGBA_8888: - case PIXEL_FORMAT_BGRA_8888: - case PIXEL_FORMAT_RGBA_FP16: - case PIXEL_FORMAT_RGBA_1010102: - case PIXEL_FORMAT_R_8: - return false; - } - // in all other case, we have no blending (also for unknown formats) - return true; -} - -bool BufferLayer::needsFiltering(const DisplayDevice* display) const { - const auto outputLayer = findOutputLayerForDisplay(display); - if (outputLayer == nullptr) { - return false; - } - - // We need filtering if the sourceCrop rectangle size does not match the - // displayframe rectangle size (not a 1:1 render) - const auto& compositionState = outputLayer->getState(); - const auto displayFrame = compositionState.displayFrame; - const auto sourceCrop = compositionState.sourceCrop; - return sourceCrop.getHeight() != displayFrame.getHeight() || - sourceCrop.getWidth() != displayFrame.getWidth(); -} - -bool BufferLayer::needsFilteringForScreenshots(const DisplayDevice* display, - const ui::Transform& inverseParentTransform) const { - const auto outputLayer = findOutputLayerForDisplay(display); - if (outputLayer == nullptr) { - return false; - } - - // We need filtering if the sourceCrop rectangle size does not match the - // viewport rectangle size (not a 1:1 render) - const auto& compositionState = outputLayer->getState(); - const ui::Transform& displayTransform = display->getTransform(); - const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse(); - // Undo the transformation of the displayFrame so that we're back into - // layer-stack space. - const Rect frame = inverseTransform.transform(compositionState.displayFrame); - const FloatRect sourceCrop = compositionState.sourceCrop; - - int32_t frameHeight = frame.getHeight(); - int32_t frameWidth = frame.getWidth(); - // If the display transform had a rotational component then undo the - // rotation so that the orientation matches the source crop. - if (displayTransform.getOrientation() & ui::Transform::ROT_90) { - std::swap(frameHeight, frameWidth); - } - return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth; -} - -Rect BufferLayer::getBufferSize(const State& s) const { - // If we have a sideband stream, or we are scaling the buffer then return the layer size since - // we cannot determine the buffer size. - if ((s.sidebandStream != nullptr) || - (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) { - return Rect(getActiveWidth(s), getActiveHeight(s)); - } - - if (mBufferInfo.mBuffer == nullptr) { - return Rect::INVALID_RECT; - } - - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - - // Undo any transformations on the buffer and return the result. - if (mBufferInfo.mTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - - if (getTransformToDisplayInverse()) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - } - - return Rect(bufWidth, bufHeight); -} - -FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const { - const State& s(getDrawingState()); - - // If we have a sideband stream, or we are scaling the buffer then return the layer size since - // we cannot determine the buffer size. - if ((s.sidebandStream != nullptr) || - (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) { - return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s)); - } - - if (mBufferInfo.mBuffer == nullptr) { - return parentBounds; - } - - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - - // Undo any transformations on the buffer and return the result. - if (mBufferInfo.mTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - - if (getTransformToDisplayInverse()) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - } - - return FloatRect(0, 0, bufWidth, bufHeight); -} - -void BufferLayer::latchAndReleaseBuffer() { - if (hasReadyFrame()) { - bool ignored = false; - latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */); - } - releasePendingBuffer(systemTime()); -} - -PixelFormat BufferLayer::getPixelFormat() const { - return mBufferInfo.mPixelFormat; -} - -bool BufferLayer::getTransformToDisplayInverse() const { - return mBufferInfo.mTransformToDisplayInverse; -} - -Rect BufferLayer::getBufferCrop() const { - // this is the crop rectangle that applies to the buffer - // itself (as opposed to the window) - if (!mBufferInfo.mCrop.isEmpty()) { - // if the buffer crop is defined, we use that - return mBufferInfo.mCrop; - } else if (mBufferInfo.mBuffer != nullptr) { - // otherwise we use the whole buffer - return mBufferInfo.mBuffer->getBounds(); - } else { - // if we don't have a buffer yet, we use an empty/invalid crop - return Rect(); - } -} - -uint32_t BufferLayer::getBufferTransform() const { - return mBufferInfo.mTransform; -} - -ui::Dataspace BufferLayer::getDataSpace() const { - return mBufferInfo.mDataspace; -} - -ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) { - ui::Dataspace updatedDataspace = dataspace; - // translate legacy dataspaces to modern dataspaces - switch (dataspace) { - case ui::Dataspace::SRGB: - updatedDataspace = ui::Dataspace::V0_SRGB; - break; - case ui::Dataspace::SRGB_LINEAR: - updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR; - break; - case ui::Dataspace::JFIF: - updatedDataspace = ui::Dataspace::V0_JFIF; - break; - case ui::Dataspace::BT601_625: - updatedDataspace = ui::Dataspace::V0_BT601_625; - break; - case ui::Dataspace::BT601_525: - updatedDataspace = ui::Dataspace::V0_BT601_525; - break; - case ui::Dataspace::BT709: - updatedDataspace = ui::Dataspace::V0_BT709; - break; - default: - break; - } - - return updatedDataspace; -} - -sp<GraphicBuffer> BufferLayer::getBuffer() const { - return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; -} - -void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) { - GLConsumer::computeTransformMatrix(outMatrix, - mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() - : nullptr, - mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled); -} - -void BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) { - Layer::setInitialValuesForClone(clonedFrom); - - sp<BufferLayer> bufferClonedFrom = static_cast<BufferLayer*>(clonedFrom.get()); - mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha; - mPotentialCursor = bufferClonedFrom->mPotentialCursor; - mProtectedByApp = bufferClonedFrom->mProtectedByApp; - - updateCloneBufferInfo(); -} - -void BufferLayer::updateCloneBufferInfo() { - if (!isClone() || !isClonedFromAlive()) { - return; - } - - sp<BufferLayer> clonedFrom = static_cast<BufferLayer*>(getClonedFrom().get()); - mBufferInfo = clonedFrom->mBufferInfo; - mSidebandStream = clonedFrom->mSidebandStream; - surfaceDamageRegion = clonedFrom->surfaceDamageRegion; - mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load(); - mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber; - - // After buffer info is updated, the drawingState from the real layer needs to be copied into - // the cloned. This is because some properties of drawingState can change when latchBuffer is - // called. However, copying the drawingState would also overwrite the cloned layer's relatives - // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in - // the cloned drawingState again. - wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf; - SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives; - wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop; - WindowInfo tmpInputInfo = mDrawingState.inputInfo; - - cloneDrawingState(clonedFrom.get()); - - mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop; - mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf; - mDrawingState.zOrderRelatives = tmpZOrderRelatives; - mDrawingState.inputInfo = tmpInputInfo; -} - -void BufferLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) { - mTransformHint = getFixedTransformHint(); - if (mTransformHint == ui::Transform::ROT_INVALID) { - mTransformHint = displayTransformHint; - } -} - -bool BufferLayer::bufferNeedsFiltering() const { - return isFixedSize(); -} - -const std::shared_ptr<renderengine::ExternalTexture>& BufferLayer::getExternalTexture() const { - return mBufferInfo.mBuffer; -} - -} // namespace android - -#if defined(__gl_h_) -#error "don't include gl/gl.h in this file" -#endif - -#if defined(__gl2_h_) -#error "don't include gl2/gl2.h in this file" -#endif - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h deleted file mode 100644 index 4c70eb58bf..0000000000 --- a/services/surfaceflinger/BufferLayer.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#pragma once - -#include <sys/types.h> -#include <cstdint> -#include <list> - -#include <gui/ISurfaceComposerClient.h> -#include <gui/LayerState.h> -#include <renderengine/Image.h> -#include <renderengine/Mesh.h> -#include <renderengine/Texture.h> -#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE -#include <ui/FrameStats.h> -#include <ui/GraphicBuffer.h> -#include <ui/PixelFormat.h> -#include <ui/Region.h> -#include <utils/RefBase.h> -#include <utils/String8.h> -#include <utils/Timers.h> - -#include "BufferLayerConsumer.h" -#include "Client.h" -#include "DisplayHardware/HWComposer.h" -#include "FrameTimeline.h" -#include "FrameTracker.h" -#include "Layer.h" -#include "LayerVector.h" -#include "MonitoredProducer.h" -#include "SurfaceFlinger.h" - -namespace android { - -class BufferLayer : public Layer { -public: - explicit BufferLayer(const LayerCreationArgs& args); - virtual ~BufferLayer() override; - - // Implements Layer. - sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override; - compositionengine::LayerFECompositionState* editCompositionState() override; - - // If we have received a new buffer this frame, we will pass its surface - // damage down to hardware composer. Otherwise, we must send a region with - // one empty rect. - void useSurfaceDamage() override; - void useEmptyDamage() override; - - bool isOpaque(const Layer::State& s) const override; - bool canReceiveInput() const override; - - // isVisible - true if this layer is visible, false otherwise - bool isVisible() const override; - - // isProtected - true if the layer may contain protected content in the - // GRALLOC_USAGE_PROTECTED sense. - bool isProtected() const override; - - // isFixedSize - true if content has a fixed size - bool isFixedSize() const override; - - bool usesSourceCrop() const override; - - bool isHdrY410() const override; - - void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence, - const std::shared_ptr<FenceTime>& presentFence, - const CompositorTiming&) override; - - // latchBuffer - called each time the screen is redrawn and returns whether - // the visible regions need to be recomputed (this is a fairly heavy - // operation, so this should be set only if needed). Typically this is used - // to figure out if the content or size of a surface has changed. - bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) override; - bool hasReadyFrame() const override; - - // Returns the current scaling mode - uint32_t getEffectiveScalingMode() const override; - - // Calls latchBuffer if the buffer has a frame queued and then releases the buffer. - // This is used if the buffer is just latched and releases to free up the buffer - // and will not be shown on screen. - // Should only be called on the main thread. - void latchAndReleaseBuffer() override; - - bool getTransformToDisplayInverse() const override; - - Rect getBufferCrop() const override; - - uint32_t getBufferTransform() const override; - - ui::Dataspace getDataSpace() const override; - - sp<GraphicBuffer> getBuffer() const override; - const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const override; - - ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; } - - // Returns true if the transformed buffer size does not match the layer size and we need - // to apply filtering. - virtual bool bufferNeedsFiltering() const; - -protected: - struct BufferInfo { - nsecs_t mDesiredPresentTime; - std::shared_ptr<FenceTime> mFenceTime; - sp<Fence> mFence; - uint32_t mTransform{0}; - ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN}; - Rect mCrop; - uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; - Region mSurfaceDamage; - HdrMetadata mHdrMetadata; - int mApi; - PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; - bool mTransformToDisplayInverse{false}; - - std::shared_ptr<renderengine::ExternalTexture> mBuffer; - uint64_t mFrameNumber; - int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; - - bool mFrameLatencyNeeded{false}; - }; - - BufferInfo mBufferInfo; - virtual void gatherBufferInfo() = 0; - - std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - - /* - * compositionengine::LayerFE overrides - */ - const compositionengine::LayerFECompositionState* getCompositionState() const override; - bool onPreComposition(nsecs_t) override; - void preparePerFrameCompositionState() override; - - static bool getOpacityForFormat(PixelFormat format); - - // from graphics API - const uint32_t mTextureName; - ui::Dataspace translateDataspace(ui::Dataspace dataspace); - void setInitialValuesForClone(const sp<Layer>& clonedFrom); - void updateCloneBufferInfo() override; - uint64_t mPreviousFrameNumber = 0; - - void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override; - - // Transform hint provided to the producer. This must be accessed holding - // the mStateLock. - ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0; - - bool getAutoRefresh() const { return mDrawingState.autoRefresh; } - bool getSidebandStreamChanged() const { return mSidebandStreamChanged; } - - // Returns true if the next buffer should be presented at the expected present time - bool shouldPresentNow(nsecs_t expectedPresentTime) const; - - // Returns true if the next buffer should be presented at the expected present time, - // overridden by BufferStateLayer and BufferQueueLayer for implementation - // specific logic - virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0; - - std::atomic<bool> mSidebandStreamChanged{false}; - -private: - virtual bool fenceHasSignaled() const = 0; - virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0; - - // Latch sideband stream and returns true if the dirty region should be updated. - virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0; - - virtual bool hasFrameUpdate() const = 0; - - virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) = 0; - - virtual status_t updateActiveBuffer() = 0; - virtual status_t updateFrameNumber() = 0; - - // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they - // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion - // detection. - bool needsInputInfo() const override { return !mPotentialCursor; } - - // Returns true if this layer requires filtering - bool needsFiltering(const DisplayDevice*) const override; - bool needsFilteringForScreenshots(const DisplayDevice*, - const ui::Transform& inverseParentTransform) const override; - - // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame - // and its parent layer is not bounded - Rect getBufferSize(const State& s) const override; - - PixelFormat getPixelFormat() const; - - // Computes the transform matrix using the setFilteringEnabled to determine whether the - // transform matrix should be computed for use with bilinear filtering. - void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]); - - std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState; - - FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; -}; - -} // namespace android diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp deleted file mode 100644 index 7361a4fdef..0000000000 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#undef LOG_TAG -#define LOG_TAG "BufferLayerConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include "BufferLayerConsumer.h" -#include "Layer.h" -#include "Scheduler/VsyncController.h" - -#include <inttypes.h> - -#include <cutils/compiler.h> - -#include <hardware/hardware.h> - -#include <math/mat4.h> - -#include <gui/BufferItem.h> -#include <gui/GLConsumer.h> -#include <gui/ISurfaceComposer.h> -#include <gui/SurfaceComposerClient.h> -#include <private/gui/ComposerService.h> -#include <renderengine/RenderEngine.h> -#include <renderengine/impl/ExternalTexture.h> -#include <utils/Log.h> -#include <utils/String8.h> -#include <utils/Trace.h> - -namespace android { - -// Macros for including the BufferLayerConsumer name in log messages -#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) - -static const mat4 mtxIdentity; - -BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, - renderengine::RenderEngine& engine, uint32_t tex, - Layer* layer) - : ConsumerBase(bq, false), - mCurrentCrop(Rect::EMPTY_RECT), - mCurrentTransform(0), - mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mCurrentFence(Fence::NO_FENCE), - mCurrentTimestamp(0), - mCurrentDataSpace(ui::Dataspace::UNKNOWN), - mCurrentFrameNumber(0), - mCurrentTransformToDisplayInverse(false), - mCurrentSurfaceDamage(), - mCurrentApi(0), - mDefaultWidth(1), - mDefaultHeight(1), - mFilteringEnabled(true), - mRE(engine), - mTexName(tex), - mLayer(layer), - mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) { - BLC_LOGV("BufferLayerConsumer"); - - memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); - - mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); -} - -status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!"); - return NO_INIT; - } - mDefaultWidth = w; - mDefaultHeight = h; - return mConsumer->setDefaultBufferSize(w, h); -} - -void BufferLayerConsumer::setContentsChangedListener(const wp<ContentsChangedListener>& listener) { - setFrameAvailableListener(listener); - Mutex::Autolock lock(mMutex); - mContentsChangedListener = listener; -} - -status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime, - bool* autoRefresh, bool* queuedBuffer, - uint64_t maxFrameNumber) { - ATRACE_CALL(); - BLC_LOGV("updateTexImage"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!"); - return NO_INIT; - } - - BufferItem item; - - // Acquire the next buffer. - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - status_t err = acquireBufferLocked(&item, expectedPresentTime, maxFrameNumber); - if (err != NO_ERROR) { - if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - err = NO_ERROR; - } else if (err == BufferQueue::PRESENT_LATER) { - // return the error, without logging - } else { - BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); - } - return err; - } - - if (autoRefresh) { - *autoRefresh = item.mAutoRefresh; - } - - if (queuedBuffer) { - *queuedBuffer = item.mQueuedBuffer; - } - - // We call the rejecter here, in case the caller has a reason to - // not accept this buffer. This is used by SurfaceFlinger to - // reject buffers which have the wrong size - int slot = item.mSlot; - if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) { - releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer); - return BUFFER_REJECTED; - } - - // Release the previous buffer. - err = updateAndReleaseLocked(item, &mPendingRelease); - if (err != NO_ERROR) { - return err; - } - return err; -} - -void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) { - if (!fence->isValid()) { - return; - } - - auto slot = mPendingRelease.isPending ? mPendingRelease.currentTexture : mCurrentTexture; - if (slot == BufferQueue::INVALID_BUFFER_SLOT) { - return; - } - - auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer - : mCurrentTextureBuffer->getBuffer(); - auto err = addReleaseFence(slot, buffer, fence); - if (err != OK) { - BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); - } -} - -bool BufferLayerConsumer::releasePendingBuffer() { - if (!mPendingRelease.isPending) { - BLC_LOGV("Pending buffer already released"); - return false; - } - BLC_LOGV("Releasing pending buffer"); - Mutex::Autolock lock(mMutex); - status_t result = - releaseBufferLocked(mPendingRelease.currentTexture, mPendingRelease.graphicBuffer); - if (result < NO_ERROR) { - BLC_LOGE("releasePendingBuffer failed: %s (%d)", strerror(-result), result); - } - mPendingRelease = PendingRelease(); - return true; -} - -sp<Fence> BufferLayerConsumer::getPrevFinalReleaseFence() const { - Mutex::Autolock lock(mMutex); - return ConsumerBase::mPrevFinalReleaseFence; -} - -status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, - uint64_t maxFrameNumber) { - status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber); - if (err != NO_ERROR) { - return err; - } - - // If item->mGraphicBuffer is not null, this buffer has not been acquired - // before, so we need to clean up old references. - if (item->mGraphicBuffer != nullptr) { - std::lock_guard<std::mutex> lock(mImagesMutex); - if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr || - mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) { - mImages[item->mSlot] = std::make_shared< - renderengine::impl::ExternalTexture>(item->mGraphicBuffer, mRE, - renderengine::impl::ExternalTexture:: - Usage::READABLE); - } - } - - return NO_ERROR; -} - -status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, - PendingRelease* pendingRelease) { - status_t err = NO_ERROR; - - int slot = item.mSlot; - - BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, - (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->getBuffer() != nullptr) - ? mCurrentTextureBuffer->getBuffer()->handle - : 0, - slot, mSlots[slot].mGraphicBuffer->handle); - - // Hang onto the pointer so that it isn't freed in the call to - // releaseBufferLocked() if we're in shared buffer mode and both buffers are - // the same. - - std::shared_ptr<renderengine::ExternalTexture> nextTextureBuffer; - { - std::lock_guard<std::mutex> lock(mImagesMutex); - nextTextureBuffer = mImages[slot]; - } - - // release old buffer - if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - if (pendingRelease == nullptr) { - status_t status = - releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->getBuffer()); - if (status < NO_ERROR) { - BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), - status); - err = status; - // keep going, with error raised [?] - } - } else { - pendingRelease->currentTexture = mCurrentTexture; - pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer(); - pendingRelease->isPending = true; - } - } - - // Update the BufferLayerConsumer state. - mCurrentTexture = slot; - mCurrentTextureBuffer = nextTextureBuffer; - mCurrentCrop = item.mCrop; - mCurrentTransform = item.mTransform; - mCurrentScalingMode = item.mScalingMode; - mCurrentTimestamp = item.mTimestamp; - mCurrentDataSpace = static_cast<ui::Dataspace>(item.mDataSpace); - mCurrentHdrMetadata = item.mHdrMetadata; - mCurrentFence = item.mFence; - mCurrentFenceTime = item.mFenceTime; - mCurrentFrameNumber = item.mFrameNumber; - mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse; - mCurrentSurfaceDamage = item.mSurfaceDamage; - mCurrentApi = item.mApi; - - computeCurrentTransformMatrixLocked(); - - return err; -} - -void BufferLayerConsumer::getTransformMatrix(float mtx[16]) { - Mutex::Autolock lock(mMutex); - memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); -} - -void BufferLayerConsumer::setFilteringEnabled(bool enabled) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!"); - return; - } - bool needsRecompute = mFilteringEnabled != enabled; - mFilteringEnabled = enabled; - - if (needsRecompute && mCurrentTextureBuffer == nullptr) { - BLC_LOGD("setFilteringEnabled called with mCurrentTextureBuffer == nullptr"); - } - - if (needsRecompute && mCurrentTextureBuffer != nullptr) { - computeCurrentTransformMatrixLocked(); - } -} - -void BufferLayerConsumer::computeCurrentTransformMatrixLocked() { - BLC_LOGV("computeCurrentTransformMatrixLocked"); - if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->getBuffer() == nullptr) { - BLC_LOGD("computeCurrentTransformMatrixLocked: " - "mCurrentTextureBuffer is nullptr"); - } - GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, - mCurrentTextureBuffer == nullptr - ? nullptr - : mCurrentTextureBuffer->getBuffer(), - getCurrentCropLocked(), mCurrentTransform, - mFilteringEnabled); -} - -nsecs_t BufferLayerConsumer::getTimestamp() { - BLC_LOGV("getTimestamp"); - Mutex::Autolock lock(mMutex); - return mCurrentTimestamp; -} - -ui::Dataspace BufferLayerConsumer::getCurrentDataSpace() { - BLC_LOGV("getCurrentDataSpace"); - Mutex::Autolock lock(mMutex); - return mCurrentDataSpace; -} - -const HdrMetadata& BufferLayerConsumer::getCurrentHdrMetadata() const { - BLC_LOGV("getCurrentHdrMetadata"); - Mutex::Autolock lock(mMutex); - return mCurrentHdrMetadata; -} - -uint64_t BufferLayerConsumer::getFrameNumber() { - BLC_LOGV("getFrameNumber"); - Mutex::Autolock lock(mMutex); - return mCurrentFrameNumber; -} - -bool BufferLayerConsumer::getTransformToDisplayInverse() const { - Mutex::Autolock lock(mMutex); - return mCurrentTransformToDisplayInverse; -} - -const Region& BufferLayerConsumer::getSurfaceDamage() const { - return mCurrentSurfaceDamage; -} - -void BufferLayerConsumer::mergeSurfaceDamage(const Region& damage) { - if (damage.bounds() == Rect::INVALID_RECT || - mCurrentSurfaceDamage.bounds() == Rect::INVALID_RECT) { - mCurrentSurfaceDamage = Region::INVALID_REGION; - } else { - mCurrentSurfaceDamage |= damage; - } -} - -int BufferLayerConsumer::getCurrentApi() const { - Mutex::Autolock lock(mMutex); - return mCurrentApi; -} - -std::shared_ptr<renderengine::ExternalTexture> BufferLayerConsumer::getCurrentBuffer( - int* outSlot, sp<Fence>* outFence) const { - Mutex::Autolock lock(mMutex); - - if (outSlot != nullptr) { - *outSlot = mCurrentTexture; - } - - if (outFence != nullptr) { - *outFence = mCurrentFence; - } - - return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer; -} - -Rect BufferLayerConsumer::getCurrentCrop() const { - Mutex::Autolock lock(mMutex); - return getCurrentCropLocked(); -} - -Rect BufferLayerConsumer::getCurrentCropLocked() const { - uint32_t width = mDefaultWidth; - uint32_t height = mDefaultHeight; - // If the buffer comes with a rotated bit for 90 (or 270) degrees, switch width/height in order - // to scale and crop correctly. - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - width = mDefaultHeight; - height = mDefaultWidth; - } - - return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) - ? GLConsumer::scaleDownCrop(mCurrentCrop, width, height) - : mCurrentCrop; -} - -uint32_t BufferLayerConsumer::getCurrentTransform() const { - Mutex::Autolock lock(mMutex); - return mCurrentTransform; -} - -uint32_t BufferLayerConsumer::getCurrentScalingMode() const { - Mutex::Autolock lock(mMutex); - return mCurrentScalingMode; -} - -sp<Fence> BufferLayerConsumer::getCurrentFence() const { - Mutex::Autolock lock(mMutex); - return mCurrentFence; -} - -std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const { - Mutex::Autolock lock(mMutex); - return mCurrentFenceTime; -} - -void BufferLayerConsumer::freeBufferLocked(int slotIndex) { - BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - std::lock_guard<std::mutex> lock(mImagesMutex); - if (slotIndex == mCurrentTexture) { - mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; - } - mImages[slotIndex] = nullptr; - ConsumerBase::freeBufferLocked(slotIndex); -} - -void BufferLayerConsumer::onDisconnect() { - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - mLayer->onDisconnect(); -} - -void BufferLayerConsumer::onSidebandStreamChanged() { - [[maybe_unused]] FrameAvailableListener* unsafeFrameAvailableListener = nullptr; - { - Mutex::Autolock lock(mFrameAvailableMutex); - unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get(); - } - sp<ContentsChangedListener> listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get()); - listener = mContentsChangedListener.promote(); - } - - if (listener != nullptr) { - listener->onSidebandStreamChanged(); - } -} - -void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { - if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) { - std::lock_guard<std::mutex> lock(mImagesMutex); - const std::shared_ptr<renderengine::ExternalTexture>& oldImage = mImages[item.mSlot]; - if (oldImage == nullptr || oldImage->getBuffer() == nullptr || - oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) { - mImages[item.mSlot] = std::make_shared< - renderengine::impl::ExternalTexture>(item.mGraphicBuffer, mRE, - renderengine::impl::ExternalTexture:: - Usage::READABLE); - } - } -} - -void BufferLayerConsumer::abandonLocked() { - BLC_LOGV("abandonLocked"); - mCurrentTextureBuffer = nullptr; - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - std::lock_guard<std::mutex> lock(mImagesMutex); - mImages[i] = nullptr; - } - ConsumerBase::abandonLocked(); -} - -status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) { - return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); -} - -void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const { - result.appendFormat("%smTexName=%d mCurrentTexture=%d\n" - "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", - prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, - mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, - mCurrentTransform); - - ConsumerBase::dumpLocked(result, prefix); -} -}; // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h deleted file mode 100644 index 23ad2a3f91..0000000000 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BUFFERLAYERCONSUMER_H -#define ANDROID_BUFFERLAYERCONSUMER_H - -#include <android-base/thread_annotations.h> -#include <gui/BufferQueueDefs.h> -#include <gui/ConsumerBase.h> -#include <gui/HdrMetadata.h> -#include <renderengine/ExternalTexture.h> -#include <ui/FenceTime.h> -#include <ui/GraphicBuffer.h> -#include <ui/GraphicTypes.h> -#include <ui/Region.h> -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -namespace android { -// ---------------------------------------------------------------------------- - -class Layer; -class String8; - -namespace renderengine { -class RenderEngine; -} // namespace renderengine - -/* - * BufferLayerConsumer consumes buffers of graphics data from a BufferQueue, - * and makes them available to RenderEngine as a texture. - * - * A typical usage pattern is to call updateTexImage() when a new frame is - * desired. If a new frame is available, the frame is latched. If not, the - * previous contents are retained. The texture is attached and updated after - * bindTextureImage() is called. - * - * All calls to updateTexImage must be made with RenderEngine being current. - * The texture is attached to the TEXTURE_EXTERNAL texture target. - */ -class BufferLayerConsumer : public ConsumerBase { -public: - static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; - - class BufferRejecter { - friend class BufferLayerConsumer; - virtual bool reject(const sp<GraphicBuffer>& buf, const BufferItem& item) = 0; - - protected: - virtual ~BufferRejecter() {} - }; - - struct ContentsChangedListener : public FrameAvailableListener { - virtual void onSidebandStreamChanged() = 0; - }; - - // BufferLayerConsumer constructs a new BufferLayerConsumer object. The - // tex parameter indicates the name of the RenderEngine texture to which - // images are to be streamed. - BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, renderengine::RenderEngine& engine, - uint32_t tex, Layer* layer); - - // Sets the contents changed listener. This should be used instead of - // ConsumerBase::setFrameAvailableListener(). - void setContentsChangedListener(const wp<ContentsChangedListener>& listener); - - // updateTexImage acquires the most recently queued buffer, and sets the - // image contents of the target texture to it. - // - // This call may only be made while RenderEngine is current. - // - // This calls doFenceWait to ensure proper synchronization unless native - // fence is supported. - // - // Unlike the GLConsumer version, this version takes a functor that may be - // used to reject the newly acquired buffer. It also does not bind the - // RenderEngine texture until bindTextureImage is called. - status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime, - bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber); - - // setReleaseFence stores a fence that will signal when the current buffer - // is no longer being read. This fence will be returned to the producer - // when the current buffer is released by updateTexImage(). Multiple - // fences can be set for a given buffer; they will be merged into a single - // union fence. - void setReleaseFence(const sp<Fence>& fence); - - bool releasePendingBuffer(); - - sp<Fence> getPrevFinalReleaseFence() const; - - // See GLConsumer::getTransformMatrix. - void getTransformMatrix(float mtx[16]); - - // getTimestamp retrieves the timestamp associated with the texture image - // set by the most recent call to updateTexImage. - // - // The timestamp is in nanoseconds, and is monotonically increasing. Its - // other semantics (zero point, etc) are source-dependent and should be - // documented by the source. - int64_t getTimestamp(); - - // getDataSpace retrieves the DataSpace associated with the texture image - // set by the most recent call to updateTexImage. - ui::Dataspace getCurrentDataSpace(); - - // getCurrentHdrMetadata retrieves the HDR metadata associated with the - // texture image set by the most recent call to updateTexImage. - const HdrMetadata& getCurrentHdrMetadata() const; - - // getFrameNumber retrieves the frame number associated with the texture - // image set by the most recent call to updateTexImage. - // - // The frame number is an incrementing counter set to 0 at the creation of - // the BufferQueue associated with this consumer. - uint64_t getFrameNumber(); - - bool getTransformToDisplayInverse() const; - - // must be called from SF main thread - const Region& getSurfaceDamage() const; - - // Merge the given damage region into the current damage region value. - void mergeSurfaceDamage(const Region& damage); - - // getCurrentApi retrieves the API which queues the current buffer. - int getCurrentApi() const; - - // See GLConsumer::setDefaultBufferSize. - status_t setDefaultBufferSize(uint32_t width, uint32_t height); - - // setFilteringEnabled sets whether the transform matrix should be computed - // for use with bilinear filtering. - void setFilteringEnabled(bool enabled); - - // getCurrentBuffer returns the buffer associated with the current image. - // When outSlot is not nullptr, the current buffer slot index is also - // returned. Simiarly, when outFence is not nullptr, the current output - // fence is returned. - std::shared_ptr<renderengine::ExternalTexture> getCurrentBuffer( - int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const; - - // getCurrentCrop returns the cropping rectangle of the current buffer. - Rect getCurrentCrop() const; - - // getCurrentTransform returns the transform of the current buffer. - uint32_t getCurrentTransform() const; - - // getCurrentScalingMode returns the scaling mode of the current buffer. - uint32_t getCurrentScalingMode() const; - - // getCurrentFence returns the fence indicating when the current buffer is - // ready to be read from. - sp<Fence> getCurrentFence() const; - - // getCurrentFence returns the FenceTime indicating when the current - // buffer is ready to be read from. - std::shared_ptr<FenceTime> getCurrentFenceTime() const; - - // setConsumerUsageBits overrides the ConsumerBase method to OR - // DEFAULT_USAGE_FLAGS to usage. - status_t setConsumerUsageBits(uint64_t usage); - void onBufferAvailable(const BufferItem& item) EXCLUDES(mImagesMutex); - -protected: - // abandonLocked overrides the ConsumerBase method to clear - // mCurrentTextureImage in addition to the ConsumerBase behavior. - virtual void abandonLocked() EXCLUDES(mImagesMutex); - - // dumpLocked overrides the ConsumerBase method to dump BufferLayerConsumer- - // specific info in addition to the ConsumerBase behavior. - virtual void dumpLocked(String8& result, const char* prefix) const; - - // See ConsumerBase::acquireBufferLocked - virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, - uint64_t maxFrameNumber = 0) override - EXCLUDES(mImagesMutex); - - bool canUseImageCrop(const Rect& crop) const; - - struct PendingRelease { - PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {} - - bool isPending; - int currentTexture; - sp<GraphicBuffer> graphicBuffer; - }; - - // This releases the buffer in the slot referenced by mCurrentTexture, - // then updates state to refer to the BufferItem, which must be a - // newly-acquired buffer. If pendingRelease is not null, the parameters - // which would have been passed to releaseBufferLocked upon the successful - // completion of the method will instead be returned to the caller, so that - // it may call releaseBufferLocked itself later. - status_t updateAndReleaseLocked(const BufferItem& item, - PendingRelease* pendingRelease = nullptr) - EXCLUDES(mImagesMutex); - -private: - // Utility class for managing GraphicBuffer references into renderengine - class Image { - public: - Image(const sp<GraphicBuffer>& graphicBuffer, renderengine::RenderEngine& engine); - virtual ~Image(); - const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; } - - private: - // mGraphicBuffer is the buffer that was used to create this image. - sp<GraphicBuffer> mGraphicBuffer; - // Back-reference into renderengine to initiate cleanup. - renderengine::RenderEngine& mRE; - DISALLOW_COPY_AND_ASSIGN(Image); - }; - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in - // that slot. Otherwise it has no effect. - // - // This method must be called with mMutex locked. - virtual void freeBufferLocked(int slotIndex) EXCLUDES(mImagesMutex); - - // IConsumerListener interface - void onDisconnect() override; - void onSidebandStreamChanged() override; - void addAndGetFrameTimestamps(const NewFrameEventsEntry*, FrameEventHistoryDelta*) override {} - - // computeCurrentTransformMatrixLocked computes the transform matrix for the - // current texture. It uses mCurrentTransform and the current GraphicBuffer - // to compute this matrix and stores it in mCurrentTransformMatrix. - // mCurrentTextureImage must not be nullptr. - void computeCurrentTransformMatrixLocked(); - - // getCurrentCropLocked returns the cropping rectangle of the current buffer. - Rect getCurrentCropLocked() const; - - // The default consumer usage flags that BufferLayerConsumer always sets on its - // BufferQueue instance; these will be OR:d with any additional flags passed - // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always - // consume buffers as hardware textures. - static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; - - // mCurrentTextureBuffer is the buffer containing the current texture. It's - // possible that this buffer is not associated with any buffer slot, so we - // must track it separately in order to support the getCurrentBuffer method. - std::shared_ptr<renderengine::ExternalTexture> mCurrentTextureBuffer; - - // mCurrentCrop is the crop rectangle that applies to the current texture. - // It gets set each time updateTexImage is called. - Rect mCurrentCrop; - - // mCurrentTransform is the transform identifier for the current texture. It - // gets set each time updateTexImage is called. - uint32_t mCurrentTransform; - - // mCurrentScalingMode is the scaling mode for the current texture. It gets - // set each time updateTexImage is called. - uint32_t mCurrentScalingMode; - - // mCurrentFence is the fence received from BufferQueue in updateTexImage. - sp<Fence> mCurrentFence; - - // The FenceTime wrapper around mCurrentFence. - std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE}; - - // mCurrentTransformMatrix is the transform matrix for the current texture. - // It gets computed by computeTransformMatrix each time updateTexImage is - // called. - float mCurrentTransformMatrix[16]; - - // mCurrentTimestamp is the timestamp for the current texture. It - // gets set each time updateTexImage is called. - int64_t mCurrentTimestamp; - - // mCurrentDataSpace is the dataspace for the current texture. It - // gets set each time updateTexImage is called. - ui::Dataspace mCurrentDataSpace; - - // mCurrentHdrMetadata is the HDR metadata for the current texture. It - // gets set each time updateTexImage is called. - HdrMetadata mCurrentHdrMetadata; - - // mCurrentFrameNumber is the frame counter for the current texture. - // It gets set each time updateTexImage is called. - uint64_t mCurrentFrameNumber; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after BufferLayerConsumer::mCurrentTransform. - // This must be set/read from SurfaceFlinger's main thread. - bool mCurrentTransformToDisplayInverse; - - // The portion of this surface that has changed since the previous frame - Region mCurrentSurfaceDamage; - - int mCurrentApi; - - uint32_t mDefaultWidth, mDefaultHeight; - - // mFilteringEnabled indicates whether the transform matrix is computed for - // use with bilinear filtering. It defaults to true and is changed by - // setFilteringEnabled(). - bool mFilteringEnabled; - - renderengine::RenderEngine& mRE; - - // mTexName is the name of the RenderEngine texture to which streamed - // images will be bound when bindTexImage is called. It is set at - // construction time. - const uint32_t mTexName; - - // The layer for this BufferLayerConsumer. Always check mAbandoned before accessing. - Layer* mLayer GUARDED_BY(mMutex); - - wp<ContentsChangedListener> mContentsChangedListener; - - // mCurrentTexture is the buffer slot index of the buffer that is currently - // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT, - // indicating that no buffer slot is currently bound to the texture. Note, - // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean - // that no buffer is bound to the texture. A call to setBufferCount will - // reset mCurrentTexture to INVALID_BUFFER_SLOT. - int mCurrentTexture; - - // Shadow buffer cache for cleaning up renderengine references. - std::shared_ptr<renderengine::ExternalTexture> - mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); - - // Separate mutex guarding the shadow buffer cache. - // mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated) - // which is contentious enough that we can't just use mMutex. - mutable std::mutex mImagesMutex; - - // A release that is pending on the receipt of a new release fence from - // presentDisplay - PendingRelease mPendingRelease; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_BUFFERLAYERCONSUMER_H diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp deleted file mode 100644 index bee4de32a6..0000000000 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#undef LOG_TAG -#define LOG_TAG "BufferQueueLayer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "BufferQueueLayer.h" - -#include <compositionengine/LayerFECompositionState.h> -#include <gui/BufferQueueConsumer.h> -#include <system/window.h> - -#include "LayerRejecter.h" -#include "SurfaceInterceptor.h" - -#include "FrameTracer/FrameTracer.h" -#include "Scheduler/LayerHistory.h" -#include "TimeStats/TimeStats.h" - -namespace android { -using PresentState = frametimeline::SurfaceFrame::PresentState; - -BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {} - -BufferQueueLayer::~BufferQueueLayer() { - mContentsChangedListener->abandon(); - mConsumer->abandon(); -} - -// ----------------------------------------------------------------------- -// Interface implementation for Layer -// ----------------------------------------------------------------------- - -void BufferQueueLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) { - const sp<Fence> releaseFence = futureFenceResult.get().value_or(Fence::NO_FENCE); - mConsumer->setReleaseFence(releaseFence); - - // Prevent tracing the same release multiple times. - if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { - mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber, - std::make_shared<FenceTime>(releaseFence), - FrameTracer::FrameEvent::RELEASE_FENCE); - mPreviousReleasedFrameNumber = mPreviousFrameNumber; - } -} - -void BufferQueueLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) { - BufferLayer::setTransformHint(displayTransformHint); - mConsumer->setTransformHint(mTransformHint); -} - -void BufferQueueLayer::releasePendingBuffer(nsecs_t) { - if (!mConsumer->releasePendingBuffer()) { - return; - } -} - -void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) { - mConsumer->setDefaultBufferSize(w, h); -} - -int32_t BufferQueueLayer::getQueuedFrameCount() const { - return mQueuedFrames; -} - -bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const { - Mutex::Autolock lock(mQueueItemLock); - - const int64_t addedTime = mQueueItems[0].item.mTimestamp; - - // Ignore timestamps more than a second in the future - const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1)); - ALOGW_IF(!isPlausible, - "[%s] Timestamp %" PRId64 " seems implausible " - "relative to expectedPresent %" PRId64, - getDebugName(), addedTime, expectedPresentTime); - - if (!isPlausible) { - mFlinger->mTimeStats->incrementBadDesiredPresent(getSequence()); - } - - const bool isDue = addedTime < expectedPresentTime; - return isDue || !isPlausible; -} - -// ----------------------------------------------------------------------- -// Interface implementation for BufferLayer -// ----------------------------------------------------------------------- - -bool BufferQueueLayer::fenceHasSignaled() const { - Mutex::Autolock lock(mQueueItemLock); - - if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { - return true; - } - - if (!hasFrameUpdate()) { - return true; - } - - if (mQueueItems[0].item.mIsDroppable) { - // Even though this buffer's fence may not have signaled yet, it could - // be replaced by another buffer before it has a chance to, which means - // that it's possible to get into a situation where a buffer is never - // able to be latched. To avoid this, grab this buffer anyway. - return true; - } - const bool fenceSignaled = - mQueueItems[0].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; - if (!fenceSignaled) { - mFlinger->mTimeStats->incrementLatchSkipped(getSequence(), - TimeStats::LatchSkipReason::LateAcquire); - } - - return fenceSignaled; -} - -bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const { - Mutex::Autolock lock(mQueueItemLock); - - if (!hasFrameUpdate() || isRemovedFromCurrentState()) { - return true; - } - - return mQueueItems[0].item.mTimestamp <= expectedPresentTime; -} - -bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) { - // We need to update the sideband stream if the layer has both a buffer and a sideband stream. - editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get(); - - bool sidebandStreamChanged = true; - if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) { - // mSidebandStreamChanged was changed to false - mSidebandStream = mConsumer->getSidebandStream(); - auto* layerCompositionState = editCompositionState(); - layerCompositionState->sidebandStream = mSidebandStream; - if (layerCompositionState->sidebandStream != nullptr) { - setTransactionFlags(eTransactionNeeded); - mFlinger->setTransactionFlags(eTraversalNeeded); - } - recomputeVisibleRegions = true; - - return true; - } - return false; -} - -bool BufferQueueLayer::hasFrameUpdate() const { - return mQueuedFrames > 0; -} - -status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) { - // This boolean is used to make sure that SurfaceFlinger's shadow copy - // of the buffer queue isn't modified when the buffer queue is returning - // BufferItem's that weren't actually queued. This can happen in shared - // buffer mode. - bool queuedBuffer = false; - const int32_t layerId = getSequence(); - LayerRejecter r(mDrawingState, getDrawingState(), recomputeVisibleRegions, - getProducerStickyTransform() != 0, mName, - getTransformToDisplayInverse()); - - if (isRemovedFromCurrentState()) { - expectedPresentTime = 0; - } - - // updateTexImage() below might drop the some buffers at the head of the queue if there is a - // buffer behind them which is timely to be presented. However this buffer may not be signaled - // yet. The code below makes sure that this wouldn't happen by setting maxFrameNumber to the - // last buffer that was signaled. - uint64_t lastSignaledFrameNumber = mLastFrameNumberReceived; - { - Mutex::Autolock lock(mQueueItemLock); - for (size_t i = 0; i < mQueueItems.size(); i++) { - bool fenceSignaled = - mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; - if (!fenceSignaled) { - break; - } - lastSignaledFrameNumber = mQueueItems[i].item.mFrameNumber; - } - } - const uint64_t maxFrameNumberToAcquire = - std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber); - - bool autoRefresh; - status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh, - &queuedBuffer, maxFrameNumberToAcquire); - mDrawingState.autoRefresh = autoRefresh; - if (updateResult == BufferQueue::PRESENT_LATER) { - // Producer doesn't want buffer to be displayed yet. Signal a - // layer update so we check again at the next opportunity. - mFlinger->onLayerUpdate(); - return BAD_VALUE; - } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) { - // If the buffer has been rejected, remove it from the shadow queue - // and return early - if (queuedBuffer) { - Mutex::Autolock lock(mQueueItemLock); - if (mQueuedFrames > 0) { - mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); - mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); - if (mQueueItems[0].surfaceFrame) { - addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame); - } - mQueueItems.erase(mQueueItems.begin()); - mQueuedFrames--; - } - } - return BAD_VALUE; - } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { - // This can occur if something goes wrong when trying to create the - // EGLImage for this buffer. If this happens, the buffer has already - // been released, so we need to clean up the queue and bug out - // early. - if (queuedBuffer) { - Mutex::Autolock lock(mQueueItemLock); - for (auto& [item, surfaceFrame] : mQueueItems) { - if (surfaceFrame) { - addSurfaceFrameDroppedForBuffer(surfaceFrame); - } - } - mQueueItems.clear(); - mQueuedFrames = 0; - mFlinger->mTimeStats->onDestroy(layerId); - mFlinger->mFrameTracer->onDestroy(layerId); - } - - // Once we have hit this state, the shadow queue may no longer - // correctly reflect the incoming BufferQueue's contents, so even if - // updateTexImage starts working, the only safe course of action is - // to continue to ignore updates. - mUpdateTexImageFailed = true; - - return BAD_VALUE; - } - - bool more_frames_pending = false; - if (queuedBuffer) { - // Autolock scope - auto currentFrameNumber = mConsumer->getFrameNumber(); - - Mutex::Autolock lock(mQueueItemLock); - - // Remove any stale buffers that have been dropped during - // updateTexImage - while (mQueuedFrames > 0 && mQueueItems[0].item.mFrameNumber != currentFrameNumber) { - mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); - mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); - if (mQueueItems[0].surfaceFrame) { - addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame); - } - mQueueItems.erase(mQueueItems.begin()); - mQueuedFrames--; - } - - uint64_t bufferID = mQueueItems[0].item.mGraphicBuffer->getId(); - mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime, - FrameTracer::FrameEvent::LATCH); - - if (mQueueItems[0].surfaceFrame) { - addSurfaceFramePresentedForBuffer(mQueueItems[0].surfaceFrame, - mQueueItems[0].item.mFenceTime->getSignalTime(), - latchTime); - } - mQueueItems.erase(mQueueItems.begin()); - more_frames_pending = (mQueuedFrames.fetch_sub(1) > 1); - } - - // Decrement the queued-frames count. Signal another event if we - // have more frames pending. - if ((queuedBuffer && more_frames_pending) || mDrawingState.autoRefresh) { - mFlinger->onLayerUpdate(); - } - - return NO_ERROR; -} - -status_t BufferQueueLayer::updateActiveBuffer() { - // update the active buffer - mPreviousBufferId = getCurrentBufferId(); - mBufferInfo.mBuffer = - mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence); - - if (mBufferInfo.mBuffer == nullptr) { - // this can only happen if the very first buffer was rejected. - return BAD_VALUE; - } - return NO_ERROR; -} - -status_t BufferQueueLayer::updateFrameNumber() { - mPreviousFrameNumber = mCurrentFrameNumber; - mCurrentFrameNumber = mConsumer->getFrameNumber(); - return NO_ERROR; -} - -void BufferQueueLayer::setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) { - mFrameTimelineInfo = frameTimelineInfo; -} - -// ----------------------------------------------------------------------- -// Interface implementation for BufferLayerConsumer::ContentsChangedListener -// ----------------------------------------------------------------------- - -void BufferQueueLayer::onFrameDequeued(const uint64_t bufferId) { - const int32_t layerId = getSequence(); - mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER, - systemTime(), FrameTracer::FrameEvent::DEQUEUE); -} - -void BufferQueueLayer::onFrameDetached(const uint64_t bufferId) { - const int32_t layerId = getSequence(); - mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER, - systemTime(), FrameTracer::FrameEvent::DETACH); -} - -void BufferQueueLayer::onFrameCancelled(const uint64_t bufferId) { - const int32_t layerId = getSequence(); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER, - systemTime(), FrameTracer::FrameEvent::CANCEL); -} - -void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { - const int32_t layerId = getSequence(); - const uint64_t bufferId = item.mGraphicBuffer->getId(); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(), - FrameTracer::FrameEvent::QUEUE); - mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber, - std::make_shared<FenceTime>(item.mFence), - FrameTracer::FrameEvent::ACQUIRE_FENCE); - - ATRACE_CALL(); - // Add this buffer from our internal queue tracker - { // Autolock scope - const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp; - - using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); - - Mutex::Autolock lock(mQueueItemLock); - // Reset the frame number tracker when we receive the first buffer after - // a frame number reset - if (item.mFrameNumber == 1) { - mLastFrameNumberReceived = 0; - } - - // Ensure that callbacks are handled in order - while (item.mFrameNumber != mLastFrameNumberReceived + 1) { - status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); - if (result != NO_ERROR) { - ALOGE("[%s] Timed out waiting on callback", getDebugName()); - break; - } - } - - auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName); - - mQueueItems.push_back({item, surfaceFrame}); - mQueuedFrames++; - - // Wake up any pending callbacks - mLastFrameNumberReceived = item.mFrameNumber; - mQueueItemCondition.broadcast(); - } - - mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(), - item.mGraphicBuffer->getHeight(), item.mFrameNumber); - - mFlinger->onLayerUpdate(); - mConsumer->onBufferAvailable(item); -} - -void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { - ATRACE_CALL(); - { // Autolock scope - Mutex::Autolock lock(mQueueItemLock); - - // Ensure that callbacks are handled in order - while (item.mFrameNumber != mLastFrameNumberReceived + 1) { - status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); - if (result != NO_ERROR) { - ALOGE("[%s] Timed out waiting on callback", getDebugName()); - break; - } - } - - if (!hasFrameUpdate()) { - ALOGE("Can't replace a frame on an empty queue"); - return; - } - - auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName); - mQueueItems[mQueueItems.size() - 1].item = item; - mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); - - // Wake up any pending callbacks - mLastFrameNumberReceived = item.mFrameNumber; - mQueueItemCondition.broadcast(); - } - - const int32_t layerId = getSequence(); - const uint64_t bufferId = item.mGraphicBuffer->getId(); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(), - FrameTracer::FrameEvent::QUEUE); - mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber, - std::make_shared<FenceTime>(item.mFence), - FrameTracer::FrameEvent::ACQUIRE_FENCE); - mConsumer->onBufferAvailable(item); -} - -void BufferQueueLayer::onSidebandStreamChanged() { - bool sidebandStreamChanged = false; - if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, true)) { - // mSidebandStreamChanged was changed to true - mFlinger->onLayerUpdate(); - } -} - -// ----------------------------------------------------------------------- - -void BufferQueueLayer::onFirstRef() { - BufferLayer::onFirstRef(); - - // Creates a custom BufferQueue for SurfaceFlingerConsumer to use - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - mFlinger->getFactory().createBufferQueue(&producer, &consumer, true); - mProducer = mFlinger->getFactory().createMonitoredProducer(producer, mFlinger, this); - mConsumer = - mFlinger->getFactory().createBufferLayerConsumer(consumer, mFlinger->getRenderEngine(), - mTextureName, this); - mConsumer->setConsumerUsageBits(getEffectiveUsage(0)); - - mContentsChangedListener = new ContentsChangedListener(this); - mConsumer->setContentsChangedListener(mContentsChangedListener); - mConsumer->setName(String8(mName.data(), mName.size())); - - mProducer->setMaxDequeuedBufferCount(2); -} - -status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) { - // never allow a surface larger than what our underlying GL implementation - // can handle. - if (mFlinger->exceedsMaxRenderTargetSize(w, h)) { - ALOGE("dimensions too large %" PRIu32 " x %" PRIu32, w, h); - return BAD_VALUE; - } - - setDefaultBufferSize(w, h); - mConsumer->setDefaultBufferFormat(format); - mConsumer->setConsumerUsageBits(getEffectiveUsage(0)); - - return NO_ERROR; -} - -sp<IGraphicBufferProducer> BufferQueueLayer::getProducer() const { - return mProducer; -} - -uint32_t BufferQueueLayer::getProducerStickyTransform() const { - int producerStickyTransform = 0; - int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform); - if (ret != OK) { - ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__, - strerror(-ret), ret); - return 0; - } - return static_cast<uint32_t>(producerStickyTransform); -} - -void BufferQueueLayer::gatherBufferInfo() { - BufferLayer::gatherBufferInfo(); - - mBufferInfo.mDesiredPresentTime = mConsumer->getTimestamp(); - mBufferInfo.mFenceTime = mConsumer->getCurrentFenceTime(); - mBufferInfo.mFence = mConsumer->getCurrentFence(); - mBufferInfo.mTransform = mConsumer->getCurrentTransform(); - mBufferInfo.mDataspace = translateDataspace(mConsumer->getCurrentDataSpace()); - mBufferInfo.mCrop = mConsumer->getCurrentCrop(); - mBufferInfo.mScaleMode = mConsumer->getCurrentScalingMode(); - mBufferInfo.mSurfaceDamage = mConsumer->getSurfaceDamage(); - mBufferInfo.mHdrMetadata = mConsumer->getCurrentHdrMetadata(); - mBufferInfo.mApi = mConsumer->getCurrentApi(); - mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse(); -} - -sp<Layer> BufferQueueLayer::createClone() { - LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); - args.textureName = mTextureName; - sp<BufferQueueLayer> layer = mFlinger->getFactory().createBufferQueueLayer(args); - layer->setInitialValuesForClone(this); - - return layer; -} - -// ----------------------------------------------------------------------- -// Interface implementation for BufferLayerConsumer::ContentsChangedListener -// ----------------------------------------------------------------------- - -void BufferQueueLayer::ContentsChangedListener::onFrameAvailable(const BufferItem& item) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameAvailable(item); - } -} - -void BufferQueueLayer::ContentsChangedListener::onFrameReplaced(const BufferItem& item) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameReplaced(item); - } -} - -void BufferQueueLayer::ContentsChangedListener::onSidebandStreamChanged() { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onSidebandStreamChanged(); - } -} - -void BufferQueueLayer::ContentsChangedListener::onFrameDequeued(const uint64_t bufferId) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameDequeued(bufferId); - } -} - -void BufferQueueLayer::ContentsChangedListener::onFrameDetached(const uint64_t bufferId) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameDetached(bufferId); - } -} - -void BufferQueueLayer::ContentsChangedListener::onFrameCancelled(const uint64_t bufferId) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameCancelled(bufferId); - } -} - -void BufferQueueLayer::ContentsChangedListener::abandon() { - Mutex::Autolock lock(mMutex); - mBufferQueueLayer = nullptr; -} - -// ----------------------------------------------------------------------- - -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h deleted file mode 100644 index e1c80d581d..0000000000 --- a/services/surfaceflinger/BufferQueueLayer.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include "BufferLayer.h" - -#include <utils/String8.h> - -namespace android { - -namespace frametimeline { -class SurfaceFrame; -} - -/* - * A new BufferQueue and a new BufferLayerConsumer are created when the - * BufferLayer is first referenced. - * - * This also implements onFrameAvailable(), which notifies SurfaceFlinger - * that new data has arrived. - */ -class BufferQueueLayer : public BufferLayer { -public: - // Only call while mStateLock is held - explicit BufferQueueLayer(const LayerCreationArgs&); - ~BufferQueueLayer() override; - - // Implements Layer. - const char* getType() const override { return "BufferQueueLayer"; } - - void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override; - - // If a buffer was replaced this frame, release the former buffer - void releasePendingBuffer(nsecs_t dequeueReadyTime) override; - - void setDefaultBufferSize(uint32_t w, uint32_t h) override; - - int32_t getQueuedFrameCount() const override; - - // Returns true if the next buffer should be presented at the expected present time - bool isBufferDue(nsecs_t expectedPresentTime) const override; - - // Implements BufferLayer. - bool fenceHasSignaled() const override; - bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; - - status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format); - sp<IGraphicBufferProducer> getProducer() const; - - void setSizeForTest(uint32_t w, uint32_t h) { - mDrawingState.active_legacy.w = w; - mDrawingState.active_legacy.h = h; - } - -protected: - void gatherBufferInfo() override; - - // ----------------------------------------------------------------------- - // Interface implementation for BufferLayerConsumer::ContentsChangedListener - // ----------------------------------------------------------------------- - class ContentsChangedListener : public BufferLayerConsumer::ContentsChangedListener { - public: - ContentsChangedListener(BufferQueueLayer* bufferQueueLayer) - : mBufferQueueLayer(bufferQueueLayer) {} - void abandon(); - - protected: - void onFrameAvailable(const BufferItem& item) override; - void onFrameReplaced(const BufferItem& item) override; - void onSidebandStreamChanged() override; - void onFrameDequeued(const uint64_t bufferId) override; - void onFrameDetached(const uint64_t bufferId) override; - void onFrameCancelled(const uint64_t bufferId) override; - - private: - BufferQueueLayer* mBufferQueueLayer = nullptr; - Mutex mMutex; - }; - -private: - - bool latchSidebandStream(bool& recomputeVisibleRegions) override; - void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override; - - bool hasFrameUpdate() const override; - - status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) override; - - status_t updateActiveBuffer() override; - status_t updateFrameNumber() override; - void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override; - - sp<Layer> createClone() override; - - void onFirstRef() override; - - void onFrameAvailable(const BufferItem& item); - void onFrameReplaced(const BufferItem& item); - void onSidebandStreamChanged(); - void onFrameDequeued(const uint64_t bufferId); - void onFrameDetached(const uint64_t bufferId); - void onFrameCancelled(const uint64_t bufferId); - - // Temporary - Used only for LEGACY camera mode. - uint32_t getProducerStickyTransform() const; - - sp<BufferLayerConsumer> mConsumer; - sp<IGraphicBufferProducer> mProducer; - - bool mUpdateTexImageFailed{false}; - - uint64_t mPreviousBufferId = 0; - uint64_t mPreviousReleasedFrameNumber = 0; - - // Local copy of the queued contents of the incoming BufferQueue - mutable Mutex mQueueItemLock; - Condition mQueueItemCondition; - - struct BufferData { - BufferData(BufferItem item, std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) - : item(item), surfaceFrame(surfaceFrame) {} - BufferItem item; - std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame; - }; - std::vector<BufferData> mQueueItems; - std::atomic<uint64_t> mLastFrameNumberReceived{0}; - - // thread-safe - std::atomic<int32_t> mQueuedFrames{0}; - - sp<ContentsChangedListener> mContentsChangedListener; - - // The last vsync info received on this layer. This will be used when we get - // a buffer to correlate the buffer with the vsync id. Can only be accessed - // with the SF state lock held. - FrameTimelineInfo mFrameTimelineInfo; -}; - -} // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp deleted file mode 100644 index 3875f151cb..0000000000 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ /dev/null @@ -1,1085 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -//#define LOG_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "BufferStateLayer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "BufferStateLayer.h" - -#include <limits> - -#include <FrameTimeline/FrameTimeline.h> -#include <compositionengine/LayerFECompositionState.h> -#include <gui/BufferQueue.h> -#include <private/gui/SyncFeatures.h> -#include <renderengine/Image.h> -#include "TunnelModeEnabledReporter.h" - -#include "EffectLayer.h" -#include "FrameTracer/FrameTracer.h" -#include "TimeStats/TimeStats.h" - -#define EARLY_RELEASE_ENABLED false - -namespace android { - -using PresentState = frametimeline::SurfaceFrame::PresentState; -namespace { -void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, - const sp<GraphicBuffer>& buffer, uint64_t framenumber, - const sp<Fence>& releaseFence, - uint32_t currentMaxAcquiredBufferCount) { - if (!listener) { - return; - } - listener->onReleaseBuffer({buffer->getId(), framenumber}, - releaseFence ? releaseFence : Fence::NO_FENCE, - currentMaxAcquiredBufferCount); -} -} // namespace - -BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) - : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) { - mDrawingState.dataspace = ui::Dataspace::V0_SRGB; -} - -BufferStateLayer::~BufferStateLayer() { - // The original layer and the clone layer share the same texture and buffer. Therefore, only - // one of the layers, in this case the original layer, needs to handle the deletion. The - // original layer and the clone should be removed at the same time so there shouldn't be any - // issue with the clone layer trying to use the texture. - if (mBufferInfo.mBuffer != nullptr) { - callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber, - mBufferInfo.mFence, - mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( - mOwnerUid)); - } -} - -// ----------------------------------------------------------------------- -// Interface implementation for Layer -// ----------------------------------------------------------------------- -void BufferStateLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) { - // If we are displayed on multiple displays in a single composition cycle then we would - // need to do careful tracking to enable the use of the mLastClientCompositionFence. - // 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 (mClearClientCompositionFenceOnLayerDisplayed) { - mLastClientCompositionFence = nullptr; - } else { - mClearClientCompositionFenceOnLayerDisplayed = true; - } - - // The previous release fence notifies the client that SurfaceFlinger is done with the previous - // buffer that was presented on this layer. The first transaction that came in this frame that - // replaced the previous buffer on this layer needs this release fence, because the fence will - // let the client know when that previous buffer is removed from the screen. - // - // Every other transaction on this layer does not need a release fence because no other - // Transactions that were set on this layer this frame are going to have their preceeding buffer - // removed from the display this frame. - // - // For example, if we have 3 transactions this frame. The first transaction doesn't contain a - // buffer so it doesn't need a previous release fence because the layer still needs the previous - // buffer. The second transaction contains a buffer so it needs a previous release fence because - // the previous buffer will be released this frame. The third transaction also contains a - // buffer. It replaces the buffer in the second transaction. The buffer in the second - // transaction will now no longer be presented so it is released immediately and the third - // transaction doesn't need a previous release fence. - sp<CallbackHandle> ch; - for (auto& handle : mDrawingState.callbackHandles) { - if (handle->releasePreviousBuffer && - mDrawingState.releaseBufferEndpoint == handle->listener) { - ch = handle; - break; - } - } - - // Prevent tracing the same release multiple times. - if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { - mPreviousReleasedFrameNumber = mPreviousFrameNumber; - } - - if (ch != nullptr) { - ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; - ch->previousReleaseFences.emplace_back(std::move(futureFenceResult)); - ch->name = mName; - } -} - -void BufferStateLayer::onSurfaceFrameCreated( - const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) { - while (mPendingJankClassifications.size() >= kPendingClassificationMaxSurfaceFrames) { - // Too many SurfaceFrames pending classification. The front of the deque is probably not - // tracked by FrameTimeline and will never be presented. This will only result in a memory - // leak. - ALOGW("Removing the front of pending jank deque from layer - %s to prevent memory leak", - mName.c_str()); - std::string miniDump = mPendingJankClassifications.front()->miniDump(); - ALOGD("Head SurfaceFrame mini dump\n%s", miniDump.c_str()); - mPendingJankClassifications.pop_front(); - } - mPendingJankClassifications.emplace_back(surfaceFrame); -} - -void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { - for (const auto& handle : mDrawingState.callbackHandles) { - handle->transformHint = mTransformHint; - handle->dequeueReadyTime = dequeueReadyTime; - handle->currentMaxAcquiredBufferCount = - mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); - } - - for (auto& handle : mDrawingState.callbackHandles) { - if (handle->releasePreviousBuffer && - mDrawingState.releaseBufferEndpoint == handle->listener) { - handle->previousReleaseCallbackId = mPreviousReleaseCallbackId; - break; - } - } - - std::vector<JankData> jankData; - jankData.reserve(mPendingJankClassifications.size()); - while (!mPendingJankClassifications.empty() - && mPendingJankClassifications.front()->getJankType()) { - std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame = - mPendingJankClassifications.front(); - mPendingJankClassifications.pop_front(); - jankData.emplace_back( - JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value())); - } - - mFlinger->getTransactionCallbackInvoker().addCallbackHandles( - mDrawingState.callbackHandles, jankData); - - sp<Fence> releaseFence = Fence::NO_FENCE; - for (auto& handle : mDrawingState.callbackHandles) { - if (handle->releasePreviousBuffer && - mDrawingState.releaseBufferEndpoint == handle->listener) { - releaseFence = - handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE; - break; - } - } - - mDrawingState.callbackHandles = {}; -} - -void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence, - const CompositorTiming& compositorTiming) { - for (const auto& handle : mDrawingState.callbackHandles) { - handle->gpuCompositionDoneFence = glDoneFence; - handle->compositorTiming = compositorTiming; - } -} - -bool BufferStateLayer::willPresentCurrentTransaction() const { - // Returns true if the most recent Transaction applied to CurrentState will be presented. - return (getSidebandStreamChanged() || getAutoRefresh() || - (mDrawingState.modified && - (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr))); -} - -Rect BufferStateLayer::getCrop(const Layer::State& s) const { - return s.crop; -} - -bool BufferStateLayer::setTransform(uint32_t transform) { - if (mDrawingState.bufferTransform == transform) return false; - mDrawingState.bufferTransform = transform; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInverse) { - if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false; - mDrawingState.sequence++; - mDrawingState.transformToDisplayInverse = transformToDisplayInverse; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool BufferStateLayer::setCrop(const Rect& crop) { - if (mDrawingState.crop == crop) return false; - mDrawingState.sequence++; - mDrawingState.crop = crop; - - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool BufferStateLayer::setBufferCrop(const Rect& bufferCrop) { - if (mDrawingState.bufferCrop == bufferCrop) return false; - - mDrawingState.sequence++; - mDrawingState.bufferCrop = bufferCrop; - - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool BufferStateLayer::setDestinationFrame(const Rect& destinationFrame) { - if (mDrawingState.destinationFrame == destinationFrame) return false; - - mDrawingState.sequence++; - mDrawingState.destinationFrame = destinationFrame; - - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -static bool assignTransform(ui::Transform* dst, ui::Transform& from) { - if (*dst == from) { - return false; - } - *dst = from; - return true; -} - -// Translate destination frame into scale and position. If a destination frame is not set, use the -// provided scale and position -bool BufferStateLayer::updateGeometry() { - if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) || - mDrawingState.destinationFrame.isEmpty()) { - // If destination frame is not set, use the requested transform set via - // BufferStateLayer::setPosition and BufferStateLayer::setMatrix. - return assignTransform(&mDrawingState.transform, mRequestedTransform); - } - - Rect destRect = mDrawingState.destinationFrame; - int32_t destW = destRect.width(); - int32_t destH = destRect.height(); - if (destRect.left < 0) { - destRect.left = 0; - destRect.right = destW; - } - if (destRect.top < 0) { - destRect.top = 0; - destRect.bottom = destH; - } - - if (!mDrawingState.buffer) { - ui::Transform t; - t.set(destRect.left, destRect.top); - return assignTransform(&mDrawingState.transform, t); - } - - uint32_t bufferWidth = mDrawingState.buffer->getWidth(); - uint32_t bufferHeight = mDrawingState.buffer->getHeight(); - // Undo any transformations on the buffer. - if (mDrawingState.bufferTransform & ui::Transform::ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (mDrawingState.transformToDisplayInverse) { - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - } - - float sx = destW / static_cast<float>(bufferWidth); - float sy = destH / static_cast<float>(bufferHeight); - ui::Transform t; - t.set(sx, 0, 0, sy); - t.set(destRect.left, destRect.top); - return assignTransform(&mDrawingState.transform, t); -} - -bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix) { - if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy && - mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) { - return false; - } - - ui::Transform t; - t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - - mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - - mDrawingState.sequence++; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - - return true; -} - -bool BufferStateLayer::setPosition(float x, float y) { - if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) { - return false; - } - - mRequestedTransform.set(x, y); - - mDrawingState.sequence++; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - - return true; -} - -bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer, - const BufferData& bufferData, nsecs_t postTime, - nsecs_t desiredPresentTime, bool isAutoTimestamp, - std::optional<nsecs_t> dequeueTime, - const FrameTimelineInfo& info) { - ATRACE_CALL(); - - if (!buffer) { - return false; - } - - const bool frameNumberChanged = - bufferData.flags.test(BufferData::BufferDataChange::frameNumberChanged); - const uint64_t frameNumber = - frameNumberChanged ? bufferData.frameNumber : mDrawingState.frameNumber + 1; - - if (mDrawingState.buffer) { - mReleasePreviousBuffer = true; - if (!mBufferInfo.mBuffer || - (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) || - mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) { - // If mDrawingState has a buffer, and we are about to update again - // before swapping to drawing state, then the first buffer will be - // dropped and we should decrement the pending buffer count and - // call any release buffer callbacks if set. - callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, - mDrawingState.acquireFence, - mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( - mOwnerUid)); - decrementPendingBufferCount(); - if (mDrawingState.bufferSurfaceFrameTX != nullptr && - mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) { - addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX); - mDrawingState.bufferSurfaceFrameTX.reset(); - } - } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) { - callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, - mLastClientCompositionFence, - mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( - mOwnerUid)); - mLastClientCompositionFence = nullptr; - } - } - - mDrawingState.frameNumber = frameNumber; - mDrawingState.releaseBufferListener = bufferData.releaseBufferListener; - mDrawingState.buffer = std::move(buffer); - mDrawingState.clientCacheId = bufferData.cachedBuffer; - - mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) - ? bufferData.acquireFence - : Fence::NO_FENCE; - mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(mDrawingState.acquireFence); - if (mDrawingState.acquireFenceTime->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { - // We latched this buffer unsiganled, so we need to pass the acquire fence - // on the callback instead of just the acquire time, since it's unknown at - // this point. - mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFence; - } else { - mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime(); - } - - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - - const int32_t layerId = getSequence(); - mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(), - mOwnerUid, postTime, getGameMode()); - mDrawingState.desiredPresentTime = desiredPresentTime; - mDrawingState.isAutoTimestamp = isAutoTimestamp; - - const nsecs_t presentTime = [&] { - if (!isAutoTimestamp) return desiredPresentTime; - - const auto prediction = - mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(info.vsyncId); - if (prediction.has_value()) return prediction->presentTime; - - return static_cast<nsecs_t>(0); - }(); - - using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); - - setFrameTimelineVsyncForBufferTransaction(info, postTime); - - if (dequeueTime && *dequeueTime != 0) { - const uint64_t bufferId = mDrawingState.buffer->getId(); - mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime, - FrameTracer::FrameEvent::DEQUEUE); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime, - FrameTracer::FrameEvent::QUEUE); - } - - mDrawingState.width = mDrawingState.buffer->getWidth(); - mDrawingState.height = mDrawingState.buffer->getHeight(); - mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint; - return true; -} - -bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) { - if (mDrawingState.dataspace == dataspace) return false; - mDrawingState.dataspace = dataspace; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool BufferStateLayer::setHdrMetadata(const HdrMetadata& hdrMetadata) { - if (mDrawingState.hdrMetadata == hdrMetadata) return false; - mDrawingState.hdrMetadata = hdrMetadata; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool BufferStateLayer::setSurfaceDamageRegion(const Region& surfaceDamage) { - mDrawingState.surfaceDamageRegion = surfaceDamage; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool BufferStateLayer::setApi(int32_t api) { - if (mDrawingState.api == api) return false; - mDrawingState.api = api; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) { - if (mDrawingState.sidebandStream == sidebandStream) return false; - - if (mDrawingState.sidebandStream != nullptr && sidebandStream == nullptr) { - mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); - } else if (sidebandStream != nullptr) { - mFlinger->mTunnelModeEnabledReporter->incrementTunnelModeCount(); - } - - mDrawingState.sidebandStream = sidebandStream; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - if (!mSidebandStreamChanged.exchange(true)) { - // mSidebandStreamChanged was false - mFlinger->onLayerUpdate(); - } - return true; -} - -bool BufferStateLayer::setTransactionCompletedListeners( - const std::vector<sp<CallbackHandle>>& handles) { - // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return - if (handles.empty()) { - mReleasePreviousBuffer = false; - return false; - } - - const bool willPresent = willPresentCurrentTransaction(); - - for (const auto& handle : handles) { - // If this transaction set a buffer on this layer, release its previous buffer - handle->releasePreviousBuffer = mReleasePreviousBuffer; - - // If this layer will be presented in this frame - if (willPresent) { - // If this transaction set an acquire fence on this layer, set its acquire time - handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence; - handle->frameNumber = mDrawingState.frameNumber; - - // Store so latched time and release fence can be set - mDrawingState.callbackHandles.push_back(handle); - - } else { // If this layer will NOT need to be relatched and presented this frame - // Notify the transaction completed thread this handle is done - mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle); - } - } - - mReleasePreviousBuffer = false; - mCallbackHandleAcquireTimeOrFence = -1; - - return willPresent; -} - -bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) { - mDrawingState.sequence++; - mDrawingState.transparentRegionHint = transparent; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -Rect BufferStateLayer::getBufferSize(const State& /*s*/) const { - // for buffer state layers we use the display frame size as the buffer size. - - if (mBufferInfo.mBuffer == nullptr) { - return Rect::INVALID_RECT; - } - - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - - // Undo any transformations on the buffer and return the result. - if (mBufferInfo.mTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - - if (getTransformToDisplayInverse()) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - } - - return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight)); -} - -FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const { - if (mBufferInfo.mBuffer == nullptr) { - return parentBounds; - } - - return getBufferSize(getDrawingState()).toFloatRect(); -} - -// ----------------------------------------------------------------------- - -// ----------------------------------------------------------------------- -// Interface implementation for BufferLayer -// ----------------------------------------------------------------------- -bool BufferStateLayer::fenceHasSignaled() const { - if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { - return true; - } - - const bool fenceSignaled = - getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled; - if (!fenceSignaled) { - mFlinger->mTimeStats->incrementLatchSkipped(getSequence(), - TimeStats::LatchSkipReason::LateAcquire); - } - - return fenceSignaled; -} - -bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const { - if (!hasFrameUpdate() || isRemovedFromCurrentState()) { - return true; - } - - return mDrawingState.isAutoTimestamp || mDrawingState.desiredPresentTime <= expectedPresentTime; -} - -bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) { - for (const auto& handle : mDrawingState.callbackHandles) { - handle->refreshStartTime = refreshStartTime; - } - return BufferLayer::onPreComposition(refreshStartTime); -} - -void BufferStateLayer::setAutoRefresh(bool autoRefresh) { - mDrawingState.autoRefresh = autoRefresh; -} - -bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) { - // We need to update the sideband stream if the layer has both a buffer and a sideband stream. - editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get(); - - if (mSidebandStreamChanged.exchange(false)) { - const State& s(getDrawingState()); - // mSidebandStreamChanged was true - mSidebandStream = s.sidebandStream; - editCompositionState()->sidebandStream = mSidebandStream; - if (mSidebandStream != nullptr) { - setTransactionFlags(eTransactionNeeded); - mFlinger->setTransactionFlags(eTraversalNeeded); - } - recomputeVisibleRegions = true; - - return true; - } - return false; -} - -bool BufferStateLayer::hasFrameUpdate() const { - const State& c(getDrawingState()); - return (mDrawingStateModified || mDrawingState.modified) && (c.buffer != nullptr || c.bgColorLayer != nullptr); -} - -status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, - nsecs_t /*expectedPresentTime*/) { - const State& s(getDrawingState()); - - if (!s.buffer) { - if (s.bgColorLayer) { - for (auto& handle : mDrawingState.callbackHandles) { - handle->latchTime = latchTime; - } - } - return NO_ERROR; - } - - for (auto& handle : mDrawingState.callbackHandles) { - if (handle->frameNumber == mDrawingState.frameNumber) { - handle->latchTime = latchTime; - } - } - - const int32_t layerId = getSequence(); - const uint64_t bufferId = mDrawingState.buffer->getId(); - const uint64_t frameNumber = mDrawingState.frameNumber; - const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence); - mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence); - mFlinger->mTimeStats->setLatchTime(layerId, frameNumber, latchTime); - - mFlinger->mFrameTracer->traceFence(layerId, bufferId, frameNumber, acquireFence, - FrameTracer::FrameEvent::ACQUIRE_FENCE); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, latchTime, - FrameTracer::FrameEvent::LATCH); - - auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX; - if (bufferSurfaceFrame != nullptr && - bufferSurfaceFrame->getPresentState() != PresentState::Presented) { - // Update only if the bufferSurfaceFrame wasn't already presented. A Presented - // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we - // are processing the next state. - addSurfaceFramePresentedForBuffer(bufferSurfaceFrame, - mDrawingState.acquireFenceTime->getSignalTime(), - latchTime); - mDrawingState.bufferSurfaceFrameTX.reset(); - } - - std::deque<sp<CallbackHandle>> remainingHandles; - mFlinger->getTransactionCallbackInvoker() - .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles); - mDrawingState.callbackHandles = remainingHandles; - - mDrawingStateModified = false; - - return NO_ERROR; -} - -status_t BufferStateLayer::updateActiveBuffer() { - const State& s(getDrawingState()); - - if (s.buffer == nullptr) { - return BAD_VALUE; - } - - if (!mBufferInfo.mBuffer || !s.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) { - decrementPendingBufferCount(); - } - - mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber}; - mBufferInfo.mBuffer = s.buffer; - mBufferInfo.mFence = s.acquireFence; - mBufferInfo.mFrameNumber = s.frameNumber; - - return NO_ERROR; -} - -status_t BufferStateLayer::updateFrameNumber() { - // TODO(marissaw): support frame history events - mPreviousFrameNumber = mCurrentFrameNumber; - mCurrentFrameNumber = mDrawingState.frameNumber; - return NO_ERROR; -} - -void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) { - std::lock_guard lock(mMutex); - if (!clientCacheId.isValid()) { - ALOGE("invalid process, failed to erase buffer"); - return; - } - eraseBufferLocked(clientCacheId); -} - -int BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) { - std::lock_guard<std::mutex> lock(mMutex); - auto itr = mCachedBuffers.find(clientCacheId); - if (itr == mCachedBuffers.end()) { - return addCachedBuffer(clientCacheId); - } - auto& [hwcCacheSlot, counter] = itr->second; - counter = mCounter++; - return hwcCacheSlot; -} - -int BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId) - REQUIRES(mMutex) { - if (!clientCacheId.isValid()) { - ALOGE("invalid process, returning invalid slot"); - return BufferQueue::INVALID_BUFFER_SLOT; - } - - ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this)); - - int hwcCacheSlot = getFreeHwcCacheSlot(); - mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++}; - return hwcCacheSlot; -} - -int BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) { - if (mFreeHwcCacheSlots.empty()) { - evictLeastRecentlyUsed(); - } - - int hwcCacheSlot = mFreeHwcCacheSlots.top(); - mFreeHwcCacheSlots.pop(); - return hwcCacheSlot; -} - -void BufferStateLayer::HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) { - uint64_t minCounter = UINT_MAX; - client_cache_t minClientCacheId = {}; - for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) { - const auto& [hwcCacheSlot, counter] = slotCounter; - if (counter < minCounter) { - minCounter = counter; - minClientCacheId = clientCacheId; - } - } - eraseBufferLocked(minClientCacheId); - - ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId, this); -} - -void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId) - REQUIRES(mMutex) { - auto itr = mCachedBuffers.find(clientCacheId); - if (itr == mCachedBuffers.end()) { - return; - } - auto& [hwcCacheSlot, counter] = itr->second; - - // TODO send to hwc cache and resources - - mFreeHwcCacheSlots.push(hwcCacheSlot); - mCachedBuffers.erase(clientCacheId); -} - -void BufferStateLayer::gatherBufferInfo() { - BufferLayer::gatherBufferInfo(); - - const State& s(getDrawingState()); - mBufferInfo.mDesiredPresentTime = s.desiredPresentTime; - mBufferInfo.mFenceTime = std::make_shared<FenceTime>(s.acquireFence); - mBufferInfo.mFence = s.acquireFence; - mBufferInfo.mTransform = s.bufferTransform; - auto lastDataspace = mBufferInfo.mDataspace; - mBufferInfo.mDataspace = translateDataspace(s.dataspace); - if (lastDataspace != mBufferInfo.mDataspace) { - mFlinger->mSomeDataspaceChanged = true; - } - mBufferInfo.mCrop = computeBufferCrop(s); - mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; - mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion; - mBufferInfo.mHdrMetadata = s.hdrMetadata; - mBufferInfo.mApi = s.api; - mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse; - mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId); -} - -uint32_t BufferStateLayer::getEffectiveScalingMode() const { - return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; -} - -Rect BufferStateLayer::computeBufferCrop(const State& s) { - if (s.buffer && !s.bufferCrop.isEmpty()) { - Rect bufferCrop; - s.buffer->getBounds().intersect(s.bufferCrop, &bufferCrop); - return bufferCrop; - } else if (s.buffer) { - return s.buffer->getBounds(); - } else { - return s.bufferCrop; - } -} - -sp<Layer> BufferStateLayer::createClone() { - LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); - args.textureName = mTextureName; - sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args); - layer->mHwcSlotGenerator = mHwcSlotGenerator; - layer->setInitialValuesForClone(this); - return layer; -} - -bool BufferStateLayer::bufferNeedsFiltering() const { - const State& s(getDrawingState()); - if (!s.buffer) { - return false; - } - - int32_t bufferWidth = static_cast<int32_t>(s.buffer->getWidth()); - int32_t bufferHeight = static_cast<int32_t>(s.buffer->getHeight()); - - // Undo any transformations on the buffer and return the result. - if (s.bufferTransform & ui::Transform::ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - - if (s.transformToDisplayInverse) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - } - - const Rect layerSize{getBounds()}; - return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight; -} - -void BufferStateLayer::decrementPendingBufferCount() { - int32_t pendingBuffers = --mPendingBufferTransactions; - tracePendingBufferCount(pendingBuffers); -} - -void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { - ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); -} - - -/* - * We don't want to send the layer's transform to input, but rather the - * parent's transform. This is because BufferStateLayer's transform is - * information about how the buffer is placed on screen. The parent's - * transform makes more sense to send since it's information about how the - * layer is placed on screen. This transform is used by input to determine - * how to go from screen space back to window space. - */ -ui::Transform BufferStateLayer::getInputTransform() const { - sp<Layer> parent = mDrawingParent.promote(); - if (parent == nullptr) { - return ui::Transform(); - } - - return parent->getTransform(); -} - -/** - * Similar to getInputTransform, we need to update the bounds to include the transform. - * This is because bounds for BSL doesn't include buffer transform, where the input assumes - * that's already included. - */ -Rect BufferStateLayer::getInputBounds() const { - Rect bufferBounds = getCroppedBufferSize(getDrawingState()); - if (mDrawingState.transform.getType() == ui::Transform::IDENTITY || !bufferBounds.isValid()) { - return bufferBounds; - } - return mDrawingState.transform.transform(bufferBounds); -} - -bool BufferStateLayer::simpleBufferUpdate(const layer_state_t& s) const { - const uint64_t requiredFlags = layer_state_t::eBufferChanged; - - const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged | - layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged | - layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged | - layer_state_t::eLayerStackChanged | layer_state_t::eAutoRefreshChanged | - layer_state_t::eReparent; - - const uint64_t allowedFlags = layer_state_t::eHasListenerCallbacksChanged | - layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFrameRateChanged | - layer_state_t::eSurfaceDamageRegionChanged | layer_state_t::eApiChanged | - layer_state_t::eMetadataChanged | layer_state_t::eDropInputModeChanged | - layer_state_t::eInputInfoChanged; - - if ((s.what & requiredFlags) != requiredFlags) { - ALOGV("%s: false [missing required flags 0x%" PRIx64 "]", __func__, - (s.what | requiredFlags) & ~s.what); - return false; - } - - if (s.what & deniedFlags) { - ALOGV("%s: false [has denied flags 0x%" PRIx64 "]", __func__, s.what & deniedFlags); - return false; - } - - if (s.what & allowedFlags) { - ALOGV("%s: [has allowed flags 0x%" PRIx64 "]", __func__, s.what & allowedFlags); - } - - if (s.what & layer_state_t::ePositionChanged) { - if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) { - ALOGV("%s: false [ePositionChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eAlphaChanged) { - if (mDrawingState.color.a != s.alpha) { - ALOGV("%s: false [eAlphaChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eColorTransformChanged) { - if (mDrawingState.colorTransform != s.colorTransform) { - ALOGV("%s: false [eColorTransformChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eBackgroundColorChanged) { - if (mDrawingState.bgColorLayer || s.bgColorAlpha != 0) { - ALOGV("%s: false [eBackgroundColorChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eMatrixChanged) { - if (mRequestedTransform.dsdx() != s.matrix.dsdx || - mRequestedTransform.dtdy() != s.matrix.dtdy || - mRequestedTransform.dtdx() != s.matrix.dtdx || - mRequestedTransform.dsdy() != s.matrix.dsdy) { - ALOGV("%s: false [eMatrixChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eCornerRadiusChanged) { - if (mDrawingState.cornerRadius != s.cornerRadius) { - ALOGV("%s: false [eCornerRadiusChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) { - if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) { - ALOGV("%s: false [eBackgroundBlurRadiusChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eTransformChanged) { - if (mDrawingState.bufferTransform != s.transform) { - ALOGV("%s: false [eTransformChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eTransformToDisplayInverseChanged) { - if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) { - ALOGV("%s: false [eTransformToDisplayInverseChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eCropChanged) { - if (mDrawingState.crop != s.crop) { - ALOGV("%s: false [eCropChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eDataspaceChanged) { - if (mDrawingState.dataspace != s.dataspace) { - ALOGV("%s: false [eDataspaceChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eHdrMetadataChanged) { - if (mDrawingState.hdrMetadata != s.hdrMetadata) { - ALOGV("%s: false [eHdrMetadataChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eSidebandStreamChanged) { - if (mDrawingState.sidebandStream != s.sidebandStream) { - ALOGV("%s: false [eSidebandStreamChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eColorSpaceAgnosticChanged) { - if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) { - ALOGV("%s: false [eColorSpaceAgnosticChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eShadowRadiusChanged) { - if (mDrawingState.shadowRadius != s.shadowRadius) { - ALOGV("%s: false [eShadowRadiusChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eFixedTransformHintChanged) { - if (mDrawingState.fixedTransformHint != s.fixedTransformHint) { - ALOGV("%s: false [eFixedTransformHintChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eTrustedOverlayChanged) { - if (mDrawingState.isTrustedOverlay != s.isTrustedOverlay) { - ALOGV("%s: false [eTrustedOverlayChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eStretchChanged) { - StretchEffect temp = s.stretchEffect; - temp.sanitize(); - if (mDrawingState.stretchEffect != temp) { - ALOGV("%s: false [eStretchChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eBufferCropChanged) { - if (mDrawingState.bufferCrop != s.bufferCrop) { - ALOGV("%s: false [eBufferCropChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eDestinationFrameChanged) { - if (mDrawingState.destinationFrame != s.destinationFrame) { - ALOGV("%s: false [eDestinationFrameChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eDimmingEnabledChanged) { - if (mDrawingState.dimmingEnabled != s.dimmingEnabled) { - ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__); - return false; - } - } - - ALOGV("%s: true", __func__); - return true; -} - -} // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h deleted file mode 100644 index 3f0dbe4039..0000000000 --- a/services/surfaceflinger/BufferStateLayer.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include "BufferLayer.h" -#include "Layer.h" - -#include <renderengine/Image.h> -#include <renderengine/RenderEngine.h> -#include <system/window.h> -#include <utils/String8.h> - -#include <stack> - -namespace android { - -class SlotGenerationTest; - -class BufferStateLayer : public BufferLayer { -public: - explicit BufferStateLayer(const LayerCreationArgs&); - - ~BufferStateLayer() override; - - // Implements Layer. - const char* getType() const override { return "BufferStateLayer"; } - - void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override; - - void releasePendingBuffer(nsecs_t dequeueReadyTime) override; - - void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence, - const CompositorTiming& compositorTiming) override; - - bool isBufferDue(nsecs_t /*expectedPresentTime*/) const override { return true; } - - Region getActiveTransparentRegion(const Layer::State& s) const override { - return s.transparentRegionHint; - } - Rect getCrop(const Layer::State& s) const; - - bool setTransform(uint32_t transform) override; - bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; - bool setCrop(const Rect& crop) override; - bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */, - const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, - bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime, - const FrameTimelineInfo& info) override; - bool setDataspace(ui::Dataspace dataspace) override; - bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; - bool setSurfaceDamageRegion(const Region& surfaceDamage) override; - bool setApi(int32_t api) override; - bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override; - bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override; - bool setPosition(float /*x*/, float /*y*/) override; - bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/); - - // Override to ignore legacy layer state properties that are not used by BufferStateLayer - bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } - bool setTransparentRegionHint(const Region& transparent) override; - - Rect getBufferSize(const State& s) const override; - FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; - void setAutoRefresh(bool autoRefresh) override; - - bool setBufferCrop(const Rect& bufferCrop) override; - bool setDestinationFrame(const Rect& destinationFrame) override; - bool updateGeometry() override; - - // ----------------------------------------------------------------------- - - // ----------------------------------------------------------------------- - // Interface implementation for BufferLayer - // ----------------------------------------------------------------------- - bool fenceHasSignaled() const override; - bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; - bool onPreComposition(nsecs_t refreshStartTime) override; - uint32_t getEffectiveScalingMode() const override; - - // See mPendingBufferTransactions - void decrementPendingBufferCount(); - std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; } - std::string getPendingBufferCounterName() override { return mBlastTransactionName; } - - bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const override { return true; } - -protected: - void gatherBufferInfo() override; - void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame); - ui::Transform getInputTransform() const override; - Rect getInputBounds() const override; - -private: - friend class SlotGenerationTest; - friend class TransactionFrameTracerTest; - friend class TransactionSurfaceFrameTest; - - inline void tracePendingBufferCount(int32_t pendingBuffers); - - bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime, - nsecs_t requestedPresentTime); - - bool latchSidebandStream(bool& recomputeVisibleRegions) override; - - bool hasFrameUpdate() const override; - - status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) override; - - status_t updateActiveBuffer() override; - status_t updateFrameNumber() override; - - sp<Layer> createClone() override; - - // Crop that applies to the buffer - Rect computeBufferCrop(const State& s); - - bool willPresentCurrentTransaction() const; - - bool bufferNeedsFiltering() const override; - - bool simpleBufferUpdate(const layer_state_t& s) const override; - - ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; - uint64_t mPreviousReleasedFrameNumber = 0; - - uint64_t mPreviousBarrierFrameNumber = 0; - - bool mReleasePreviousBuffer = false; - - // Stores the last set acquire fence signal time used to populate the callback handle's acquire - // time. - std::variant<nsecs_t, sp<Fence>> mCallbackHandleAcquireTimeOrFence = -1; - - std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications; - // An upper bound on the number of SurfaceFrames in the pending classifications deque. - static constexpr int kPendingClassificationMaxSurfaceFrames = 25; - - const std::string mBlastTransactionName{"BufferTX - " + mName}; - // This integer is incremented everytime a buffer arrives at the server for this layer, - // and decremented when a buffer is dropped or latched. When changed the integer is exported - // to systrace with ATRACE_INT and mBlastTransactionName. This way when debugging perf it is - // possible to see when a buffer arrived at the server, and in which frame it latched. - // - // You can understand the trace this way: - // - If the integer increases, a buffer arrived at the server. - // - If the integer decreases in latchBuffer, that buffer was latched - // - If the integer decreases in setBuffer or doTransaction, a buffer was dropped - std::atomic<int32_t> mPendingBufferTransactions{0}; - - // Contains requested position and matrix updates. This will be applied if the client does - // not specify a destination frame. - ui::Transform mRequestedTransform; - - // TODO(marissaw): support sticky transform for LEGACY camera mode - - class HwcSlotGenerator : public ClientCache::ErasedRecipient { - public: - HwcSlotGenerator() { - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - mFreeHwcCacheSlots.push(i); - } - } - - void bufferErased(const client_cache_t& clientCacheId); - - int getHwcCacheSlot(const client_cache_t& clientCacheId); - - private: - friend class SlotGenerationTest; - int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex); - int getFreeHwcCacheSlot() REQUIRES(mMutex); - void evictLeastRecentlyUsed() REQUIRES(mMutex); - void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex); - - struct CachedBufferHash { - std::size_t operator()(const client_cache_t& clientCacheId) const { - return std::hash<uint64_t>{}(clientCacheId.id); - } - }; - - std::mutex mMutex; - - std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>, - CachedBufferHash> - mCachedBuffers GUARDED_BY(mMutex); - std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex); - - // The cache increments this counter value when a slot is updated or used. - // Used to track the least recently-used buffer - uint64_t mCounter = 0; - }; - - sp<HwcSlotGenerator> mHwcSlotGenerator; -}; - -} // namespace android diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 6d7b732b36..3685bb4ecd 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -21,12 +21,16 @@ #include <private/android_filesystem_config.h> +#include <gui/AidlStatusUtil.h> + #include "Client.h" #include "Layer.h" #include "SurfaceFlinger.h" namespace android { +using gui::aidl_utils::binderStatusFromStatusT; + // --------------------------------------------------------------------------- const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); @@ -72,52 +76,90 @@ sp<Layer> Client::getLayerUser(const sp<IBinder>& handle) const return lbc; } -status_t Client::createSurface(const String8& name, uint32_t /* w */, uint32_t /* h */, - PixelFormat /* format */, uint32_t flags, - const sp<IBinder>& parentHandle, LayerMetadata metadata, - sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* /* gbp */, - int32_t* outLayerId, uint32_t* outTransformHint) { +binder::Status Client::createSurface(const std::string& name, int32_t flags, + const sp<IBinder>& parent, const gui::LayerMetadata& metadata, + gui::CreateSurfaceResult* outResult) { // We rely on createLayer to check permissions. - LayerCreationArgs args(mFlinger.get(), this, name.c_str(), flags, std::move(metadata)); - return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, nullptr, - outTransformHint); -} - -status_t Client::createWithSurfaceParent(const String8& /* name */, uint32_t /* w */, - uint32_t /* h */, PixelFormat /* format */, - uint32_t /* flags */, - const sp<IGraphicBufferProducer>& /* parent */, - LayerMetadata /* metadata */, sp<IBinder>* /* handle */, - sp<IGraphicBufferProducer>* /* gbp */, - int32_t* /* outLayerId */, - uint32_t* /* outTransformHint */) { - // This api does not make sense with blast since SF no longer tracks IGBP. This api should be - // removed. - return BAD_VALUE; -} - -status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle, - int32_t* outLayerId) { - LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, LayerMetadata()); - return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId); + sp<IBinder> handle; + int32_t layerId; + uint32_t transformHint; + LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), name.c_str(), + static_cast<uint32_t>(flags), std::move(metadata)); + const status_t status = + mFlinger->createLayer(args, &handle, parent, &layerId, nullptr, &transformHint); + if (status == NO_ERROR) { + outResult->handle = handle; + outResult->layerId = layerId; + outResult->transformHint = static_cast<int32_t>(transformHint); + } + return binderStatusFromStatusT(status); } -status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const { +binder::Status Client::clearLayerFrameStats(const sp<IBinder>& handle) { + status_t status; sp<Layer> layer = getLayerUser(handle); if (layer == nullptr) { - return NAME_NOT_FOUND; + status = NAME_NOT_FOUND; + } else { + layer->clearFrameStats(); + status = NO_ERROR; } - layer->clearFrameStats(); - return NO_ERROR; + return binderStatusFromStatusT(status); } -status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const { +binder::Status Client::getLayerFrameStats(const sp<IBinder>& handle, gui::FrameStats* outStats) { + status_t status; sp<Layer> layer = getLayerUser(handle); if (layer == nullptr) { - return NAME_NOT_FOUND; + status = NAME_NOT_FOUND; + } else { + FrameStats stats; + layer->getFrameStats(&stats); + outStats->refreshPeriodNano = stats.refreshPeriodNano; + outStats->desiredPresentTimesNano.reserve(stats.desiredPresentTimesNano.size()); + for (const auto& t : stats.desiredPresentTimesNano) { + outStats->desiredPresentTimesNano.push_back(t); + } + outStats->actualPresentTimesNano.reserve(stats.actualPresentTimesNano.size()); + for (const auto& t : stats.actualPresentTimesNano) { + outStats->actualPresentTimesNano.push_back(t); + } + outStats->frameReadyTimesNano.reserve(stats.frameReadyTimesNano.size()); + for (const auto& t : stats.frameReadyTimesNano) { + outStats->frameReadyTimesNano.push_back(t); + } + status = NO_ERROR; } - layer->getFrameStats(outStats); - return NO_ERROR; + return binderStatusFromStatusT(status); +} + +binder::Status Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, + gui::MirrorSurfaceResult* outResult) { + sp<IBinder> handle; + int32_t layerId; + LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), "MirrorRoot", + 0 /* flags */, gui::LayerMetadata()); + status_t status = mFlinger->mirrorLayer(args, mirrorFromHandle, &handle, &layerId); + if (status == NO_ERROR) { + outResult->handle = handle; + outResult->layerId = layerId; + } + return binderStatusFromStatusT(status); +} + +binder::Status Client::mirrorDisplay(int64_t displayId, gui::MirrorSurfaceResult* outResult) { + sp<IBinder> handle; + int32_t layerId; + LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), + "MirrorRoot-" + std::to_string(displayId), 0 /* flags */, + gui::LayerMetadata()); + std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId)); + status_t status = mFlinger->mirrorDisplay(*id, args, &handle, &layerId); + if (status == NO_ERROR) { + outResult->handle = handle; + outResult->layerId = layerId; + } + return binderStatusFromStatusT(status); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h index 15cd763822..4e59dfdf3a 100644 --- a/services/surfaceflinger/Client.h +++ b/services/surfaceflinger/Client.h @@ -24,15 +24,14 @@ #include <utils/KeyedVector.h> #include <utils/Mutex.h> -#include <gui/ISurfaceComposerClient.h> +#include <android/gui/BnSurfaceComposerClient.h> namespace android { class Layer; class SurfaceFlinger; -class Client : public BnSurfaceComposerClient -{ +class Client : public gui::BnSurfaceComposerClient { public: explicit Client(const sp<SurfaceFlinger>& flinger); ~Client() = default; @@ -47,25 +46,20 @@ public: private: // ISurfaceComposerClient interface - virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint = nullptr); - virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, - const sp<IGraphicBufferProducer>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint = nullptr); + binder::Status createSurface(const std::string& name, int32_t flags, const sp<IBinder>& parent, + const gui::LayerMetadata& metadata, + gui::CreateSurfaceResult* outResult) override; - status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* handle, - int32_t* outLayerId); + binder::Status clearLayerFrameStats(const sp<IBinder>& handle) override; - virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const; + binder::Status getLayerFrameStats(const sp<IBinder>& handle, + gui::FrameStats* outStats) override; - virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const; + binder::Status mirrorSurface(const sp<IBinder>& mirrorFromHandle, + gui::MirrorSurfaceResult* outResult) override; + + binder::Status mirrorDisplay(int64_t displayId, gui::MirrorSurfaceResult* outResult) override; // constant sp<SurfaceFlinger> mFlinger; diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index 3c7b9d93aa..cf932a86c2 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -30,7 +30,7 @@ namespace android { ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache); -ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {} +ClientCache::ClientCache() : mDeathRecipient(sp<CacheDeathRecipient>::make()) {} bool ClientCache::getBuffer(const client_cache_t& cacheId, ClientCacheBuffer** outClientCacheBuffer) { diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 11a9e19db8..b5d2ad0f74 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -9,7 +9,10 @@ package { cc_defaults { name: "libcompositionengine_defaults", - defaults: ["surfaceflinger_defaults"], + defaults: [ + "android.hardware.graphics.composer3-ndk_shared", + "surfaceflinger_defaults", + ], cflags: [ "-DLOG_TAG=\"CompositionEngine\"", "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", @@ -20,7 +23,6 @@ cc_defaults { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.graphics.composer3-V1-ndk", "android.hardware.power@1.0", "android.hardware.power@1.3", "android.hardware.power-V2-cpp", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h index 3faa068c03..6832ae12df 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h @@ -18,9 +18,10 @@ #include <TimeStats/TimeStats.h> #include <utils/Timers.h> - #include <memory> +#include "Feature.h" + namespace android { class HWComposer; @@ -72,6 +73,8 @@ public: // TODO(b/121291683): These will become private/internal virtual void preComposition(CompositionRefreshArgs&) = 0; + virtual FeatureFlags getFeatureFlags() const = 0; + // Debugging virtual void dump(std::string&) const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index f201751d59..f861fc97e4 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -32,6 +32,11 @@ namespace android::compositionengine { using Layers = std::vector<sp<compositionengine::LayerFE>>; using Outputs = std::vector<std::shared_ptr<compositionengine::Output>>; +struct BorderRenderInfo { + float width = 0; + half4 color; + std::vector<int32_t> layerIds; +}; /** * A parameter object for refreshing a set of outputs */ @@ -90,6 +95,8 @@ struct CompositionRefreshArgs { // If set, a frame has been scheduled for that time. std::optional<std::chrono::steady_clock::time_point> scheduledFrameTime; + + std::vector<BorderRenderInfo> borderInfoList; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/TestUtils.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h index c80fde6ead..ee8000ae18 100644 --- a/services/surfaceflinger/CompositionEngine/tests/TestUtils.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright 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. @@ -13,19 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #pragma once -#include <future> +#include <ftl/flags.h> +#include <cstdint> namespace android::compositionengine { -namespace { -template <class T> -std::future<T> futureOf(T obj) { - std::promise<T> resultPromise; - std::future<T> resultFuture = resultPromise.get_future(); - resultPromise.set_value(std::move(obj)); - return resultFuture; -} -} // namespace -} // namespace android::compositionengine +enum class Feature : int32_t { + kSnapshotLayerMetadata = 1 << 0, +}; + +using FeatureFlags = ftl::Flags<Feature>; + +} // namespace android::compositionengine
\ No newline at end of file diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index ec610c1b1d..fe8cad502b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -20,8 +20,6 @@ #include <ostream> #include <unordered_set> -#include <compositionengine/FenceResult.h> - // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" @@ -33,6 +31,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include <ftl/future.h> +#include <ui/FenceResult.h> #include <utils/RefBase.h> #include <utils/Timers.h> @@ -40,6 +39,10 @@ namespace android { class Fence; +namespace gui { +struct LayerMetadata; +} + namespace compositionengine { struct LayerFECompositionState; @@ -54,31 +57,8 @@ public: // Called before composition starts. Should return true if this layer has // pending updates which would require an extra display refresh cycle to // process. - virtual bool onPreComposition(nsecs_t refreshStartTime) = 0; - - // Used with latchCompositionState() - enum class StateSubset { - // Gets the basic geometry (bounds, transparent region, visibility, - // transforms, alpha) for the layer, for computing visibility and - // coverage. - BasicGeometry, - - // Gets the full geometry (crops, buffer transforms, metadata) and - // content (buffer or color) state for the layer. - GeometryAndContent, - - // Gets the per frame content (buffer or color) state for the layer. - Content, - - // Gets the cursor state for the layer. - Cursor, - }; - - // Prepares the output-independent composition state for the layer. The - // StateSubset argument selects what portion of the state is actually needed - // by the CompositionEngine code, since computing everything may be - // expensive. - virtual void prepareCompositionState(StateSubset) = 0; + virtual bool onPreComposition(nsecs_t refreshStartTime, + bool updatingOutputGeometryThisFrame) = 0; struct ClientCompositionTargetSettings { enum class BlurSetting { @@ -150,11 +130,11 @@ public: uint64_t frameNumber = 0; }; - // Returns the z-ordered list of LayerSettings to pass to RenderEngine::drawLayers. The list - // may contain shadows casted by the layer or the content of the layer itself. If the layer - // does not render then an empty list will be returned. - virtual std::vector<LayerSettings> prepareClientCompositionList( - ClientCompositionTargetSettings&) = 0; + // Returns the LayerSettings to pass to RenderEngine::drawLayers. The state may contain shadows + // casted by the layer or the content of the layer itself. If the layer does not render then an + // empty optional will be returned. + virtual std::optional<LayerSettings> prepareClientComposition( + ClientCompositionTargetSettings&) const = 0; // Called after the layer is displayed to update the presentation fence virtual void onLayerDisplayed(ftl::SharedFuture<FenceResult>) = 0; @@ -168,6 +148,8 @@ public: // Whether the layer should be rendered with rounded corners. virtual bool hasRoundedCorners() const = 0; virtual void setWasClientComposed(const sp<Fence>&) {} + virtual const gui::LayerMetadata* getMetadata() const = 0; + virtual const gui::LayerMetadata* getRelativeMetadata() const = 0; }; // TODO(b/121291683): Specialize std::hash<> for sp<T> so these and others can diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 2203639b1a..874b330c1c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -262,9 +262,6 @@ public: // Presents the output, finalizing all composition details virtual void present(const CompositionRefreshArgs&) = 0; - // Latches the front-end layer state for each output layer - virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0; - // Enables predicting composition strategy to run client composition earlier virtual void setPredictCompositionStrategy(bool) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index bf5184e997..6d0c395b2f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -126,9 +126,9 @@ public: // Returns true if the composition settings scale pixels virtual bool needsFiltering() const = 0; - // Returns a composition list to be used by RenderEngine if the layer has been overridden + // Returns LayerSettings to be used by RenderEngine if the layer has been overridden // during the composition process - virtual std::vector<LayerFE::LayerSettings> getOverrideCompositionList() const = 0; + virtual std::optional<LayerFE::LayerSettings> getOverrideCompositionSettings() const = 0; // Debugging virtual void dump(std::string& result) const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index 9ee779cca1..585467456c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -91,16 +91,9 @@ public: // Called after the HWC calls are made to present the display virtual void onPresentDisplayCompleted() = 0; - // Called after the surface has been rendering to signal the surface should - // be made ready for displaying - virtual void flip() = 0; - // Debugging - Dumps the state of the RenderSurface to a string virtual void dump(std::string& result) const = 0; - // Debugging - gets the page flip count for the RenderSurface - virtual std::uint32_t getPageFlipCount() const = 0; - // Returns true if the render surface supports client composition prediction. virtual bool supportsCompositionStrategyPrediction() const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h index 386808d714..dd4dbe9318 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -48,11 +48,11 @@ public: void preComposition(CompositionRefreshArgs&) override; + FeatureFlags getFeatureFlags() const override; + // Debugging void dump(std::string&) const override; - void updateLayerStateFromFE(CompositionRefreshArgs& args); - // Testing void setNeedsAnotherUpdateForTest(bool); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index df721cdc89..23d5570096 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -89,7 +89,6 @@ public: compositionengine::Output::CoverageState&) override; void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override; - void updateLayerStateFromFE(const CompositionRefreshArgs&) const override; void updateCompositionState(const compositionengine::CompositionRefreshArgs&) override; void planComposition() override; void writeCompositionState(const compositionengine::CompositionRefreshArgs&) override; @@ -152,8 +151,11 @@ protected: virtual const compositionengine::CompositionEngine& getCompositionEngine() const = 0; virtual void dumpState(std::string& out) const = 0; + bool mustRecompose() const; + private: void dirtyEntireOutput(); + void updateCompositionStateForBorder(const compositionengine::CompositionRefreshArgs&); compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const; void finishPrepareFrame(); ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; @@ -170,6 +172,9 @@ private: std::unique_ptr<ClientCompositionRequestCache> mClientCompositionRequestCache; std::unique_ptr<planner::Planner> mPlanner; std::unique_ptr<HwcAsyncWorker> mHwComposerAsyncWorker; + + // Whether the content must be recomposed this frame. + bool mMustRecompose = false; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 7709b967b6..c29165210d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -33,6 +33,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include <compositionengine/ProjectionSpace.h> +#include <renderengine/BorderRenderInfo.h> #include <ui/LayerStack.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -164,6 +165,8 @@ struct OutputCompositionState { bool treat170mAsSrgb = false; + std::vector<renderengine::BorderRenderInfo> borderInfoList; + uint64_t lastOutputLayerHash = 0; uint64_t outputLayerHash = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index ecd432f629..6d4abf9f47 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -18,6 +18,7 @@ #include <cstdint> #include <memory> +#include <optional> #include <string> #include <compositionengine/LayerFE.h> @@ -57,7 +58,7 @@ public: void prepareForDeviceLayerRequests() override; void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; bool needsFiltering() const override; - std::vector<LayerFE::LayerSettings> getOverrideCompositionList() const override; + std::optional<LayerFE::LayerSettings> getOverrideCompositionSettings() const override; void dump(std::string&) const override; virtual FloatRect calculateOutputSourceCrop(uint32_t internalDisplayRotationFlags) const; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index e4cb113645..1c14a43920 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -62,15 +62,12 @@ public: base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; - void flip() override; bool supportsCompositionStrategyPrediction() const override; // Debugging void dump(std::string& result) const override; - std::uint32_t getPageFlipCount() const override; // Testing - void setPageFlipCountForTest(std::uint32_t); void setSizeForTest(const ui::Size&); std::shared_ptr<renderengine::ExternalTexture>& mutableTextureForTest(); base::unique_fd& mutableBufferReadyForTest(); @@ -89,7 +86,6 @@ private: ui::Size mSize; const size_t mMaxTextureCacheSize; bool mProtected{false}; - std::uint32_t mPageFlipCount{0}; }; std::unique_ptr<compositionengine::RenderSurface> createRenderSurface( diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h index f953d0b7d0..a48cc6f975 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -53,6 +53,8 @@ public: MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&)); + MOCK_CONST_METHOD0(getFeatureFlags, FeatureFlags()); + MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 1c5c10f823..14922a4e0d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -42,18 +42,19 @@ public: MOCK_CONST_METHOD0(getCompositionState, const LayerFECompositionState*()); - MOCK_METHOD1(onPreComposition, bool(nsecs_t)); + MOCK_METHOD2(onPreComposition, bool(nsecs_t, bool)); - MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset)); - MOCK_METHOD1(prepareClientCompositionList, - std::vector<compositionengine::LayerFE::LayerSettings>( - compositionengine::LayerFE::ClientCompositionTargetSettings&)); + MOCK_CONST_METHOD1(prepareClientComposition, + std::optional<compositionengine::LayerFE::LayerSettings>( + compositionengine::LayerFE::ClientCompositionTargetSettings&)); MOCK_METHOD(void, onLayerDisplayed, (ftl::SharedFuture<FenceResult>), (override)); MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); MOCK_CONST_METHOD0(hasRoundedCorners, bool()); + MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*()); + MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 2a04949cff..7592cac582 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -91,7 +91,6 @@ public: void(sp<compositionengine::LayerFE>&, compositionengine::Output::CoverageState&)); MOCK_METHOD1(setReleasedLayers, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&)); MOCK_METHOD1(updateCompositionState, void(const CompositionRefreshArgs&)); MOCK_METHOD0(planComposition, void()); MOCK_METHOD1(writeCompositionState, void(const CompositionRefreshArgs&)); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index a6cb811468..c22f1bf260 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -16,6 +16,8 @@ #pragma once +#include <optional> + #include <compositionengine/CompositionEngine.h> #include <compositionengine/LayerFE.h> #include <compositionengine/Output.h> @@ -51,7 +53,7 @@ public: MOCK_METHOD0(prepareForDeviceLayerRequests, void()); MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request)); MOCK_CONST_METHOD0(needsFiltering, bool()); - MOCK_CONST_METHOD0(getOverrideCompositionList, std::vector<LayerFE::LayerSettings>()); + MOCK_CONST_METHOD0(getOverrideCompositionSettings, std::optional<LayerFE::LayerSettings>()); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index e12aebb50c..af8d4bcb0b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -42,9 +42,7 @@ public: MOCK_METHOD1(dequeueBuffer, std::shared_ptr<renderengine::ExternalTexture>(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd)); MOCK_METHOD0(onPresentDisplayCompleted, void()); - MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); - MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t()); MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool()); }; diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 6203dc6737..a4e1fff2ad 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -105,8 +105,6 @@ void CompositionEngine::present(CompositionRefreshArgs& args) { } } - updateLayerStateFromFE(args); - for (const auto& output : args.outputs) { output->present(args); } @@ -119,8 +117,6 @@ void CompositionEngine::updateCursorAsync(CompositionRefreshArgs& args) { for (const auto& output : args.outputs) { for (auto* layer : output->getOutputLayersOrderedByZ()) { if (layer->isHardwareCursor()) { - // Latch the cursor composition state from each front-end layer. - layer->getLayerFE().prepareCompositionState(LayerFE::StateSubset::Cursor); layer->writeCursorPositionToHWC(); } } @@ -136,7 +132,7 @@ void CompositionEngine::preComposition(CompositionRefreshArgs& args) { mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC); for (auto& layer : args.layers) { - if (layer->onPreComposition(mRefreshStartTime)) { + if (layer->onPreComposition(mRefreshStartTime, args.updatingOutputGeometryThisFrame)) { needsAnotherUpdate = true; } } @@ -144,6 +140,10 @@ void CompositionEngine::preComposition(CompositionRefreshArgs& args) { mNeedsAnotherUpdate = needsAnotherUpdate; } +FeatureFlags CompositionEngine::getFeatureFlags() const { + return {}; +} + void CompositionEngine::dump(std::string&) const { // The base class has no state to dump, but derived classes might. } @@ -152,12 +152,5 @@ void CompositionEngine::setNeedsAnotherUpdateForTest(bool value) { mNeedsAnotherUpdate = value; } -void CompositionEngine::updateLayerStateFromFE(CompositionRefreshArgs& args) { - // Update the composition state from each front-end layer - for (const auto& output : args.outputs) { - output->updateLayerStateFromFE(args); - } -} - } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 1ec6449ed0..0b69d44ac4 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -196,7 +196,7 @@ void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& }); if (hasQueuedFrames) { - releasedLayers.emplace_back(layerFE); + releasedLayers.emplace_back(wp<LayerFE>::fromExisting(layerFE)); } } @@ -248,7 +248,7 @@ bool Display::chooseCompositionStrategy( return false; } - const nsecs_t startTime = systemTime(); + const TimePoint startTime = TimePoint::now(); // Get any composition changes requested by the HWC device, and apply them. std::optional<android::HWComposer::DeviceRequestedChanges> changes; @@ -266,7 +266,7 @@ bool Display::chooseCompositionStrategy( } if (isPowerHintSessionEnabled()) { - mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime()); + mPowerAdvisor->setHwcValidateTiming(mId, startTime, TimePoint::now()); mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition); } @@ -370,7 +370,7 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { auto& hwc = getCompositionEngine().getHwComposer(); - const nsecs_t startTime = systemTime(); + const TimePoint startTime = TimePoint::now(); if (isPowerHintSessionEnabled()) { if (!getCompositionEngine().getHwComposer().getComposer()->isSupported( @@ -384,7 +384,7 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { getState().previousPresentFence); if (isPowerHintSessionEnabled()) { - mPowerAdvisor->setHwcPresentTiming(mId, startTime, systemTime()); + mPowerAdvisor->setHwcPresentTiming(mId, startTime, TimePoint::now()); } fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt); @@ -426,7 +426,7 @@ void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refre // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or // 2) There is work to be done (the dirty region isn't empty) - if (GpuVirtualDisplayId::tryCast(mId) && getDirtyRegion().isEmpty()) { + if (GpuVirtualDisplayId::tryCast(mId) && !mustRecompose()) { ALOGV("Skipping display composition"); return; } diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index b724daa8ce..e3f3680c1c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -501,7 +501,6 @@ void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, // appear on multiple outputs. if (!coverage.latchedLayers.count(layerFE)) { coverage.latchedLayers.insert(layerFE); - layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry); } // Only consider the layers on this output @@ -725,14 +724,6 @@ void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) // The base class does nothing with this call. } -void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const { - for (auto* layer : getOutputLayersOrderedByZ()) { - layer->getLayerFE().prepareCompositionState( - args.updatingGeometryThisFrame ? LayerFE::StateSubset::GeometryAndContent - : LayerFE::StateSubset::Content); - } -} - void Output::updateCompositionState(const compositionengine::CompositionRefreshArgs& refreshArgs) { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -754,6 +745,44 @@ void Output::updateCompositionState(const compositionengine::CompositionRefreshA forceClientComposition = false; } } + + updateCompositionStateForBorder(refreshArgs); +} + +void Output::updateCompositionStateForBorder( + const compositionengine::CompositionRefreshArgs& refreshArgs) { + std::unordered_map<int32_t, const Region*> layerVisibleRegionMap; + // Store a map of layerId to their computed visible region. + for (auto* layer : getOutputLayersOrderedByZ()) { + int layerId = (layer->getLayerFE()).getSequence(); + layerVisibleRegionMap[layerId] = &((layer->getState()).visibleRegion); + } + OutputCompositionState& outputCompositionState = editState(); + outputCompositionState.borderInfoList.clear(); + bool clientComposeTopLayer = false; + for (const auto& borderInfo : refreshArgs.borderInfoList) { + renderengine::BorderRenderInfo info; + for (const auto& id : borderInfo.layerIds) { + info.combinedRegion.orSelf(*(layerVisibleRegionMap[id])); + } + + if (!info.combinedRegion.isEmpty()) { + info.width = borderInfo.width; + info.color = borderInfo.color; + outputCompositionState.borderInfoList.emplace_back(std::move(info)); + clientComposeTopLayer = true; + } + } + + // In this situation we must client compose the top layer instead of using hwc + // because we want to draw the border above all else. + // This could potentially cause a bit of a performance regression if the top + // layer would have been rendered using hwc originally. + // TODO(b/227656283): Measure system's performance before enabling the border feature + if (clientComposeTopLayer) { + auto topLayer = getOutputLayerOrderedByZByIndex(getOutputLayerCount() - 1); + (topLayer->editState()).forceClientComposition = true; + } } void Output::planComposition() { @@ -977,17 +1006,17 @@ void Output::beginFrame() { // frame, then nothing more until we get new layers. // - When a display is created with a private layer stack, we won't // emit any black frames until a layer is added to the layer stack. - const bool mustRecompose = dirty && !(empty && wasEmpty); + mMustRecompose = dirty && !(empty && wasEmpty); const char flagPrefix[] = {'-', '+'}; static_cast<void>(flagPrefix); - ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__, - mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty], - flagPrefix[empty], flagPrefix[wasEmpty]); + ALOGV("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __func__, + mMustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty], + flagPrefix[empty], flagPrefix[wasEmpty]); - mRenderSurface->beginFrame(mustRecompose); + mRenderSurface->beginFrame(mMustRecompose); - if (mustRecompose) { + if (mMustRecompose) { outputState.lastCompositionHadVisibleLayers = !empty; } } @@ -1122,7 +1151,8 @@ void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositi if (isPowerHintSessionEnabled()) { // get fence end time to know when gpu is complete in display - setHintSessionGpuFence(std::make_unique<FenceTime>(new Fence(dup(optReadyFence->get())))); + setHintSessionGpuFence( + std::make_unique<FenceTime>(sp<Fence>::make(dup(optReadyFence->get())))); } // swap buffers (presentation) mRenderSurface->queueBuffer(std::move(*optReadyFence)); @@ -1220,6 +1250,13 @@ std::optional<base::unique_fd> Output::composeSurfaces( // Compute the global color transform matrix. clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix; + for (auto& info : outputState.borderInfoList) { + renderengine::BorderRenderInfo borderInfo; + borderInfo.width = info.width; + borderInfo.color = info.color; + borderInfo.combinedRegion = info.combinedRegion; + clientCompositionDisplay.borderInfoList.emplace_back(std::move(borderInfo)); + } clientCompositionDisplay.deviceHandlesColorTransform = outputState.usesDeviceComposition || getSkipColorTransform(); @@ -1284,11 +1321,10 @@ std::optional<base::unique_fd> Output::composeSurfaces( // over to RenderEngine, in which case this flag can be removed from the drawLayers interface. const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay; - auto fenceResult = - toFenceResult(renderEngine - .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, - tex, useFramebufferCache, std::move(fd)) - .get()); + auto fenceResult = renderEngine + .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex, + useFramebufferCache, std::move(fd)) + .get(); if (mClientCompositionRequestCache && fenceStatus(fenceResult) != NO_ERROR) { // If rendering was not successful, remove the request from the cache. @@ -1320,7 +1356,7 @@ std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests( bool firstLayer = true; bool disableBlurs = false; - sp<GraphicBuffer> previousOverrideBuffer = nullptr; + uint64_t previousOverrideBufferId = 0; for (auto* layer : getOutputLayersOrderedByZ()) { const auto& layerState = layer->getState(); @@ -1356,11 +1392,10 @@ std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests( !layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty(); if (clientComposition || clearClientComposition) { - std::vector<LayerFE::LayerSettings> results; - if (layer->getState().overrideInfo.buffer != nullptr) { - if (layer->getState().overrideInfo.buffer->getBuffer() != previousOverrideBuffer) { - results = layer->getOverrideCompositionList(); - previousOverrideBuffer = layer->getState().overrideInfo.buffer->getBuffer(); + if (auto overrideSettings = layer->getOverrideCompositionSettings()) { + if (overrideSettings->bufferId != previousOverrideBufferId) { + previousOverrideBufferId = overrideSettings->bufferId; + clientCompositionLayers.push_back(std::move(*overrideSettings)); ALOGV("Replacing [%s] with override in RE", layer->getLayerFE().getDebugName()); } else { ALOGV("Skipping redundant override buffer for [%s] in RE", @@ -1386,20 +1421,18 @@ std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests( .clearContent = !clientComposition, .blurSetting = blurSetting, .whitePointNits = layerState.whitePointNits}; - results = layerFE.prepareClientCompositionList(targetSettings); - if (realContentIsVisible && !results.empty()) { - layer->editState().clientCompositionTimestamp = systemTime(); + if (auto clientCompositionSettings = + layerFE.prepareClientComposition(targetSettings)) { + clientCompositionLayers.push_back(std::move(*clientCompositionSettings)); + if (realContentIsVisible) { + layer->editState().clientCompositionTimestamp = systemTime(); + } } } if (clientComposition) { outLayerFEs.push_back(&layerFE); } - - clientCompositionLayers.insert(clientCompositionLayers.end(), - std::make_move_iterator(results.begin()), - std::make_move_iterator(results.end())); - results.clear(); } firstLayer = false; @@ -1447,7 +1480,6 @@ void Output::postFramebuffer() { auto& outputState = editState(); outputState.dirtyRegion.clear(); - mRenderSurface->flip(); auto frame = presentAndGetFrameFences(); @@ -1590,5 +1622,9 @@ void Output::finishPrepareFrame() { mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition); } +bool Output::mustRecompose() const { + return mMustRecompose; +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 948c0c90bf..c512a1e97f 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -62,14 +62,18 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits); dumpVal(out, "clientTargetBrightness", clientTargetBrightness); dumpVal(out, "displayBrightness", displayBrightness); - out.append("\n "); dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction)); + out.append("\n "); out.append("\n "); dumpVal(out, "treate170mAsSrgb", treat170mAsSrgb); - out += '\n'; + out.append("\n"); + for (const auto& borderRenderInfo : borderInfoList) { + dumpVal(out, "borderRegion", borderRenderInfo.combinedRegion); + } + out.append("\n"); } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 1bb9d0eb63..a39c527655 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -787,7 +787,7 @@ bool OutputLayer::needsFiltering() const { sourceCrop.getWidth() != displayFrame.getWidth(); } -std::vector<LayerFE::LayerSettings> OutputLayer::getOverrideCompositionList() const { +std::optional<LayerFE::LayerSettings> OutputLayer::getOverrideCompositionSettings() const { if (getState().overrideInfo.buffer == nullptr) { return {}; } @@ -816,7 +816,7 @@ std::vector<LayerFE::LayerSettings> OutputLayer::getOverrideCompositionList() co settings.alpha = 1.0f; settings.whitePointNits = getOutput().getState().sdrWhitePointNits; - return {static_cast<LayerFE::LayerSettings>(settings)}; + return settings; } void OutputLayer::dump(std::string& out) const { diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 5a3af7bfea..0fe55db05c 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -251,10 +251,6 @@ void RenderSurface::onPresentDisplayCompleted() { mDisplaySurface->onFrameCommitted(); } -void RenderSurface::flip() { - mPageFlipCount++; -} - void RenderSurface::dump(std::string& out) const { using android::base::StringAppendF; @@ -265,7 +261,6 @@ void RenderSurface::dump(std::string& out) const { dumpVal(out, "size", mSize); StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(), ANativeWindow_getFormat(mNativeWindow.get())); - dumpVal(out, "flips", mPageFlipCount); out.append("\n"); String8 surfaceDump; @@ -273,14 +268,6 @@ void RenderSurface::dump(std::string& out) const { out.append(surfaceDump); } -std::uint32_t RenderSurface::getPageFlipCount() const { - return mPageFlipCount; -} - -void RenderSurface::setPageFlipCountForTest(std::uint32_t count) { - mPageFlipCount = count; -} - void RenderSurface::setSizeForTest(const ui::Size& size) { mSize = size; } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index d6f02ee42a..0731d4899c 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -193,11 +193,11 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te std::vector<renderengine::LayerSettings> layerSettings; renderengine::LayerSettings highlight; for (const auto& layer : mLayers) { - const auto clientCompositionList = - layer.getState()->getOutputLayer()->getLayerFE().prepareClientCompositionList( - targetSettings); - layerSettings.insert(layerSettings.end(), clientCompositionList.cbegin(), - clientCompositionList.cend()); + if (auto clientCompositionSettings = + layer.getState()->getOutputLayer()->getLayerFE().prepareClientComposition( + targetSettings)) { + layerSettings.push_back(std::move(*clientCompositionSettings)); + } } renderengine::LayerSettings blurLayerSettings; @@ -205,43 +205,40 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te auto blurSettings = targetSettings; blurSettings.blurSetting = LayerFE::ClientCompositionTargetSettings::BlurSetting::BackgroundBlurOnly; - auto clientCompositionList = - mBlurLayer->getOutputLayer()->getLayerFE().prepareClientCompositionList( - blurSettings); - blurLayerSettings = clientCompositionList.back(); + + auto blurLayerSettings = + mBlurLayer->getOutputLayer()->getLayerFE().prepareClientComposition(blurSettings); // This mimics Layer::prepareClearClientComposition - blurLayerSettings.skipContentDraw = true; - blurLayerSettings.name = std::string("blur layer"); + blurLayerSettings->skipContentDraw = true; + blurLayerSettings->name = std::string("blur layer"); // Clear out the shadow settings - blurLayerSettings.shadow = {}; - layerSettings.push_back(blurLayerSettings); + blurLayerSettings->shadow = {}; + layerSettings.push_back(std::move(*blurLayerSettings)); } - renderengine::LayerSettings holePunchSettings; - renderengine::LayerSettings holePunchBackgroundSettings; if (mHolePunchLayer) { auto& layerFE = mHolePunchLayer->getOutputLayer()->getLayerFE(); - auto clientCompositionList = layerFE.prepareClientCompositionList(targetSettings); - // Assume that the final layer contains the buffer that we want to - // replace with a hole punch. - holePunchSettings = clientCompositionList.back(); + + auto holePunchSettings = layerFE.prepareClientComposition(targetSettings); // This mimics Layer::prepareClearClientComposition - holePunchSettings.source.buffer.buffer = nullptr; - holePunchSettings.source.solidColor = half3(0.0f, 0.0f, 0.0f); - holePunchSettings.disableBlending = true; - holePunchSettings.alpha = 0.0f; - holePunchSettings.name = + holePunchSettings->source.buffer.buffer = nullptr; + holePunchSettings->source.solidColor = half3(0.0f, 0.0f, 0.0f); + holePunchSettings->disableBlending = true; + holePunchSettings->alpha = 0.0f; + holePunchSettings->name = android::base::StringPrintf("hole punch layer for %s", layerFE.getDebugName()); - layerSettings.push_back(holePunchSettings); // Add a solid background as the first layer in case there is no opaque // buffer behind the punch hole + renderengine::LayerSettings holePunchBackgroundSettings; holePunchBackgroundSettings.alpha = 1.0f; holePunchBackgroundSettings.name = std::string("holePunchBackground"); - holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries; + holePunchBackgroundSettings.geometry.boundaries = holePunchSettings->geometry.boundaries; holePunchBackgroundSettings.geometry.positionTransform = - holePunchSettings.geometry.positionTransform; - layerSettings.emplace(layerSettings.begin(), holePunchBackgroundSettings); + holePunchSettings->geometry.positionTransform; + layerSettings.emplace(layerSettings.begin(), std::move(holePunchBackgroundSettings)); + + layerSettings.push_back(std::move(*holePunchSettings)); } if (sDebugHighlighLayers) { @@ -276,11 +273,10 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te constexpr bool kUseFramebufferCache = false; - auto fenceResult = - toFenceResult(renderEngine - .drawLayers(displaySettings, layerSettings, texture->get(), - kUseFramebufferCache, std::move(bufferFence)) - .get()); + auto fenceResult = renderEngine + .drawLayers(displaySettings, layerSettings, texture->get(), + kUseFramebufferCache, std::move(bufferFence)) + .get(); if (fenceStatus(fenceResult) == NO_ERROR) { mDrawFence = std::move(fenceResult).value_or(Fence::NO_FENCE); diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp index de9de0150d..b570979f1f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp @@ -108,12 +108,6 @@ TEST_F(CompositionEnginePresentTest, worksAsExpected) { EXPECT_CALL(*mOutput2, prepare(Ref(mRefreshArgs), _)); EXPECT_CALL(*mOutput3, prepare(Ref(mRefreshArgs), _)); - // The next step in presenting is to make sure all outputs have the latest - // state from the front-end (SurfaceFlinger). - EXPECT_CALL(*mOutput1, updateLayerStateFromFE(Ref(mRefreshArgs))); - EXPECT_CALL(*mOutput2, updateLayerStateFromFE(Ref(mRefreshArgs))); - EXPECT_CALL(*mOutput3, updateLayerStateFromFE(Ref(mRefreshArgs))); - // The last step is to actually present each output. EXPECT_CALL(*mOutput1, present(Ref(mRefreshArgs))); EXPECT_CALL(*mOutput2, present(Ref(mRefreshArgs))); @@ -175,21 +169,18 @@ TEST_F(CompositionEngineUpdateCursorAsyncTest, handlesMultipleLayersBeingCursorL { InSequence seq; EXPECT_CALL(mOutput2Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mOutput2Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); EXPECT_CALL(mOutput2Layer1.outputLayer, writeCursorPositionToHWC()); } { InSequence seq; EXPECT_CALL(mOutput3Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mOutput3Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); EXPECT_CALL(mOutput3Layer1.outputLayer, writeCursorPositionToHWC()); } { InSequence seq; EXPECT_CALL(mOutput3Layer2.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mOutput3Layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); EXPECT_CALL(mOutput3Layer2.outputLayer, writeCursorPositionToHWC()); } @@ -222,9 +213,12 @@ TEST_F(CompositionTestPreComposition, preCompositionInvokesLayerPreCompositionWi nsecs_t ts1 = 0; nsecs_t ts2 = 0; nsecs_t ts3 = 0; - EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts1), Return(false))); - EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts2), Return(false))); - EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts3), Return(false))); + EXPECT_CALL(*mLayer1FE, onPreComposition(_, _)) + .WillOnce(DoAll(SaveArg<0>(&ts1), Return(false))); + EXPECT_CALL(*mLayer2FE, onPreComposition(_, _)) + .WillOnce(DoAll(SaveArg<0>(&ts2), Return(false))); + EXPECT_CALL(*mLayer3FE, onPreComposition(_, _)) + .WillOnce(DoAll(SaveArg<0>(&ts3), Return(false))); mRefreshArgs.outputs = {mOutput1}; mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE}; @@ -238,9 +232,9 @@ TEST_F(CompositionTestPreComposition, preCompositionInvokesLayerPreCompositionWi } TEST_F(CompositionTestPreComposition, preCompositionDefaultsToNoUpdateNeeded) { - EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(false)); - EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false)); - EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false)); + EXPECT_CALL(*mLayer1FE, onPreComposition(_, _)).WillOnce(Return(false)); + EXPECT_CALL(*mLayer2FE, onPreComposition(_, _)).WillOnce(Return(false)); + EXPECT_CALL(*mLayer3FE, onPreComposition(_, _)).WillOnce(Return(false)); mEngine.setNeedsAnotherUpdateForTest(true); @@ -255,9 +249,9 @@ TEST_F(CompositionTestPreComposition, preCompositionDefaultsToNoUpdateNeeded) { TEST_F(CompositionTestPreComposition, preCompositionSetsNeedsAnotherUpdateIfAtLeastOneLayerRequestsIt) { - EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(true)); - EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false)); - EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false)); + EXPECT_CALL(*mLayer1FE, onPreComposition(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mLayer2FE, onPreComposition(_, _)).WillOnce(Return(false)); + EXPECT_CALL(*mLayer3FE, onPreComposition(_, _)).WillOnce(Return(false)); mRefreshArgs.outputs = {mOutput1}; mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE}; diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 344fea3331..95459c0499 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -194,7 +194,7 @@ struct DisplayTestCommon : public testing::Test { StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor; StrictMock<renderengine::mock::RenderEngine> mRenderEngine; StrictMock<mock::CompositionEngine> mCompositionEngine; - sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>(); + sp<mock::NativeWindow> mNativeWindow = sp<StrictMock<mock::NativeWindow>>::make(); }; struct PartialMockDisplayTestCommon : public DisplayTestCommon { @@ -524,7 +524,7 @@ TEST_F(DisplaySetReleasedLayersTest, doesNothingIfGpuDisplay) { auto args = getDisplayCreationArgsForGpuVirtualDisplay(); std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args); - sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>(); + sp<mock::LayerFE> layerXLayerFE = sp<StrictMock<mock::LayerFE>>::make(); { Output::ReleasedLayers releasedLayers; @@ -542,7 +542,7 @@ TEST_F(DisplaySetReleasedLayersTest, doesNothingIfGpuDisplay) { } TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) { - sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>(); + sp<mock::LayerFE> layerXLayerFE = sp<StrictMock<mock::LayerFE>>::make(); { Output::ReleasedLayers releasedLayers; @@ -558,7 +558,7 @@ TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) { } TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) { - sp<mock::LayerFE> unknownLayer = new StrictMock<mock::LayerFE>(); + sp<mock::LayerFE> unknownLayer = sp<StrictMock<mock::LayerFE>>::make(); CompositionRefreshArgs refreshArgs; refreshArgs.layersWithQueuedFrames.push_back(mLayer1.layerFE); @@ -897,9 +897,9 @@ TEST_F(DisplayPresentAndGetFrameFencesTest, returnsNoFencesOnGpuDisplay) { } TEST_F(DisplayPresentAndGetFrameFencesTest, returnsPresentAndLayerFences) { - sp<Fence> presentFence = new Fence(); - sp<Fence> layer1Fence = new Fence(); - sp<Fence> layer2Fence = new Fence(); + sp<Fence> presentFence = sp<Fence>::make(); + sp<Fence> layer1Fence = sp<Fence>::make(); + sp<Fence> layer2Fence = sp<Fence>::make(); EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(HalDisplayId(DEFAULT_DISPLAY_ID), _, _)) .Times(1); @@ -971,16 +971,40 @@ TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { // We expect no calls to queueBuffer if composition was skipped. EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0); + EXPECT_CALL(*renderSurface, beginFrame(false)); gpuDisplay->editState().isEnabled = true; gpuDisplay->editState().usesClientComposition = false; gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION; + gpuDisplay->editState().lastCompositionHadVisibleLayers = true; + gpuDisplay->beginFrame(); gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer)); } -TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { +TEST_F(DisplayFinishFrameTest, skipsCompositionIfEmpty) { + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); + std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args); + + mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>(); + gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface)); + + // We expect no calls to queueBuffer if composition was skipped. + EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0); + EXPECT_CALL(*renderSurface, beginFrame(false)); + + gpuDisplay->editState().isEnabled = true; + gpuDisplay->editState().usesClientComposition = false; + gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); + gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1)); + gpuDisplay->editState().lastCompositionHadVisibleLayers = false; + + gpuDisplay->beginFrame(); + gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer)); +} + +TEST_F(DisplayFinishFrameTest, performsCompositionIfDirtyAndNotEmpty) { auto args = getDisplayCreationArgsForGpuVirtualDisplay(); std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args); @@ -989,11 +1013,15 @@ TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { // We expect a single call to queueBuffer when composition is not skipped. EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1); + EXPECT_CALL(*renderSurface, beginFrame(true)); gpuDisplay->editState().isEnabled = true; gpuDisplay->editState().usesClientComposition = false; gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1)); + gpuDisplay->editState().lastCompositionHadVisibleLayers = true; + + gpuDisplay->beginFrame(); gpuDisplay->finishFrame({}, std::move(mResultWithBuffer)); } @@ -1018,8 +1046,8 @@ struct DisplayFunctionalTest : public testing::Test { NiceMock<android::mock::HWComposer> mHwComposer; NiceMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor; NiceMock<mock::CompositionEngine> mCompositionEngine; - sp<mock::NativeWindow> mNativeWindow = new NiceMock<mock::NativeWindow>(); - sp<mock::DisplaySurface> mDisplaySurface = new NiceMock<mock::DisplaySurface>(); + sp<mock::NativeWindow> mNativeWindow = sp<NiceMock<mock::NativeWindow>>::make(); + sp<mock::DisplaySurface> mDisplaySurface = sp<NiceMock<mock::DisplaySurface>>::make(); std::shared_ptr<Display> mDisplay; impl::RenderSurface* mRenderSurface; diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp index 00eafb15f5..7197780c17 100644 --- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp @@ -66,8 +66,10 @@ public: } impl::HwcBufferCache mCache; - sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + sp<GraphicBuffer> mBuffer1 = + sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u); + sp<GraphicBuffer> mBuffer2 = + sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u); }; TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) { diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index d7704a893d..9102139634 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -70,6 +70,7 @@ public: MOCK_METHOD1(disconnectDisplay, void(HalDisplayId)); MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&)); MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(HalDisplayId)); + MOCK_METHOD(nsecs_t, getPresentTimestamp, (PhysicalDisplayId), (const, override)); MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(HalDisplayId, HWC2::Layer*)); MOCK_METHOD3(setOutputBuffer, status_t(HalVirtualDisplayId, const sp<Fence>&, const sp<GraphicBuffer>&)); diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h index c8bd5e436c..e220541461 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h @@ -38,7 +38,7 @@ public: MOCK_METHOD(bool, usePowerHintSession, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); - MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDuration), (override)); + MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override)); MOCK_METHOD(void, sendActualWorkDuration, (), (override)); MOCK_METHOD(void, sendPredictedWorkDuration, (), (override)); MOCK_METHOD(void, enablePowerHint, (bool enabled), (override)); @@ -46,25 +46,24 @@ public: MOCK_METHOD(void, setGpuFenceTime, (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override)); MOCK_METHOD(void, setHwcValidateTiming, - (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime), + (DisplayId displayId, TimePoint validateStartTime, TimePoint validateEndTime), (override)); MOCK_METHOD(void, setHwcPresentTiming, - (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime), + (DisplayId displayId, TimePoint presentStartTime, TimePoint presentEndTime), (override)); MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override)); MOCK_METHOD(void, setRequiresClientComposition, (DisplayId displayId, bool requiresClientComposition), (override)); - MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override)); - MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime), + MOCK_METHOD(void, setExpectedPresentTime, (TimePoint expectedPresentTime), (override)); + MOCK_METHOD(void, setSfPresentTiming, (TimePoint presentFenceTime, TimePoint presentEndTime), (override)); MOCK_METHOD(void, setHwcPresentDelayedTime, - (DisplayId displayId, - std::chrono::steady_clock::time_point earliestFrameStartTime)); - MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override)); - MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override)); - MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override)); + (DisplayId displayId, TimePoint earliestFrameStartTime)); + MOCK_METHOD(void, setFrameDelay, (Duration frameDelayDuration), (override)); + MOCK_METHOD(void, setCommitStart, (TimePoint commitStartTime), (override)); + MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override)); MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override)); - MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override)); + MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); }; } // namespace mock diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 5290bd9cba..0f7dce896c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -955,11 +955,11 @@ native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = reinterpret_cast<native_handle_t*>(1031); const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer; const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kOverrideBuffer = - new GraphicBuffer(4, 5, PIXEL_FORMAT_RGBA_8888, - AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | - AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN); + sp<GraphicBuffer>::make(4, 5, PIXEL_FORMAT_RGBA_8888, + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN); const sp<Fence> OutputLayerWriteStateToHWCTest::kFence; -const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence(); +const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = sp<Fence>::make(); const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key = "com.example.metadata.1"; const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}}; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index cf12890310..eb209e9b72 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -39,7 +39,6 @@ #include "CallOrderStateMachineHelper.h" #include "MockHWC2.h" #include "RegionMatcher.h" -#include "TestUtils.h" namespace android::compositionengine { namespace { @@ -293,7 +292,7 @@ TEST_F(OutputTest, setLayerCachingEnabled_disablesCachingAndResetsOverrideInfo) InjectedLayer layer; layer.outputLayerState.overrideInfo.buffer = std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(), renderEngine, + ExternalTexture>(sp<GraphicBuffer>::make(), renderEngine, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage::WRITEABLE); injectOutputLayer(layer); @@ -759,56 +758,6 @@ TEST_F(OutputSetReleasedLayersTest, setReleasedLayersTakesGivenLayers) { } /* - * Output::updateLayerStateFromFE() - */ - -using OutputUpdateLayerStateFromFETest = OutputTest; - -TEST_F(OutputUpdateLayerStateFromFETest, handlesNoOutputLayerCase) { - CompositionRefreshArgs refreshArgs; - - mOutput->updateLayerStateFromFE(refreshArgs); -} - -TEST_F(OutputUpdateLayerStateFromFETest, preparesContentStateForAllContainedLayers) { - InjectedLayer layer1; - InjectedLayer layer2; - InjectedLayer layer3; - - EXPECT_CALL(*layer1.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content)); - EXPECT_CALL(*layer2.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content)); - EXPECT_CALL(*layer3.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content)); - - injectOutputLayer(layer1); - injectOutputLayer(layer2); - injectOutputLayer(layer3); - - CompositionRefreshArgs refreshArgs; - refreshArgs.updatingGeometryThisFrame = false; - - mOutput->updateLayerStateFromFE(refreshArgs); -} - -TEST_F(OutputUpdateLayerStateFromFETest, preparesGeometryAndContentStateForAllContainedLayers) { - InjectedLayer layer1; - InjectedLayer layer2; - InjectedLayer layer3; - - EXPECT_CALL(*layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent)); - EXPECT_CALL(*layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent)); - EXPECT_CALL(*layer3.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent)); - - injectOutputLayer(layer1); - injectOutputLayer(layer2); - injectOutputLayer(layer3); - - CompositionRefreshArgs refreshArgs; - refreshArgs.updatingGeometryThisFrame = true; - - mOutput->updateLayerStateFromFE(refreshArgs); -} - -/* * Output::updateAndWriteCompositionState() */ @@ -1017,7 +966,7 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(), renderEngine, + ExternalTexture>(sp<GraphicBuffer>::make(), renderEngine, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage::WRITEABLE); layer1.outputLayerState.overrideInfo.buffer = buffer; @@ -1537,9 +1486,6 @@ const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintNegativ TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) { EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false)); - EXPECT_CALL(*mLayer.layerFE, - prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry)); - mGeomSnapshots.clear(); ensureOutputLayerIfVisible(); @@ -3227,7 +3173,6 @@ TEST_F(OutputPostFramebufferTest, ifEnabledMustFlipThenPresentThenSendPresentCom // setup below are satisfied in the specific order. InSequence seq; - EXPECT_CALL(*mRenderSurface, flip()); EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences)); EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); @@ -3250,7 +3195,6 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence); frameFences.layerFences.emplace(&mLayer3.hwc2Layer, layer3Fence); - EXPECT_CALL(*mRenderSurface, flip()); EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences)); EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); @@ -3284,7 +3228,6 @@ TEST_F(OutputPostFramebufferTest, releaseFencesIncludeClientTargetAcquireFence) frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp<Fence>::make()); frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp<Fence>::make()); - EXPECT_CALL(*mRenderSurface, flip()); EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences)); EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); @@ -3320,7 +3263,6 @@ TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) { Output::FrameFences frameFences; frameFences.presentFence = presentFence; - EXPECT_CALL(*mRenderSurface, flip()); EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences)); EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); @@ -3449,7 +3391,7 @@ struct OutputComposeSurfacesTest : public testing::Test { StrictMock<OutputPartialMock> mOutput; std::shared_ptr<renderengine::ExternalTexture> mOutputBuffer = std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(), mRenderEngine, + ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage::WRITEABLE); @@ -3531,9 +3473,8 @@ TEST_F(OutputComposeSurfacesTest, handlesZeroCompositionRequests) { .WillRepeatedly([&](const renderengine::DisplaySettings&, const std::vector<renderengine::LayerSettings>&, const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) - -> std::future<renderengine::RenderEngineResult> { - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + base::unique_fd&&) -> ftl::Future<FenceResult> { + return ftl::yield<FenceResult>(Fence::NO_FENCE); }); verify().execute().expectAFenceWasReturned(); } @@ -3563,9 +3504,8 @@ TEST_F(OutputComposeSurfacesTest, buildsAndRendersRequestList) { .WillRepeatedly([&](const renderengine::DisplaySettings&, const std::vector<renderengine::LayerSettings>&, const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) - -> std::future<renderengine::RenderEngineResult> { - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + base::unique_fd&&) -> ftl::Future<FenceResult> { + return ftl::yield<FenceResult>(Fence::NO_FENCE); }); verify().execute().expectAFenceWasReturned(); @@ -3598,9 +3538,8 @@ TEST_F(OutputComposeSurfacesTest, .WillRepeatedly([&](const renderengine::DisplaySettings&, const std::vector<renderengine::LayerSettings>&, const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) - -> std::future<renderengine::RenderEngineResult> { - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + base::unique_fd&&) -> ftl::Future<FenceResult> { + return ftl::yield<FenceResult>(Fence::NO_FENCE); }); verify().execute().expectAFenceWasReturned(); @@ -3626,10 +3565,8 @@ TEST_F(OutputComposeSurfacesTest, renderDuplicateClientCompositionRequestsWithou EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .Times(2) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))) + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); verify().execute().expectAFenceWasReturned(); EXPECT_FALSE(mOutput.mState.reusedClientComposition); @@ -3657,8 +3594,7 @@ TEST_F(OutputComposeSurfacesTest, skipDuplicateClientCompositionRequests) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)); verify().execute().expectAFenceWasReturned(); @@ -3687,7 +3623,7 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { const auto otherOutputBuffer = std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(), mRenderEngine, + ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage::WRITEABLE); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) @@ -3697,9 +3633,8 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { .WillRepeatedly([&](const renderengine::DisplaySettings&, const std::vector<renderengine::LayerSettings>&, const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) - -> std::future<renderengine::RenderEngineResult> { - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + base::unique_fd&&) -> ftl::Future<FenceResult> { + return ftl::yield<FenceResult>(Fence::NO_FENCE); }); verify().execute().expectAFenceWasReturned(); @@ -3730,11 +3665,9 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfRequestChanges) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r3), _, false, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); verify().execute().expectAFenceWasReturned(); EXPECT_FALSE(mOutput.mState.reusedClientComposition); @@ -3811,8 +3744,7 @@ struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComp : public CallOrderStateMachineHelper<TestType, ExpectDisplaySettingsState> { auto thenExpectDisplaySettingsUsed(renderengine::DisplaySettings settings) { EXPECT_CALL(getInstance()->mRenderEngine, drawLayers(settings, _, _, false, _)) - .WillOnce(Return(ByMove(futureOf<renderengine::RenderEngineResult>( - {NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); return nextState<ExecuteState>(); } }; @@ -4065,14 +3997,12 @@ struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeS .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _)) - .WillRepeatedly( - [&](const renderengine::DisplaySettings&, - const std::vector<renderengine::LayerSettings>&, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { - return futureOf<renderengine::RenderEngineResult>( - {NO_ERROR, base::unique_fd()}); - }); + .WillRepeatedly([&](const renderengine::DisplaySettings&, + const std::vector<renderengine::LayerSettings>&, + const std::shared_ptr<renderengine::ExternalTexture>&, + const bool, base::unique_fd&&) -> ftl::Future<FenceResult> { + return ftl::yield<FenceResult>(Fence::NO_FENCE); + }); } Layer mLayer1; @@ -4137,8 +4067,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { // Must happen after setting the protected content state. EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); base::unique_fd fd; std::shared_ptr<renderengine::ExternalTexture> tex; @@ -4230,8 +4159,7 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDatas EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); base::unique_fd fd; std::shared_ptr<renderengine::ExternalTexture> tex; @@ -4254,8 +4182,7 @@ struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace, _)) .WillOnce(Return(std::vector<LayerFE::LayerSettings>{})); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _)) - .WillOnce(Return(ByMove(futureOf<renderengine::RenderEngineResult>( - {NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u)); EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u)) .WillRepeatedly(Return(&mLayer.outputLayer)); @@ -4312,6 +4239,8 @@ struct GenerateClientCompositionRequestsTest : public testing::Test { struct Layer { Layer() { + EXPECT_CALL(mOutputLayer, getOverrideCompositionSettings()) + .WillRepeatedly(Return(std::nullopt)); EXPECT_CALL(mOutputLayer, getState()).WillRepeatedly(ReturnRef(mOutputLayerState)); EXPECT_CALL(mOutputLayer, editState()).WillRepeatedly(ReturnRef(mOutputLayerState)); EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*mLayerFE)); @@ -4409,23 +4338,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, requiresVisibleRegionA } TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, gathersClientCompositionRequests) { - LayerFE::LayerSettings mShadowSettings; - mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; - - EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(_)) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(_)) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[1].mLayerSettings}))); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(_)) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>( - {mShadowSettings, mLayers[2].mLayerSettings}))); + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(_)) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientComposition(_)) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mLayers[1].mLayerSettings))); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(_)) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mLayers[2].mLayerSettings))); auto requests = mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, kDisplayDataspace); - ASSERT_EQ(3u, requests.size()); + ASSERT_EQ(2u, requests.size()); EXPECT_EQ(mLayers[1].mLayerSettings, requests[0]); - EXPECT_EQ(mShadowSettings, requests[1]); - EXPECT_EQ(mLayers[2].mLayerSettings, requests[2]); + EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]); // Check that a timestamp was set for the layers that generated requests EXPECT_TRUE(0 == mLayers[0].mOutputLayerState.clientCompositionTimestamp); @@ -4442,27 +4366,21 @@ MATCHER_P(ClientCompositionTargetSettingsBlurSettingsEq, expectedBlurSetting, "" } TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, overridesBlur) { - LayerFE::LayerSettings mShadowSettings; - mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; - mLayers[2].mOutputLayerState.overrideInfo.disableBackgroundBlur = true; - EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(_)) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(_)) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[1].mLayerSettings}))); + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(_)) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientComposition(_)) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mLayers[1].mLayerSettings))); EXPECT_CALL(*mLayers[2].mLayerFE, - prepareClientCompositionList(ClientCompositionTargetSettingsBlurSettingsEq( + prepareClientComposition(ClientCompositionTargetSettingsBlurSettingsEq( LayerFE::ClientCompositionTargetSettings::BlurSetting::BlurRegionsOnly))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>( - {mShadowSettings, mLayers[2].mLayerSettings}))); - + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mLayers[2].mLayerSettings))); auto requests = mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, kDisplayDataspace); - ASSERT_EQ(3u, requests.size()); + ASSERT_EQ(2u, requests.size()); EXPECT_EQ(mLayers[1].mLayerSettings, requests[0]); - EXPECT_EQ(mShadowSettings, requests[1]); - EXPECT_EQ(mLayers[2].mLayerSettings, requests[2]); + EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]); // Check that a timestamp was set for the layers that generated requests EXPECT_TRUE(0 == mLayers[0].mOutputLayerState.clientCompositionTimestamp); @@ -4484,8 +4402,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[1].mLayerFEState.isOpaque = true; mLayers[2].mLayerFEState.isOpaque = true; - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(_)) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings}))); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(_)) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mLayers[2].mLayerSettings))); auto requests = mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, kDisplayDataspace); @@ -4507,8 +4425,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[1].mLayerFEState.isOpaque = false; mLayers[2].mLayerFEState.isOpaque = false; - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(_)) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings}))); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(_)) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mLayers[2].mLayerSettings))); auto requests = mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, kDisplayDataspace); @@ -4566,10 +4484,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu mBlackoutSettings.alpha = 0.f; mBlackoutSettings.disableBlending = true; - EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mBlackoutSettings}))); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings}))); + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mBlackoutSettings))); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mLayers[2].mLayerSettings))); auto requests = mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, kDisplayDataspace); @@ -4624,12 +4542,12 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, kLayerWhitePointNits, }; - EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); static_cast<void>( mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, @@ -4678,12 +4596,12 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, kLayerWhitePointNits, }; - EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); static_cast<void>( mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, @@ -4732,12 +4650,12 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, kLayerWhitePointNits, }; - EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); static_cast<void>( mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, @@ -4785,12 +4703,12 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, kLayerWhitePointNits, }; - EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); static_cast<void>( mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, @@ -4836,12 +4754,12 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, kLayerWhitePointNits, }; - EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>())); static_cast<void>(mOutput.generateClientCompositionRequestsHelper(true /* supportsProtectedContent */, kDisplayDataspace)); @@ -5022,8 +4940,8 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); - EXPECT_CALL(*leftLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(leftLayerSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({leftLayer.mLayerSettings}))); + EXPECT_CALL(*leftLayer.mLayerFE, prepareClientComposition(Eq(ByRef(leftLayerSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(leftLayer.mLayerSettings))); compositionengine::LayerFE::ClientCompositionTargetSettings rightLayerSettings{ Region(Rect(1000, 0, 2000, 1000)), @@ -5040,8 +4958,8 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); - EXPECT_CALL(*rightLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(rightLayerSettings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({rightLayer.mLayerSettings}))); + EXPECT_CALL(*rightLayer.mLayerFE, prepareClientComposition(Eq(ByRef(rightLayerSettings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(rightLayer.mLayerSettings))); constexpr bool supportsProtectedContent = true; auto requests = @@ -5079,8 +4997,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mShadowSettings}))); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2Settings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mShadowSettings))); auto requests = mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, kDisplayDataspace); @@ -5097,9 +5015,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, const Region kPartialContentWithPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 50, 80)); - LayerFE::LayerSettings mShadowSettings; - mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; - mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion; mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion; @@ -5118,16 +5033,14 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) - .WillOnce(Return(std::vector<LayerFE::LayerSettings>( - {mShadowSettings, mLayers[2].mLayerSettings}))); + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2Settings)))) + .WillOnce(Return(std::optional<LayerFE::LayerSettings>(mLayers[2].mLayerSettings))); auto requests = mOutput.generateClientCompositionRequestsHelper(false /* supportsProtectedContent */, kDisplayDataspace); - ASSERT_EQ(2u, requests.size()); + ASSERT_EQ(1u, requests.size()); - EXPECT_EQ(mShadowSettings, requests[0]); - EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]); + EXPECT_EQ(mLayers[2].mLayerSettings, requests[0]); } } // namespace diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index e5f9ebfbeb..83937a679e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -61,8 +61,8 @@ public: StrictMock<renderengine::mock::RenderEngine> mRenderEngine; StrictMock<mock::CompositionEngine> mCompositionEngine; StrictMock<mock::Display> mDisplay; - sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>(); - sp<mock::DisplaySurface> mDisplaySurface = new StrictMock<mock::DisplaySurface>(); + sp<mock::NativeWindow> mNativeWindow = sp<StrictMock<mock::NativeWindow>>::make(); + sp<mock::DisplaySurface> mDisplaySurface = sp<StrictMock<mock::DisplaySurface>>::make(); impl::RenderSurface mSurface{mCompositionEngine, mDisplay, RenderSurfaceCreationArgsBuilder() .setDisplayWidth(DEFAULT_DISPLAY_WIDTH) @@ -109,7 +109,7 @@ TEST_F(RenderSurfaceTest, sizeReturnsConstructedSize) { */ TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) { - sp<Fence> fence = new Fence(); + sp<Fence> fence = sp<Fence>::make(); EXPECT_CALL(*mDisplaySurface, getClientTargetAcquireFence()).WillOnce(ReturnRef(fence)); @@ -234,7 +234,7 @@ TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) { */ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { - sp<GraphicBuffer> buffer = new GraphicBuffer(); + sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(); EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _)) .WillOnce( @@ -253,7 +253,7 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { const auto buffer = std::make_shared< renderengine::impl:: - ExternalTexture>(new GraphicBuffer(), mRenderEngine, + ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine, renderengine::impl::ExternalTexture::Usage::READABLE | renderengine::impl::ExternalTexture::Usage::WRITEABLE); mSurface.mutableTextureForTest() = buffer; @@ -271,8 +271,9 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { } TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { - const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(), - mRenderEngine, false); + const auto buffer = + std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(), + mRenderEngine, false); mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; @@ -290,8 +291,9 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { - const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(), - mRenderEngine, false); + const auto buffer = + std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(), + mRenderEngine, false); mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; @@ -309,7 +311,7 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) { - sp<GraphicBuffer> buffer = new GraphicBuffer(); + sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(); impl::OutputCompositionState state; state.usesClientComposition = false; @@ -329,8 +331,9 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferY } TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) { - const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(), - mRenderEngine, false); + const auto buffer = + std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(), + mRenderEngine, false); mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; @@ -359,17 +362,5 @@ TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) { mSurface.onPresentDisplayCompleted(); } -/* - * RenderSurface::flip() - */ - -TEST_F(RenderSurfaceTest, flipForwardsSignal) { - mSurface.setPageFlipCountForTest(500); - - mSurface.flip(); - - EXPECT_EQ(501u, mSurface.getPageFlipCount()); -} - } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index 0e9db369e8..d5d688e705 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -28,8 +28,6 @@ #include <utils/Errors.h> #include <memory> -#include "tests/TestUtils.h" - namespace android::compositionengine { using namespace std::chrono_literals; @@ -345,19 +343,18 @@ TEST_F(CachedSetTest, renderUnsecureOutput) { CachedSet cachedSet(layer1); cachedSet.append(CachedSet(layer2)); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; - clientCompList1.push_back({}); - clientCompList1[0].alpha = 0.5f; + std::optional<compositionengine::LayerFE::LayerSettings> clientComp1; + clientComp1.emplace(); + clientComp1->alpha = 0.5f; - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; - clientCompList2.push_back({}); - clientCompList2[0].alpha = 0.75f; + std::optional<compositionengine::LayerFE::LayerSettings> clientComp2; + clientComp2.emplace(); + clientComp2->alpha = 0.75f; - const auto drawLayers = - [&](const renderengine::DisplaySettings& displaySettings, - const std::vector<renderengine::LayerSettings>& layers, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>& layers, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) -> ftl::Future<FenceResult> { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), @@ -365,15 +362,13 @@ TEST_F(CachedSetTest, renderUnsecureOutput) { EXPECT_EQ(0.5f, layers[0].alpha); EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + return ftl::yield<FenceResult>(Fence::NO_FENCE); }; - EXPECT_CALL(*layerFE1, - prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(false))) - .WillOnce(Return(clientCompList1)); - EXPECT_CALL(*layerFE2, - prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(false))) - .WillOnce(Return(clientCompList2)); + EXPECT_CALL(*layerFE1, prepareClientComposition(ClientCompositionTargetSettingsSecureEq(false))) + .WillOnce(Return(clientComp1)); + EXPECT_CALL(*layerFE2, prepareClientComposition(ClientCompositionTargetSettingsSecureEq(false))) + .WillOnce(Return(clientComp2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); mOutputState.isSecure = false; cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true); @@ -397,19 +392,18 @@ TEST_F(CachedSetTest, renderSecureOutput) { CachedSet cachedSet(layer1); cachedSet.append(CachedSet(layer2)); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; - clientCompList1.push_back({}); - clientCompList1[0].alpha = 0.5f; + std::optional<compositionengine::LayerFE::LayerSettings> clientComp1; + clientComp1.emplace(); + clientComp1->alpha = 0.5f; - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; - clientCompList2.push_back({}); - clientCompList2[0].alpha = 0.75f; + std::optional<compositionengine::LayerFE::LayerSettings> clientComp2; + clientComp2.emplace(); + clientComp2->alpha = 0.75f; - const auto drawLayers = - [&](const renderengine::DisplaySettings& displaySettings, - const std::vector<renderengine::LayerSettings>& layers, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>& layers, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) -> ftl::Future<FenceResult> { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), @@ -418,15 +412,13 @@ TEST_F(CachedSetTest, renderSecureOutput) { EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + return ftl::yield<FenceResult>(Fence::NO_FENCE); }; - EXPECT_CALL(*layerFE1, - prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(true))) - .WillOnce(Return(clientCompList1)); - EXPECT_CALL(*layerFE2, - prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(true))) - .WillOnce(Return(clientCompList2)); + EXPECT_CALL(*layerFE1, prepareClientComposition(ClientCompositionTargetSettingsSecureEq(true))) + .WillOnce(Return(clientComp1)); + EXPECT_CALL(*layerFE2, prepareClientComposition(ClientCompositionTargetSettingsSecureEq(true))) + .WillOnce(Return(clientComp2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); mOutputState.isSecure = true; cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true); @@ -450,31 +442,30 @@ TEST_F(CachedSetTest, renderWhitePoint) { CachedSet cachedSet(layer1); cachedSet.append(CachedSet(layer2)); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; - clientCompList1.push_back({}); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp1; + clientComp1.emplace(); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; - clientCompList2.push_back({}); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp2; + clientComp2.emplace(); mOutputState.displayBrightnessNits = 400.f; - const auto drawLayers = - [&](const renderengine::DisplaySettings& displaySettings, - const std::vector<renderengine::LayerSettings>&, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>&, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) -> ftl::Future<FenceResult> { EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits); - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + return ftl::yield<FenceResult>(Fence::NO_FENCE); }; EXPECT_CALL(*layerFE1, - prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq( + prepareClientComposition(ClientCompositionTargetSettingsWhitePointEq( mOutputState.displayBrightnessNits))) - .WillOnce(Return(clientCompList1)); + .WillOnce(Return(clientComp1)); EXPECT_CALL(*layerFE2, - prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq( + prepareClientComposition(ClientCompositionTargetSettingsWhitePointEq( mOutputState.displayBrightnessNits))) - .WillOnce(Return(clientCompList2)); + .WillOnce(Return(clientComp2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); mOutputState.isSecure = true; cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true); @@ -501,31 +492,30 @@ TEST_F(CachedSetTest, renderWhitePointNoColorTransform) { CachedSet cachedSet(layer1); cachedSet.append(CachedSet(layer2)); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; - clientCompList1.push_back({}); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp1; + clientComp1.emplace(); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; - clientCompList2.push_back({}); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp2; + clientComp2.emplace(); mOutputState.displayBrightnessNits = 400.f; - const auto drawLayers = - [&](const renderengine::DisplaySettings& displaySettings, - const std::vector<renderengine::LayerSettings>&, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>&, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) -> ftl::Future<FenceResult> { EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits); - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + return ftl::yield<FenceResult>(Fence::NO_FENCE); }; EXPECT_CALL(*layerFE1, - prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq( + prepareClientComposition(ClientCompositionTargetSettingsWhitePointEq( mOutputState.displayBrightnessNits))) - .WillOnce(Return(clientCompList1)); + .WillOnce(Return(clientComp1)); EXPECT_CALL(*layerFE2, - prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq( + prepareClientComposition(ClientCompositionTargetSettingsWhitePointEq( mOutputState.displayBrightnessNits))) - .WillOnce(Return(clientCompList2)); + .WillOnce(Return(clientComp2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); mOutputState.isSecure = true; cachedSet.render(mRenderEngine, mTexturePool, mOutputState, false); @@ -549,21 +539,20 @@ TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) { CachedSet cachedSet(layer1); cachedSet.append(CachedSet(layer2)); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; - clientCompList1.push_back({}); - clientCompList1[0].alpha = 0.5f; + std::optional<compositionengine::LayerFE::LayerSettings> clientComp1; + clientComp1.emplace(); + clientComp1->alpha = 0.5f; - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; - clientCompList2.push_back({}); - clientCompList2[0].alpha = 0.75f; + std::optional<compositionengine::LayerFE::LayerSettings> clientComp2; + clientComp2.emplace(); + clientComp2->alpha = 0.75f; mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(2, 3, 10, 5)); - const auto drawLayers = - [&](const renderengine::DisplaySettings& displaySettings, - const std::vector<renderengine::LayerSettings>& layers, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>& layers, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) -> ftl::Future<FenceResult> { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), @@ -572,11 +561,11 @@ TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) { EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + return ftl::yield<FenceResult>(Fence::NO_FENCE); }; - EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); - EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); + EXPECT_CALL(*layerFE1, prepareClientComposition(_)).WillOnce(Return(clientComp1)); + EXPECT_CALL(*layerFE2, prepareClientComposition(_)).WillOnce(Return(clientComp2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true); expectReadyBuffer(cachedSet); @@ -773,28 +762,27 @@ TEST_F(CachedSetTest, addHolePunch) { cachedSet.addHolePunchLayerIfFeasible(layer3, true); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; - clientCompList1.push_back({}); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; - clientCompList2.push_back({}); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3; - clientCompList3.push_back({}); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp1; + clientComp1.emplace(); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp2; + clientComp2.emplace(); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp3; + clientComp3.emplace(); - clientCompList3[0].source.buffer.buffer = + clientComp3->source.buffer.buffer = std::make_shared<renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); - EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); - EXPECT_CALL(*layerFE3, prepareClientCompositionList(_)).WillOnce(Return(clientCompList3)); + EXPECT_CALL(*layerFE1, prepareClientComposition(_)).WillOnce(Return(clientComp1)); + EXPECT_CALL(*layerFE2, prepareClientComposition(_)).WillOnce(Return(clientComp2)); + EXPECT_CALL(*layerFE3, prepareClientComposition(_)).WillOnce(Return(clientComp3)); - const auto drawLayers = - [&](const renderengine::DisplaySettings&, - const std::vector<renderengine::LayerSettings>& layers, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + const auto drawLayers = [&](const renderengine::DisplaySettings&, + const std::vector<renderengine::LayerSettings>& layers, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) -> ftl::Future<FenceResult> { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 4u); @@ -814,7 +802,7 @@ TEST_F(CachedSetTest, addHolePunch) { EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha); } - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + return ftl::yield<FenceResult>(Fence::NO_FENCE); }; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); @@ -822,7 +810,7 @@ TEST_F(CachedSetTest, addHolePunch) { } TEST_F(CachedSetTest, addHolePunch_noBuffer) { - // Same as addHolePunch, except that clientCompList3 does not contain a + // Same as addHolePunch, except that clientComp3 does not contain a // buffer. This imitates the case where the buffer had protected content, so // BufferLayer did not add it to the LayerSettings. This should not assert. mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5); @@ -840,22 +828,21 @@ TEST_F(CachedSetTest, addHolePunch_noBuffer) { cachedSet.addHolePunchLayerIfFeasible(layer3, true); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; - clientCompList1.push_back({}); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; - clientCompList2.push_back({}); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3; - clientCompList3.push_back({}); - - EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); - EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); - EXPECT_CALL(*layerFE3, prepareClientCompositionList(_)).WillOnce(Return(clientCompList3)); - - const auto drawLayers = - [&](const renderengine::DisplaySettings&, - const std::vector<renderengine::LayerSettings>& layers, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + std::optional<compositionengine::LayerFE::LayerSettings> clientComp1; + clientComp1.emplace(); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp2; + clientComp2.emplace(); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp3; + clientComp3.emplace(); + + EXPECT_CALL(*layerFE1, prepareClientComposition(_)).WillOnce(Return(clientComp1)); + EXPECT_CALL(*layerFE2, prepareClientComposition(_)).WillOnce(Return(clientComp2)); + EXPECT_CALL(*layerFE3, prepareClientComposition(_)).WillOnce(Return(clientComp3)); + + const auto drawLayers = [&](const renderengine::DisplaySettings&, + const std::vector<renderengine::LayerSettings>& layers, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) -> ftl::Future<FenceResult> { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 4u); @@ -876,7 +863,7 @@ TEST_F(CachedSetTest, addHolePunch_noBuffer) { EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha); } - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + return ftl::yield<FenceResult>(Fence::NO_FENCE); }; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); @@ -974,40 +961,39 @@ TEST_F(CachedSetTest, addBlur) { cachedSet.addBackgroundBlurLayer(layer3); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; - clientCompList1.push_back({}); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; - clientCompList2.push_back({}); - std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3; - clientCompList3.push_back({}); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp1; + clientComp1.emplace(); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp2; + clientComp2.emplace(); + std::optional<compositionengine::LayerFE::LayerSettings> clientComp3; + clientComp3.emplace(); - clientCompList3[0].source.buffer.buffer = + clientComp3->source.buffer.buffer = std::make_shared<renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); EXPECT_CALL(*layerFE1, - prepareClientCompositionList(ClientCompositionTargetSettingsBlurSettingsEq( + prepareClientComposition(ClientCompositionTargetSettingsBlurSettingsEq( compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting:: Enabled))) - .WillOnce(Return(clientCompList1)); + .WillOnce(Return(clientComp1)); EXPECT_CALL(*layerFE2, - prepareClientCompositionList(ClientCompositionTargetSettingsBlurSettingsEq( + prepareClientComposition(ClientCompositionTargetSettingsBlurSettingsEq( compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting:: Enabled))) - .WillOnce(Return(clientCompList2)); + .WillOnce(Return(clientComp2)); EXPECT_CALL(*layerFE3, - prepareClientCompositionList(ClientCompositionTargetSettingsBlurSettingsEq( + prepareClientComposition(ClientCompositionTargetSettingsBlurSettingsEq( compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting:: BackgroundBlurOnly))) - .WillOnce(Return(clientCompList3)); + .WillOnce(Return(clientComp3)); - const auto drawLayers = - [&](const renderengine::DisplaySettings&, - const std::vector<renderengine::LayerSettings>& layers, - const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + const auto drawLayers = [&](const renderengine::DisplaySettings&, + const std::vector<renderengine::LayerSettings>& layers, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) -> ftl::Future<FenceResult> { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 3u); @@ -1016,7 +1002,7 @@ TEST_F(CachedSetTest, addBlur) { EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings.source.solidColor); EXPECT_EQ(0.0f, blurSettings.alpha); - return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}); + return ftl::yield<FenceResult>(Fence::NO_FENCE); }; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp index 96021ec104..86cfee6f0a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp @@ -27,8 +27,6 @@ #include <renderengine/mock/RenderEngine.h> #include <chrono> -#include "tests/TestUtils.h" - namespace android::compositionengine { using namespace std::chrono_literals; using impl::planner::CachedSet; @@ -108,11 +106,12 @@ void FlattenerTest::SetUp() { testLayer->outputLayerCompositionState.visibleRegion = Region(Rect(pos + 1, pos + 1, pos + 2, pos + 2)); + const auto kUsageFlags = + static_cast<uint64_t>(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE); testLayer->layerFECompositionState.buffer = - new GraphicBuffer(100, 100, HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, - "output"); + sp<GraphicBuffer>::make(100u, 100u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, + "output"); testLayer->layerFE = sp<mock::LayerFE>::make(); @@ -123,12 +122,11 @@ void FlattenerTest::SetUp() { EXPECT_CALL(*testLayer->layerFE, getCompositionState) .WillRepeatedly(Return(&testLayer->layerFECompositionState)); - std::vector<LayerFE::LayerSettings> clientCompositionList = { - LayerFE::LayerSettings{}, - }; + std::optional<LayerFE::LayerSettings> clientComposition; + clientComposition.emplace(); - EXPECT_CALL(*testLayer->layerFE, prepareClientCompositionList) - .WillRepeatedly(Return(clientCompositionList)); + EXPECT_CALL(*testLayer->layerFE, prepareClientComposition) + .WillRepeatedly(Return(clientComposition)); EXPECT_CALL(testLayer->outputLayer, getLayerFE) .WillRepeatedly(ReturnRef(*testLayer->layerFE)); EXPECT_CALL(testLayer->outputLayer, getState) @@ -171,8 +169,7 @@ void FlattenerTest::initializeFlattener(const std::vector<const LayerState*>& la void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) { // layers would be flattened but the buffer would not be overridden EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), @@ -423,8 +420,7 @@ TEST_F(FlattenerTest, flattenLayers_BufferUpdateToFlatten) { layerState1->resetFramesSinceBufferUpdate(); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); @@ -447,8 +443,7 @@ TEST_F(FlattenerTest, flattenLayers_BufferUpdateToFlatten) { mTime += 200ms; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); @@ -500,8 +495,7 @@ TEST_F(FlattenerTest, flattenLayers_BufferUpdateForMiddleLayer) { layerState3->resetFramesSinceBufferUpdate(); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); @@ -515,8 +509,7 @@ TEST_F(FlattenerTest, flattenLayers_BufferUpdateForMiddleLayer) { // Layers 1 and 2 will be flattened a new drawFrame would be called for Layer4 and Layer5 EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); @@ -545,8 +538,7 @@ TEST_F(FlattenerTest, flattenLayers_BufferUpdateForMiddleLayer) { layerState3->incrementFramesSinceBufferUpdate(); mTime += 200ms; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); @@ -601,8 +593,7 @@ TEST_F(FlattenerTest, flattenLayers_pipRequiresRoundedCorners) { // This will render a CachedSet. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. @@ -637,16 +628,15 @@ TEST_F(FlattenerTest, flattenLayers_pip) { EXPECT_CALL(*mTestLayers[2]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true)); - std::vector<LayerFE::LayerSettings> clientCompositionList = { - LayerFE::LayerSettings{}, - }; - clientCompositionList[0].source.buffer.buffer = std::make_shared< + std::optional<LayerFE::LayerSettings> clientComposition; + clientComposition.emplace(); + clientComposition->source.buffer.buffer = std::make_shared< renderengine::impl::ExternalTexture>(mTestLayers[2]->layerFECompositionState.buffer, mRenderEngine, renderengine::impl::ExternalTexture::Usage:: READABLE); - EXPECT_CALL(*mTestLayers[2]->layerFE, prepareClientCompositionList(_)) - .WillOnce(Return(clientCompositionList)); + EXPECT_CALL(*mTestLayers[2]->layerFE, prepareClientComposition(_)) + .WillOnce(Return(clientComposition)); const std::vector<const LayerState*> layers = { layerState1.get(), @@ -667,8 +657,7 @@ TEST_F(FlattenerTest, flattenLayers_pip) { // This will render a CachedSet. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. @@ -711,16 +700,15 @@ TEST_F(FlattenerTest, flattenLayers_holePunchSingleLayer) { EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true)); - std::vector<LayerFE::LayerSettings> clientCompositionList = { - LayerFE::LayerSettings{}, - }; - clientCompositionList[0].source.buffer.buffer = std::make_shared< + std::optional<LayerFE::LayerSettings> clientComposition; + clientComposition.emplace(); + clientComposition->source.buffer.buffer = std::make_shared< renderengine::impl::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer, mRenderEngine, renderengine::impl::ExternalTexture::Usage:: READABLE); - EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_)) - .WillOnce(Return(clientCompositionList)); + EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientComposition(_)) + .WillOnce(Return(clientComposition)); const std::vector<const LayerState*> layers = { layerState0.get(), @@ -741,8 +729,7 @@ TEST_F(FlattenerTest, flattenLayers_holePunchSingleLayer) { // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the // exception that there would be a hole punch above it. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. @@ -783,16 +770,15 @@ TEST_F(FlattenerTest, flattenLayers_holePunchSingleColorLayer) { EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true)); - std::vector<LayerFE::LayerSettings> clientCompositionList = { - LayerFE::LayerSettings{}, - }; - clientCompositionList[0].source.buffer.buffer = std::make_shared< + std::optional<LayerFE::LayerSettings> clientComposition; + clientComposition.emplace(); + clientComposition->source.buffer.buffer = std::make_shared< renderengine::impl::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer, mRenderEngine, renderengine::impl::ExternalTexture::Usage:: READABLE); - EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_)) - .WillOnce(Return(clientCompositionList)); + EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientComposition(_)) + .WillOnce(Return(clientComposition)); const std::vector<const LayerState*> layers = { layerState0.get(), @@ -813,8 +799,7 @@ TEST_F(FlattenerTest, flattenLayers_holePunchSingleColorLayer) { // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the // exception that there would be a hole punch above it. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. @@ -865,8 +850,7 @@ TEST_F(FlattenerTest, flattenLayers_flattensBlurBehindRunIfFirstRun) { // layers would be flattened but the buffer would not be overridden EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), @@ -911,8 +895,7 @@ TEST_F(FlattenerTest, flattenLayers_doesNotFlattenBlurBehindRun) { // layers would be flattened but the buffer would not be overridden EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillRepeatedly(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillRepeatedly(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), @@ -965,8 +948,7 @@ TEST_F(FlattenerTest, flattenLayers_flattenSkipsLayerWithBlurBehind) { // layers would be flattened but the buffer would not be overridden EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), @@ -1014,8 +996,7 @@ TEST_F(FlattenerTest, flattenLayers_whenBlurLayerIsChanging_appliesBlurToInactiv // layers would be flattened but the buffer would not be overridden EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), @@ -1057,8 +1038,7 @@ TEST_F(FlattenerTest, flattenLayers_renderCachedSets_doesNotRenderTwice) { mTime += 200ms; // layers would be flattened but the buffer would not be overridden EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), @@ -1125,8 +1105,7 @@ TEST_F(FlattenerRenderSchedulingTest, flattenLayers_renderCachedSets_defersUpToM } EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::chrono::steady_clock::now() - (kCachedSetRenderDuration + 10ms), @@ -1162,8 +1141,7 @@ TEST_F(FlattenerTest, flattenLayers_skipsBT601_625) { // This will render a CachedSet. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. @@ -1213,8 +1191,7 @@ TEST_F(FlattenerTest, flattenLayers_skipsHDR) { // This will render a CachedSet. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. @@ -1264,8 +1241,7 @@ TEST_F(FlattenerTest, flattenLayers_skipsHDR2) { // This will render a CachedSet. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. @@ -1318,8 +1294,7 @@ TEST_F(FlattenerTest, flattenLayers_skipsColorLayers) { // This will render a CachedSet. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. @@ -1371,8 +1346,7 @@ TEST_F(FlattenerTest, flattenLayers_includes_DISPLAY_DECORATION) { // This will render a CachedSet. EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) - .WillOnce(Return(ByMove( - futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})))); + .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE)))); mFlattener->renderCachedSets(mOutputState, std::nullopt, true); // We've rendered a CachedSet, but we haven't merged it in. diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp index 5c6e8da58c..47b682059f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp @@ -112,6 +112,9 @@ struct LayerStateTest : public testing::Test { sp<mock::LayerFE> mLayerFE = sp<mock::LayerFE>::make(); mock::OutputLayer mOutputLayer; std::unique_ptr<LayerState> mLayerState; + + static constexpr auto kUsageFlags = static_cast<uint32_t>( + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN); }; TEST_F(LayerStateTest, getOutputLayer) { @@ -346,7 +349,7 @@ TEST_F(LayerStateTest, compareCompositionType) { TEST_F(LayerStateTest, updateBuffer) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; - layerFECompositionState.buffer = new GraphicBuffer(); + layerFECompositionState.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique<LayerState>(&mOutputLayer); @@ -354,7 +357,7 @@ TEST_F(LayerStateTest, updateBuffer) { mock::OutputLayer newOutputLayer; sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make(); LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.buffer = new GraphicBuffer(); + layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer); @@ -364,7 +367,7 @@ TEST_F(LayerStateTest, updateBuffer) { TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; - layerFECompositionState.buffer = new GraphicBuffer(); + layerFECompositionState.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique<LayerState>(&mOutputLayer); @@ -372,7 +375,7 @@ TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) { mock::OutputLayer newOutputLayer; sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make(); LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.buffer = new GraphicBuffer(); + layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); @@ -388,7 +391,7 @@ TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) { TEST_F(LayerStateTest, updateBufferSingleBufferedUsage) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; - layerFECompositionState.buffer = new GraphicBuffer(); + layerFECompositionState.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique<LayerState>(&mOutputLayer); @@ -396,7 +399,7 @@ TEST_F(LayerStateTest, updateBufferSingleBufferedUsage) { mock::OutputLayer newOutputLayer; sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make(); LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.buffer = new GraphicBuffer(); + layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make(); layerFECompositionStateTwo.buffer->usage = static_cast<uint64_t>(BufferUsage::FRONT_BUFFER); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); @@ -412,14 +415,14 @@ TEST_F(LayerStateTest, updateBufferSingleBufferedUsage) { TEST_F(LayerStateTest, compareBuffer) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; - layerFECompositionState.buffer = new GraphicBuffer(); + layerFECompositionState.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique<LayerState>(&mOutputLayer); mock::OutputLayer newOutputLayer; sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make(); LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.buffer = new GraphicBuffer(); + layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); @@ -720,10 +723,7 @@ TEST_F(LayerStateTest, updatePixelFormat) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; layerFECompositionState.buffer = - new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, - AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | - AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, - "buffer1"); + sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888, kUsageFlags, "buffer1"); setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique<LayerState>(&mOutputLayer); @@ -732,10 +732,7 @@ TEST_F(LayerStateTest, updatePixelFormat) { sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make(); LayerFECompositionState layerFECompositionStateTwo; layerFECompositionStateTwo.buffer = - new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888, - AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | - AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, - "buffer2"); + sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBX_8888, kUsageFlags, "buffer2"); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer); @@ -748,10 +745,7 @@ TEST_F(LayerStateTest, comparePixelFormat) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; layerFECompositionState.buffer = - new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, - AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | - AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, - "buffer1"); + sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888, kUsageFlags, "buffer1"); setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique<LayerState>(&mOutputLayer); @@ -759,10 +753,7 @@ TEST_F(LayerStateTest, comparePixelFormat) { sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make(); LayerFECompositionState layerFECompositionStateTwo; layerFECompositionStateTwo.buffer = - new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888, - AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | - AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, - "buffer2"); + sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBX_8888, kUsageFlags, "buffer2"); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); @@ -1069,7 +1060,7 @@ TEST_F(LayerStateTest, getNonBufferHash_isIdempotent) { TEST_F(LayerStateTest, getNonBufferHash_filtersOutBuffers) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; - layerFECompositionState.buffer = new GraphicBuffer(); + layerFECompositionState.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique<LayerState>(&mOutputLayer); @@ -1077,7 +1068,7 @@ TEST_F(LayerStateTest, getNonBufferHash_filtersOutBuffers) { mock::OutputLayer newOutputLayer; sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make(); LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.buffer = new GraphicBuffer(); + layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp index 68c72e0945..35d0ffb6e9 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp @@ -228,7 +228,7 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) { } TEST_F(LayerStackTest, getApproximateMatch_exactMatchesSameBuffer) { - sp<GraphicBuffer> buffer = new GraphicBuffer(); + sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(); mock::OutputLayer outputLayerOne; sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make(); OutputLayerCompositionState outputLayerCompositionStateOne; @@ -268,7 +268,7 @@ TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) { .dataspace = ui::Dataspace::SRGB, }; LayerFECompositionState layerFECompositionStateOne; - layerFECompositionStateOne.buffer = new GraphicBuffer(); + layerFECompositionStateOne.buffer = sp<GraphicBuffer>::make(); layerFECompositionStateOne.alpha = sAlphaOne; layerFECompositionStateOne.colorTransformIsIdentity = true; setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne, @@ -285,7 +285,7 @@ TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) { .dataspace = ui::Dataspace::DISPLAY_P3, }; LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.buffer = new GraphicBuffer(); + layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make(); layerFECompositionStateTwo.alpha = sAlphaTwo; layerFECompositionStateTwo.colorTransformIsIdentity = false; layerFECompositionStateTwo.colorTransform = sMat4One; @@ -310,7 +310,7 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchMultipleApproximations) { .sourceCrop = sFloatRectOne, }; LayerFECompositionState layerFECompositionStateOne; - layerFECompositionStateOne.buffer = new GraphicBuffer(); + layerFECompositionStateOne.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne, layerFECompositionStateOne); LayerState layerStateOne(&outputLayerOne); @@ -321,7 +321,7 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchMultipleApproximations) { .sourceCrop = sFloatRectTwo, }; LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.buffer = new GraphicBuffer(); + layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make(); setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo, layerFECompositionStateTwo); LayerState layerStateTwo(&outputLayerTwo); diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp deleted file mode 100644 index 3ccc229261..0000000000 --- a/services/surfaceflinger/ContainerLayer.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -// #define LOG_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "ContainerLayer" - -#include "ContainerLayer.h" - -namespace android { - -ContainerLayer::ContainerLayer(const LayerCreationArgs& args) : Layer(args) {} - -ContainerLayer::~ContainerLayer() = default; - -bool ContainerLayer::isVisible() const { - return false; -} - -sp<Layer> ContainerLayer::createClone() { - sp<ContainerLayer> layer = mFlinger->getFactory().createContainerLayer( - LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata())); - layer->setInitialValuesForClone(this); - return layer; -} - -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h deleted file mode 100644 index 9b7bab1e1d..0000000000 --- a/services/surfaceflinger/ContainerLayer.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ -#pragma once - -#include <sys/types.h> - -#include <cstdint> - -#include "Layer.h" - -namespace android { - -class ContainerLayer : public Layer { -public: - explicit ContainerLayer(const LayerCreationArgs&); - ~ContainerLayer() override; - - const char* getType() const override { return "ContainerLayer"; } - bool isVisible() const override; - - bool isCreatedFromMainThread() const override { return true; } - -protected: - bool canDrawShadows() const override { return false; } - sp<Layer> createClone() override; -}; - -} // namespace android diff --git a/services/surfaceflinger/Display/DisplayMap.h b/services/surfaceflinger/Display/DisplayMap.h new file mode 100644 index 0000000000..baf0da9f1b --- /dev/null +++ b/services/surfaceflinger/Display/DisplayMap.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include <ftl/small_map.h> + +namespace android::display { + +// The static capacities were chosen to exceed a typical number of physical and/or virtual displays. + +template <typename Key, typename Value> +using DisplayMap = ftl::SmallMap<Key, Value, 5>; + +template <typename Key, typename Value> +using PhysicalDisplayMap = ftl::SmallMap<Key, Value, 3>; + +} // namespace android::display diff --git a/services/surfaceflinger/Display/DisplaySnapshot.cpp b/services/surfaceflinger/Display/DisplaySnapshot.cpp new file mode 100644 index 0000000000..b4f104a74d --- /dev/null +++ b/services/surfaceflinger/Display/DisplaySnapshot.cpp @@ -0,0 +1,58 @@ +/* + * 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 <functional> +#include <utility> + +#include <ftl/algorithm.h> +#include <ftl/enum.h> + +#include "DisplaySnapshot.h" + +namespace android::display { + +DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId, + ui::DisplayConnectionType connectionType, + DisplayModes&& displayModes, + std::optional<DeviceProductInfo>&& deviceProductInfo) + : mDisplayId(displayId), + mConnectionType(connectionType), + mDisplayModes(std::move(displayModes)), + mDeviceProductInfo(std::move(deviceProductInfo)) {} + +std::optional<DisplayModeId> DisplaySnapshot::translateModeId(hal::HWConfigId hwcId) const { + return ftl::find_if(mDisplayModes, + [hwcId](const DisplayModes::value_type& pair) { + return pair.second->getHwcId() == hwcId; + }) + .transform(&ftl::to_key<DisplayModes>); +} + +void DisplaySnapshot::dump(std::string& out) const { + using namespace std::string_literals; + + out += " connectionType="s; + out += ftl::enum_string(mConnectionType); + + out += "\n deviceProductInfo="s; + if (mDeviceProductInfo) { + mDeviceProductInfo->dump(out); + } else { + out += "{}"s; + } +} + +} // namespace android::display diff --git a/services/surfaceflinger/Display/DisplaySnapshot.h b/services/surfaceflinger/Display/DisplaySnapshot.h new file mode 100644 index 0000000000..0279220b1b --- /dev/null +++ b/services/surfaceflinger/Display/DisplaySnapshot.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#pragma once + +#include <optional> +#include <string> + +#include <ui/DisplayId.h> +#include <ui/StaticDisplayInfo.h> + +#include "../DisplayHardware/DisplayMode.h" + +namespace android::display { + +// Immutable state of a physical display, captured on hotplug. +class DisplaySnapshot { +public: + DisplaySnapshot(PhysicalDisplayId, ui::DisplayConnectionType, DisplayModes&&, + std::optional<DeviceProductInfo>&&); + + DisplaySnapshot(const DisplaySnapshot&) = delete; + DisplaySnapshot(DisplaySnapshot&&) = default; + + PhysicalDisplayId displayId() const { return mDisplayId; } + ui::DisplayConnectionType connectionType() const { return mConnectionType; } + + std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const; + + const auto& displayModes() const { return mDisplayModes; } + const auto& deviceProductInfo() const { return mDeviceProductInfo; } + + void dump(std::string&) const; + +private: + const PhysicalDisplayId mDisplayId; + const ui::DisplayConnectionType mConnectionType; + + // Effectively const except in move constructor. + DisplayModes mDisplayModes; + std::optional<DeviceProductInfo> mDeviceProductInfo; +}; + +} // namespace android::display diff --git a/services/surfaceflinger/Display/PhysicalDisplay.h b/services/surfaceflinger/Display/PhysicalDisplay.h new file mode 100644 index 0000000000..cba10146b7 --- /dev/null +++ b/services/surfaceflinger/Display/PhysicalDisplay.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#pragma once + +#include <functional> +#include <utility> + +#include <binder/IBinder.h> +#include <ui/DisplayId.h> +#include <utils/StrongPointer.h> + +#include "DisplayMap.h" +#include "DisplaySnapshot.h" + +namespace android::display { + +// TODO(b/229877597): Replace with AIDL type. +using DisplayToken = IBinder; + +class PhysicalDisplay { +public: + template <typename... Args> + PhysicalDisplay(sp<DisplayToken> token, Args&&... args) + : mToken(std::move(token)), mSnapshot(std::forward<Args>(args)...) {} + + PhysicalDisplay(const PhysicalDisplay&) = delete; + PhysicalDisplay(PhysicalDisplay&&) = default; + + const sp<DisplayToken>& token() const { return mToken; } + const DisplaySnapshot& snapshot() const { return mSnapshot; } + + // Transformers for PhysicalDisplays::get. + + using SnapshotRef = std::reference_wrapper<const DisplaySnapshot>; + SnapshotRef snapshotRef() const { return std::cref(mSnapshot); } + + bool isInternal() const { + return mSnapshot.connectionType() == ui::DisplayConnectionType::Internal; + } + + // Predicate for ftl::find_if on PhysicalDisplays. + static constexpr auto hasToken(const sp<DisplayToken>& token) { + return [&token](const std::pair<const PhysicalDisplayId, PhysicalDisplay>& pair) { + return pair.second.token() == token; + }; + } + +private: + const sp<DisplayToken> mToken; + + // Effectively const except in move constructor. + DisplaySnapshot mSnapshot; +}; + +using PhysicalDisplays = PhysicalDisplayMap<PhysicalDisplayId, PhysicalDisplay>; + +// Combinator for ftl::Optional<PhysicalDisplayId>::and_then. +constexpr auto getPhysicalDisplay(const PhysicalDisplays& displays) { + return [&](PhysicalDisplayId id) { return displays.get(id); }; +} + +} // namespace android::display diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 26fbd55d6e..f8115ebcd9 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -39,6 +39,7 @@ #include <system/window.h> #include <ui/GraphicTypes.h> +#include "Display/DisplaySnapshot.h" #include "DisplayDevice.h" #include "Layer.h" #include "RefreshRateOverlay.h" @@ -63,12 +64,10 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mHwComposer(args.hwComposer), mDisplayToken(args.displayToken), mSequenceId(args.sequenceId), - mConnectionType(args.connectionType), mCompositionDisplay{args.compositionDisplay}, mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())), mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())), mPhysicalOrientation(args.physicalOrientation), - mSupportedModes(std::move(args.supportedModes)), mIsPrimary(args.isPrimary), mRefreshRateConfigs(std::move(args.refreshRateConfigs)) { mCompositionDisplay->editState().isSecure = args.isSecure; @@ -132,14 +131,6 @@ void DisplayDevice::setDisplayName(const std::string& displayName) { } } -void DisplayDevice::setDeviceProductInfo(std::optional<DeviceProductInfo> info) { - mDeviceProductInfo = std::move(info); -} - -uint32_t DisplayDevice::getPageFlipCount() const { - return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); -} - auto DisplayDevice::getInputInfo() const -> InputInfo { gui::DisplayInfo info; info.displayId = getLayerStack().id; @@ -200,16 +191,19 @@ bool DisplayDevice::isPoweredOn() const { return mPowerMode && *mPowerMode != hal::PowerMode::OFF; } -void DisplayDevice::setActiveMode(DisplayModeId id) { - const auto mode = getMode(id); - LOG_FATAL_IF(!mode, "Cannot set active mode which is not supported."); - ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue()); - mActiveMode = mode; - if (mRefreshRateConfigs) { - mRefreshRateConfigs->setActiveModeId(mActiveMode->getId()); - } +void DisplayDevice::setActiveMode(DisplayModeId modeId, const display::DisplaySnapshot& snapshot) { + const auto fpsOpt = snapshot.displayModes().get(modeId).transform( + [](const DisplayModePtr& mode) { return mode->getFps(); }); + + LOG_ALWAYS_FATAL_IF(!fpsOpt, "Unknown mode"); + const Fps fps = *fpsOpt; + + ATRACE_INT(mActiveModeFPSTrace.c_str(), fps.getIntValue()); + + mRefreshRateConfigs->setActiveModeId(modeId); + if (mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(mActiveMode->getFps()); + mRefreshRateOverlay->changeRefreshRate(fps); } } @@ -229,29 +223,6 @@ status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info, constraints, outTimeline); } -const DisplayModePtr& DisplayDevice::getActiveMode() const { - return mActiveMode; -} - -const DisplayModes& DisplayDevice::getSupportedModes() const { - return mSupportedModes; -} - -DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const { - const DisplayModePtr nullMode; - return mSupportedModes.get(modeId).value_or(std::cref(nullMode)); -} - -std::optional<DisplayModeId> DisplayDevice::translateModeId(hal::HWConfigId hwcId) const { - const auto it = - std::find_if(mSupportedModes.begin(), mSupportedModes.end(), - [hwcId](const auto& pair) { return pair.second->getHwcId() == hwcId; }); - if (it != mSupportedModes.end()) { - return it->second->getId(); - } - return {}; -} - nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { const auto physicalId = getPhysicalId(); if (!mHwComposer.isConnected(physicalId)) { @@ -264,27 +235,17 @@ nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { return vsyncPeriod; } - return getActiveMode()->getFps().getPeriodNsecs(); -} - -nsecs_t DisplayDevice::getRefreshTimestamp() const { - const nsecs_t now = systemTime(CLOCK_MONOTONIC); - const auto vsyncPeriodNanos = getVsyncPeriodFromHWC(); - return now - ((now - mLastHwVsync) % vsyncPeriodNanos); -} - -void DisplayDevice::onVsync(nsecs_t timestamp) { - mLastHwVsync = timestamp; + return refreshRateConfigs().getActiveModePtr()->getVsyncPeriod(); } ui::Dataspace DisplayDevice::getCompositionDataSpace() const { return mCompositionDisplay->getState().dataspace; } -void DisplayDevice::setLayerStack(ui::LayerStack stack) { - mCompositionDisplay->setLayerFilter({stack, isInternal()}); +void DisplayDevice::setLayerFilter(ui::LayerFilter filter) { + mCompositionDisplay->setLayerFilter(filter); if (mRefreshRateOverlay) { - mRefreshRateOverlay->setLayerStack(stack); + mRefreshRateOverlay->setLayerStack(filter.layerStack); } } @@ -358,11 +319,7 @@ std::string DisplayDevice::getDebugName() const { std::string name = "Display "s + to_string(getId()) + " ("s; - if (mConnectionType) { - name += isInternal() ? "internal"s : "external"s; - } else { - name += "virtual"s; - } + name += isVirtual() ? "virtual"s : "physical"s; if (isPrimary()) { name += ", primary"s; @@ -376,15 +333,6 @@ void DisplayDevice::dump(std::string& result) const { result += getDebugName(); - if (!isVirtual()) { - result += "\n deviceProductInfo="s; - if (mDeviceProductInfo) { - mDeviceProductInfo->dump(result); - } else { - result += "{}"s; - } - } - result += "\n powerMode="s; result += mPowerMode.has_value() ? to_string(mPowerMode.value()) : "OFF(reset)"; result += '\n'; @@ -488,7 +436,7 @@ void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, showSpinnner); mRefreshRateOverlay->setLayerStack(getLayerStack()); mRefreshRateOverlay->setViewport(getSize()); - mRefreshRateOverlay->changeRefreshRate(getActiveMode()->getFps()); + mRefreshRateOverlay->changeRefreshRate(getActiveMode().getFps()); } bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredModeId, @@ -529,7 +477,7 @@ bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) { } // Check if we are already at the desired mode - if (getActiveMode()->getId() == info.mode->getId()) { + if (refreshRateConfigs().getActiveModePtr()->getId() == info.mode->getId()) { return false; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index fc24a9ce49..510df81da1 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -65,6 +65,10 @@ class Display; class DisplaySurface; } // namespace compositionengine +namespace display { +class DisplaySnapshot; +} // namespace display + class DisplayDevice : public RefBase { public: constexpr static float sDefaultMinLumiance = 0.0; @@ -80,11 +84,8 @@ public: return mCompositionDisplay; } - std::optional<ui::DisplayConnectionType> getConnectionType() const { return mConnectionType; } - - bool isVirtual() const { return !mConnectionType; } + bool isVirtual() const { return VirtualDisplayId::tryCast(getId()).has_value(); } bool isPrimary() const { return mIsPrimary; } - bool isInternal() const { return mConnectionType == ui::DisplayConnectionType::Internal; } // isSecure indicates whether this display can be trusted to display // secure surfaces. @@ -94,7 +95,7 @@ public: int getHeight() const; ui::Size getSize() const { return {getWidth(), getHeight()}; } - void setLayerStack(ui::LayerStack); + void setLayerFilter(ui::LayerFilter); void setDisplaySize(int width, int height); void setProjection(ui::Rotation orientation, Rect viewport, Rect frame); void stageBrightness(float brightness) REQUIRES(kMainThreadContext); @@ -164,11 +165,6 @@ public: void setDisplayName(const std::string& displayName); const std::string& getDisplayName() const { return mDisplayName; } - void setDeviceProductInfo(std::optional<DeviceProductInfo> info); - const std::optional<DeviceProductInfo>& getDeviceProductInfo() const { - return mDeviceProductInfo; - } - struct InputInfo { gui::DisplayInfo info; ui::Transform transform; @@ -193,8 +189,6 @@ public: /* ------------------------------------------------------------------------ * Display mode management. */ - const DisplayModePtr& getActiveMode() const; - struct ActiveModeInfo { DisplayModePtr mode; scheduler::DisplayModeEvent event = scheduler::DisplayModeEvent::None; @@ -211,24 +205,18 @@ public: return mUpcomingActiveMode; } - void setActiveMode(DisplayModeId) REQUIRES(kMainThreadContext); + const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext) { + return mRefreshRateConfigs->getActiveMode(); + } + + // Precondition: DisplaySnapshot must contain a mode with DisplayModeId. + void setActiveMode(DisplayModeId, const display::DisplaySnapshot&) REQUIRES(kMainThreadContext); + status_t initiateModeChange(const ActiveModeInfo&, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) REQUIRES(kMainThreadContext); - // Return the immutable list of supported display modes. The HWC may report different modes - // after a hotplug reconnect event, in which case the DisplayDevice object will be recreated. - // Hotplug reconnects are common for external displays. - const DisplayModes& getSupportedModes() const; - - // Returns nullptr if the given mode ID is not supported. A previously - // supported mode may be no longer supported for some devices like TVs and - // set-top boxes after a hotplug reconnect. - DisplayModePtr getMode(DisplayModeId) const; - - std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const; - // Returns the refresh rate configs for this display. scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; } @@ -240,14 +228,12 @@ public: } // Enables an overlay to be displayed with the current refresh rate - void enableRefreshRateOverlay(bool enable, bool showSpinner); + void enableRefreshRateOverlay(bool enable, bool showSpinner) REQUIRES(kMainThreadContext); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired); void animateRefreshRateOverlay(); - void onVsync(nsecs_t timestamp); nsecs_t getVsyncPeriodFromHWC() const; - nsecs_t getRefreshTimestamp() const; status_t setRefreshRatePolicy( const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, @@ -259,7 +245,6 @@ public: /* ------------------------------------------------------------------------ * Debugging */ - uint32_t getPageFlipCount() const; std::string getDebugName() const; void dump(std::string& result) const; @@ -268,7 +253,6 @@ private: HWComposer& mHwComposer; const wp<IBinder> mDisplayToken; const int32_t mSequenceId; - const std::optional<ui::DisplayConnectionType> mConnectionType; const std::shared_ptr<compositionengine::Display> mCompositionDisplay; @@ -281,22 +265,17 @@ private: static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags; - // allow initial power mode as null. + // Allow nullopt as initial power mode. std::optional<hardware::graphics::composer::hal::PowerMode> mPowerMode; - DisplayModePtr mActiveMode; - std::optional<float> mStagedBrightness = std::nullopt; - float mBrightness = -1.f; - const DisplayModes mSupportedModes; - std::atomic<nsecs_t> mLastHwVsync = 0; + std::optional<float> mStagedBrightness; + float mBrightness = -1.f; // TODO(b/182939859): Remove special cases for primary display. const bool mIsPrimary; uint32_t mFlags = 0; - std::optional<DeviceProductInfo> mDeviceProductInfo; - std::vector<ui::Hdr> mOverrideHdrTypes; std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; @@ -314,14 +293,11 @@ private: struct DisplayDeviceState { struct Physical { PhysicalDisplayId id; - ui::DisplayConnectionType type; hardware::graphics::composer::hal::HWDisplayId hwcDisplayId; - std::optional<DeviceProductInfo> deviceProductInfo; - DisplayModes supportedModes; DisplayModePtr activeMode; bool operator==(const Physical& other) const { - return id == other.id && type == other.type && hwcDisplayId == other.hwcDisplayId; + return id == other.id && hwcDisplayId == other.hwcDisplayId; } }; @@ -357,7 +333,6 @@ struct DisplayDeviceCreationArgs { std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs; int32_t sequenceId{0}; - std::optional<ui::DisplayConnectionType> connectionType; bool isSecure{false}; sp<ANativeWindow> nativeWindow; sp<compositionengine::DisplaySurface> displaySurface; @@ -368,7 +343,6 @@ struct DisplayDeviceCreationArgs { std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes; std::optional<hardware::graphics::composer::hal::PowerMode> initialPowerMode; bool isPrimary{false}; - DisplayModes supportedModes; DisplayModeId activeModeId; }; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index c52e96d146..16d398474d 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -369,7 +369,7 @@ Error Display::getReleaseFences(std::unordered_map<HWC2::Layer*, sp<Fence>>* out for (uint32_t element = 0; element < numElements; ++element) { auto layer = getLayerById(layerIds[element]); if (layer) { - sp<Fence> fence(new Fence(fenceFds[element])); + sp<Fence> fence(sp<Fence>::make(fenceFds[element])); releaseFences.emplace(layer.get(), fence); } else { ALOGE("getReleaseFences: invalid layer %" PRIu64 @@ -394,7 +394,7 @@ Error Display::present(sp<Fence>* outPresentFence) return error; } - *outPresentFence = new Fence(presentFenceFd); + *outPresentFence = sp<Fence>::make(presentFenceFd); return Error::NONE; } @@ -532,7 +532,7 @@ Error Display::presentOrValidate(nsecs_t expectedPresentTime, uint32_t* outNumTy } if (*state == 1) { - *outPresentFence = new Fence(presentFenceFd); + *outPresentFence = sp<Fence>::make(presentFenceFd); } if (*state == 0) { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 24aef9b73c..96399e263e 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -70,7 +70,7 @@ namespace hal = android::hardware::graphics::composer::hal; struct ComposerCallback { virtual void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) = 0; virtual void onComposerHalRefresh(hal::HWDisplayId) = 0; - virtual void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp, + virtual void onComposerHalVsync(hal::HWDisplayId, nsecs_t timestamp, std::optional<hal::VsyncPeriodNanos>) = 0; virtual void onComposerHalVsyncPeriodTimingChanged(hal::HWDisplayId, const hal::VsyncPeriodChangeTimeline&) = 0; @@ -88,7 +88,7 @@ public: virtual hal::HWDisplayId getId() const = 0; virtual bool isConnected() const = 0; - virtual void setConnected(bool connected) = 0; // For use by Device only + virtual void setConnected(bool connected) = 0; // For use by HWComposer only virtual bool hasCapability( aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0; virtual bool isVsyncPeriodSwitchSupported() const = 0; @@ -253,7 +253,7 @@ public: // Other Display methods hal::HWDisplayId getId() const override { return mId; } bool isConnected() const override { return mIsConnected; } - void setConnected(bool connected) override; // For use by Device only + void setConnected(bool connected) override; bool hasCapability(aidl::android::hardware::graphics::composer3::DisplayCapability) const override EXCLUDES(mDisplayCapabilitiesMutex); bool isVsyncPeriodSwitchSupported() const override; @@ -271,7 +271,7 @@ private: // Member variables - // These are references to data owned by HWC2::Device, which will outlive + // These are references to data owned by HWComposer, which will outlive // this HWC2::Display, so these references are guaranteed to be valid for // the lifetime of this object. android::Hwc2::Composer& mComposer; @@ -383,7 +383,7 @@ public: hal::Error setBlockingRegion(const android::Region& region) override; private: - // These are references to data owned by HWC2::Device, which will outlive + // These are references to data owned by HWComposer, which will outlive // this HWC2::Layer, so these references are guaranteed to be valid for // the lifetime of this object. android::Hwc2::Composer& mComposer; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index a6aee1f2f5..0a4ad9796b 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -144,7 +144,7 @@ bool HWComposer::updatesDeviceProductInfoOnHotplugReconnect() const { return mUpdateDeviceProductInfoOnHotplugReconnect; } -bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { +bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, nsecs_t timestamp) { const auto displayId = toPhysicalDisplayId(hwcDisplayId); if (!displayId) { LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display"); @@ -160,13 +160,13 @@ bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { // with the same timestamp when turning the display off and on. This // is a bug in the HWC implementation, but filter the extra events // out here so they don't cause havoc downstream. - if (timestamp == displayData.lastHwVsync) { + if (timestamp == displayData.lastPresentTimestamp) { ALOGW("Ignoring duplicate VSYNC event from HWC for display %s (t=%" PRId64 ")", to_string(*displayId).c_str(), timestamp); return false; } - displayData.lastHwVsync = timestamp; + displayData.lastPresentTimestamp = timestamp; } const auto tag = "HW_VSYNC_" + to_string(*displayId); @@ -252,11 +252,7 @@ std::shared_ptr<HWC2::Layer> HWComposer::createLayer(HalDisplayId displayId) { } bool HWComposer::isConnected(PhysicalDisplayId displayId) const { - if (mDisplayData.count(displayId)) { - return mDisplayData.at(displayId).hwcDisplay->isConnected(); - } - - return false; + return mDisplayData.count(displayId) && mDisplayData.at(displayId).hwcDisplay->isConnected(); } std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId displayId) const { @@ -286,17 +282,12 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId d std::optional<hal::HWConfigId> HWComposer::getActiveMode(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt); - const auto hwcId = *fromPhysicalDisplayId(displayId); - ALOGV("[%" PRIu64 "] getActiveMode", hwcId); - hal::HWConfigId configId; - auto error = static_cast<hal::Error>(mComposer->getActiveConfig(hwcId, &configId)); - if (error == hal::Error::BAD_CONFIG) { - LOG_DISPLAY_ERROR(displayId, "No active mode"); - return std::nullopt; - } + hal::HWConfigId configId; + const auto error = static_cast<hal::Error>(mComposer->getActiveConfig(hwcId, &configId)); + RETURN_IF_HWC_ERROR_FOR("getActiveConfig", error, displayId, std::nullopt); return configId; } @@ -494,6 +485,11 @@ sp<Fence> HWComposer::getPresentFence(HalDisplayId displayId) const { return mDisplayData.at(displayId).lastPresentFence; } +nsecs_t HWComposer::getPresentTimestamp(PhysicalDisplayId displayId) const { + RETURN_IF_INVALID_DISPLAY(displayId, 0); + return mDisplayData.at(displayId).lastPresentTimestamp; +} + sp<Fence> HWComposer::getLayerReleaseFence(HalDisplayId displayId, HWC2::Layer* layer) const { RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE); const auto& displayFences = mDisplayData.at(displayId).releaseFences; @@ -951,18 +947,15 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect( return {}; } - // The display will later be destroyed by a call to - // destroyDisplay(). For now we just mark it disconnected. - if (isConnected(*displayId)) { - mDisplayData[*displayId].hwcDisplay->setConnected(false); - } else { + if (!isConnected(*displayId)) { LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected"); + return {}; } - // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay - // via SurfaceFlinger's onHotplugReceived callback handling - return DisplayIdentificationInfo{.id = *displayId, - .name = std::string(), - .deviceProductInfo = std::nullopt}; + + // The display will later be destroyed by a call to HWComposer::disconnectDisplay. For now, mark + // it as disconnected. + mDisplayData.at(*displayId).hwcDisplay->setConnected(false); + return DisplayIdentificationInfo{.id = *displayId}; } void HWComposer::loadCapabilities() { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 92a8f30f1b..6c43d8b812 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -160,8 +160,9 @@ public: // reset state when a display is disconnected virtual void disconnectDisplay(HalDisplayId) = 0; - // get the present fence received from the last call to present. + // Get the present fence/timestamp received from the last call to present. virtual sp<Fence> getPresentFence(HalDisplayId) const = 0; + virtual nsecs_t getPresentTimestamp(PhysicalDisplayId) const = 0; // Get last release fence for the given layer virtual sp<Fence> getLayerReleaseFence(HalDisplayId, HWC2::Layer*) const = 0; @@ -214,7 +215,7 @@ public: // TODO(b/157555476): Remove when the framework has proper support for headless mode virtual bool updatesDeviceProductInfoOnHotplugReconnect() const = 0; - virtual bool onVsync(hal::HWDisplayId, int64_t timestamp) = 0; + virtual bool onVsync(hal::HWDisplayId, nsecs_t timestamp) = 0; virtual void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) = 0; virtual bool isConnected(PhysicalDisplayId) const = 0; @@ -343,8 +344,9 @@ public: // reset state when a display is disconnected void disconnectDisplay(HalDisplayId) override; - // get the present fence received from the last call to present. + // Get the present fence/timestamp received from the last call to present. sp<Fence> getPresentFence(HalDisplayId) const override; + nsecs_t getPresentTimestamp(PhysicalDisplayId) const override; // Get last release fence for the given layer sp<Fence> getLayerReleaseFence(HalDisplayId, HWC2::Layer*) const override; @@ -387,7 +389,7 @@ public: bool updatesDeviceProductInfoOnHotplugReconnect() const override; - bool onVsync(hal::HWDisplayId, int64_t timestamp) override; + bool onVsync(hal::HWDisplayId, nsecs_t timestamp) override; void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) override; bool isConnected(PhysicalDisplayId) const override; @@ -456,7 +458,10 @@ private: struct DisplayData { std::unique_ptr<HWC2::Display> hwcDisplay; + sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires + nsecs_t lastPresentTimestamp = 0; + std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; bool validateWasSkipped; @@ -466,8 +471,6 @@ private: std::mutex vsyncEnabledLock; hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE; - - nsecs_t lastHwVsync = 0; }; std::optional<DisplayIdentificationInfo> onHotplugConnect(hal::HWDisplayId); diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index a0350b717a..cb2c8c53ef 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -59,8 +59,6 @@ using android::hardware::power::IPowerHintSession; using android::hardware::power::Mode; using android::hardware::power::WorkDuration; -using scheduler::OneShotTimer; - PowerAdvisor::~PowerAdvisor() = default; namespace { @@ -196,7 +194,7 @@ bool PowerAdvisor::isPowerHintSessionRunning() { return mPowerHintSessionRunning; } -void PowerAdvisor::setTargetWorkDuration(int64_t targetDuration) { +void PowerAdvisor::setTargetWorkDuration(Duration targetDuration) { if (!usePowerHintSession()) { ALOGV("Power hint session target duration cannot be set, skipping"); return; @@ -215,13 +213,13 @@ void PowerAdvisor::sendActualWorkDuration() { ALOGV("Actual work duration power hint cannot be sent, skipping"); return; } - const std::optional<nsecs_t> actualDuration = estimateWorkDuration(false); + const std::optional<Duration> actualDuration = estimateWorkDuration(false); if (actualDuration.has_value()) { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { - halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin.count(), - systemTime()); + halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin, + TimePoint::now()); } } } @@ -232,14 +230,14 @@ void PowerAdvisor::sendPredictedWorkDuration() { return; } - const std::optional<nsecs_t> predictedDuration = estimateWorkDuration(true); + const std::optional<Duration> predictedDuration = estimateWorkDuration(true); if (predictedDuration.has_value()) { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { - halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin.count(), - systemTime()); + halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin, + TimePoint::now()); } } } @@ -281,22 +279,22 @@ void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTim } } displayData.lastValidGpuStartTime = displayData.gpuStartTime; - displayData.lastValidGpuEndTime = signalTime; + displayData.lastValidGpuEndTime = TimePoint::fromNs(signalTime); } } displayData.gpuEndFenceTime = std::move(fenceTime); - displayData.gpuStartTime = systemTime(); + displayData.gpuStartTime = TimePoint::now(); } -void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime, - nsecs_t validateEndTime) { +void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime, + TimePoint validateEndTime) { DisplayTimingData& displayData = mDisplayTimingData[displayId]; displayData.hwcValidateStartTime = validateStartTime; displayData.hwcValidateEndTime = validateEndTime; } -void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, - nsecs_t presentEndTime) { +void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime, + TimePoint presentEndTime) { DisplayTimingData& displayData = mDisplayTimingData[displayId]; displayData.hwcPresentStartTime = presentStartTime; displayData.hwcPresentEndTime = presentEndTime; @@ -311,43 +309,41 @@ void PowerAdvisor::setRequiresClientComposition(DisplayId displayId, mDisplayTimingData[displayId].usedClientComposition = requiresClientComposition; } -void PowerAdvisor::setExpectedPresentTime(nsecs_t expectedPresentTime) { +void PowerAdvisor::setExpectedPresentTime(TimePoint expectedPresentTime) { mExpectedPresentTimes.append(expectedPresentTime); } -void PowerAdvisor::setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) { +void PowerAdvisor::setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) { mLastSfPresentEndTime = presentEndTime; mLastPresentFenceTime = presentFenceTime; } -void PowerAdvisor::setFrameDelay(nsecs_t frameDelayDuration) { +void PowerAdvisor::setFrameDelay(Duration frameDelayDuration) { mFrameDelayDuration = frameDelayDuration; } -void PowerAdvisor::setHwcPresentDelayedTime( - DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) { - mDisplayTimingData[displayId].hwcPresentDelayedTime = - (earliestFrameStartTime - std::chrono::steady_clock::now()).count() + systemTime(); +void PowerAdvisor::setHwcPresentDelayedTime(DisplayId displayId, TimePoint earliestFrameStartTime) { + mDisplayTimingData[displayId].hwcPresentDelayedTime = earliestFrameStartTime; } -void PowerAdvisor::setCommitStart(nsecs_t commitStartTime) { +void PowerAdvisor::setCommitStart(TimePoint commitStartTime) { mCommitStartTimes.append(commitStartTime); } -void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) { - mLastPostcompDuration = compositeEnd - mLastSfPresentEndTime; +void PowerAdvisor::setCompositeEnd(TimePoint compositeEndTime) { + mLastPostcompDuration = compositeEndTime - mLastSfPresentEndTime; } void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) { mDisplayIds = displayIds; } -void PowerAdvisor::setTotalFrameTargetWorkDuration(nsecs_t targetDuration) { +void PowerAdvisor::setTotalFrameTargetWorkDuration(Duration targetDuration) { mTotalFrameTargetDuration = targetDuration; } std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds( - std::optional<nsecs_t> DisplayTimingData::*sortBy) { + std::optional<TimePoint> DisplayTimingData::*sortBy) { std::vector<DisplayId> sortedDisplays; std::copy_if(mDisplayIds.begin(), mDisplayIds.end(), std::back_inserter(sortedDisplays), [&](DisplayId id) { @@ -360,33 +356,34 @@ std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds( return sortedDisplays; } -std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { +std::optional<Duration> PowerAdvisor::estimateWorkDuration(bool earlyHint) { if (earlyHint && (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull())) { return std::nullopt; } // Tracks when we finish presenting to hwc - nsecs_t estimatedEndTime = mCommitStartTimes[0]; + TimePoint estimatedEndTime = mCommitStartTimes[0]; // How long we spent this frame not doing anything, waiting for fences or vsync - nsecs_t idleDuration = 0; + Duration idleDuration = 0ns; // Most recent previous gpu end time in the current frame, probably from a prior display, used // as the start time for the next gpu operation if it ran over time since it probably blocked - std::optional<nsecs_t> previousValidGpuEndTime; + std::optional<TimePoint> previousValidGpuEndTime; // The currently estimated gpu end time for the frame, // used to accumulate gpu time as we iterate over the active displays - std::optional<nsecs_t> estimatedGpuEndTime; + std::optional<TimePoint> estimatedGpuEndTime; // If we're predicting at the start of the frame, we use last frame as our reference point // If we're predicting at the end of the frame, we use the current frame as a reference point - nsecs_t referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]); + TimePoint referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]); // When the prior frame should be presenting to the display // If we're predicting at the start of the frame, we use last frame's expected present time // If we're predicting at the end of the frame, the present fence time is already known - nsecs_t lastFramePresentTime = (earlyHint ? mExpectedPresentTimes[-1] : mLastPresentFenceTime); + TimePoint lastFramePresentTime = + (earlyHint ? mExpectedPresentTimes[-1] : mLastPresentFenceTime); // The timing info for the previously calculated display, if there was one std::optional<DisplayTimeline> previousDisplayReferenceTiming; @@ -427,10 +424,10 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { // Track how long we spent waiting for the fence, can be excluded from the timing estimate idleDuration += estimatedTiming.probablyWaitsForPresentFence ? lastFramePresentTime - estimatedTiming.presentFenceWaitStartTime - : 0; + : 0ns; // Track how long we spent waiting to present, can be excluded from the timing estimate - idleDuration += earlyHint ? 0 : referenceTiming.hwcPresentDelayDuration; + idleDuration += earlyHint ? 0ns : referenceTiming.hwcPresentDelayDuration; // Estimate the reference frame's gpu timing auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime); @@ -438,15 +435,15 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration; // Estimate the prediction frame's gpu end time from the reference frame - estimatedGpuEndTime = - std::max(estimatedTiming.hwcPresentStartTime, estimatedGpuEndTime.value_or(0)) + + estimatedGpuEndTime = std::max(estimatedTiming.hwcPresentStartTime, + estimatedGpuEndTime.value_or(TimePoint{0ns})) + gpuTiming->duration; } previousDisplayReferenceTiming = referenceTiming; } - ATRACE_INT64("Idle duration", idleDuration); + ATRACE_INT64("Idle duration", idleDuration.ns()); - nsecs_t estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime; + TimePoint estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime; // Don't count time spent idly waiting in the estimate as we could do more work in that time estimatedEndTime -= idleDuration; @@ -454,21 +451,22 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { // We finish the frame when both present and the gpu are done, so wait for the later of the two // Also add the frame delay duration since the target did not move while we were delayed - nsecs_t totalDuration = mFrameDelayDuration + - std::max(estimatedEndTime, estimatedGpuEndTime.value_or(0)) - mCommitStartTimes[0]; + Duration totalDuration = mFrameDelayDuration + + std::max(estimatedEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) - + mCommitStartTimes[0]; // We finish SurfaceFlinger when post-composition finishes, so add that in here - nsecs_t flingerDuration = + Duration flingerDuration = estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0]; // Combine the two timings into a single normalized one - nsecs_t combinedDuration = combineTimingEstimates(totalDuration, flingerDuration); + Duration combinedDuration = combineTimingEstimates(totalDuration, flingerDuration); return std::make_optional(combinedDuration); } -nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration) { - nsecs_t targetDuration; +Duration PowerAdvisor::combineTimingEstimates(Duration totalDuration, Duration flingerDuration) { + Duration targetDuration{0ns}; { std::lock_guard lock(mPowerHalMutex); targetDuration = *getPowerHal()->getTargetWorkDuration(); @@ -477,17 +475,18 @@ nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flin // Normalize total to the flinger target (vsync period) since that's how often we actually send // hints - nsecs_t normalizedTotalDuration = (targetDuration * totalDuration) / *mTotalFrameTargetDuration; + Duration normalizedTotalDuration = Duration::fromNs((targetDuration.ns() * totalDuration.ns()) / + mTotalFrameTargetDuration->ns()); return std::max(flingerDuration, normalizedTotalDuration); } PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference( - nsecs_t fenceTime, nsecs_t displayStartTime) { + TimePoint fenceTime, TimePoint displayStartTime) { DisplayTimeline estimated; estimated.hwcPresentStartTime = displayStartTime; // We don't predict waiting for vsync alignment yet - estimated.hwcPresentDelayDuration = 0; + estimated.hwcPresentDelayDuration = 0ns; // How long we expect to run before we start waiting for the fence // For now just re-use last frame's post-present duration and assume it will not change much @@ -502,12 +501,11 @@ PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFro } PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline( - nsecs_t fenceTime) { + TimePoint fenceTime) { DisplayTimeline timeline; // How long between calling hwc present and trying to wait on the fence - const nsecs_t fenceWaitStartDelay = - (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated) - .count(); + const Duration fenceWaitStartDelay = + (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated); // Did our reference frame wait for an appropriate vsync before calling into hwc const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() && @@ -522,7 +520,7 @@ PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayT // How long hwc present was delayed waiting for the next appropriate vsync timeline.hwcPresentDelayDuration = - (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0); + (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0ns); // When we started waiting for the present fence after calling into hwc present timeline.presentFenceWaitStartTime = timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay; @@ -537,23 +535,26 @@ PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayT } std::optional<PowerAdvisor::GpuTimeline> PowerAdvisor::DisplayTimingData::estimateGpuTiming( - std::optional<nsecs_t> previousEnd) { + std::optional<TimePoint> previousEndTime) { if (!(usedClientComposition && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) { return std::nullopt; } - const nsecs_t latestGpuStartTime = std::max(previousEnd.value_or(0), *gpuStartTime); - const nsecs_t latestGpuEndTime = gpuEndFenceTime->getSignalTime(); - nsecs_t gpuDuration = 0; - if (latestGpuEndTime != Fence::SIGNAL_TIME_INVALID && - latestGpuEndTime != Fence::SIGNAL_TIME_PENDING) { + const TimePoint latestGpuStartTime = + std::max(previousEndTime.value_or(TimePoint{0ns}), *gpuStartTime); + const nsecs_t gpuEndFenceSignal = gpuEndFenceTime->getSignalTime(); + Duration gpuDuration{0ns}; + if (gpuEndFenceSignal != Fence::SIGNAL_TIME_INVALID && + gpuEndFenceSignal != Fence::SIGNAL_TIME_PENDING) { + const TimePoint latestGpuEndTime = TimePoint::fromNs(gpuEndFenceSignal); + // If we know how long the most recent gpu duration was, use that gpuDuration = latestGpuEndTime - latestGpuStartTime; } else if (lastValidGpuEndTime.has_value()) { // If we don't have the fence data, use the most recent information we do have gpuDuration = *lastValidGpuEndTime - *lastValidGpuStartTime; - if (latestGpuEndTime == Fence::SIGNAL_TIME_PENDING) { + if (gpuEndFenceSignal == Fence::SIGNAL_TIME_PENDING) { // If pending but went over the previous duration, use current time as the end - gpuDuration = std::max(gpuDuration, systemTime() - latestGpuStartTime); + gpuDuration = std::max(gpuDuration, Duration{TimePoint::now() - latestGpuStartTime}); } } return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime}; @@ -614,15 +615,15 @@ public: bool startPowerHintSession() override { return false; } - void setTargetWorkDuration(int64_t) override {} + void setTargetWorkDuration(Duration) override {} - void sendActualWorkDuration(int64_t, nsecs_t) override {} + void sendActualWorkDuration(Duration, TimePoint) override {} bool shouldReconnectHAL() override { return false; } std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; } - std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; } + std::optional<Duration> getTargetWorkDuration() override { return std::nullopt; } private: const sp<V1_3::IPower> mPowerHal = nullptr; @@ -640,9 +641,6 @@ AidlPowerHalWrapper::AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::m } mSupportsPowerHint = checkPowerHintSessionSupported(); - - // Currently set to 0 to disable rate limiter by default - mAllowedActualDeviation = base::GetIntProperty<nsecs_t>("debug.sf.allowed_actual_deviation", 0); } AidlPowerHalWrapper::~AidlPowerHalWrapper() { @@ -730,9 +728,9 @@ bool AidlPowerHalWrapper::startPowerHintSession() { ALOGV("Cannot start power hint session, skipping"); return false; } - auto ret = - mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()), - mPowerHintThreadIds, mTargetDuration, &mPowerHintSession); + auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()), + mPowerHintThreadIds, mTargetDuration.ns(), + &mPowerHintSession); if (!ret.isOk()) { ALOGW("Failed to start power hint session with error: %s", ret.exceptionToString(ret.exceptionCode()).c_str()); @@ -742,14 +740,14 @@ bool AidlPowerHalWrapper::startPowerHintSession() { return isPowerHintSessionRunning(); } -void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDuration) { +void AidlPowerHalWrapper::setTargetWorkDuration(Duration targetDuration) { ATRACE_CALL(); mTargetDuration = targetDuration; - if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration); + if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns()); if (isPowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) { - ALOGV("Sending target time: %" PRId64 "ns", targetDuration); + ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns()); mLastTargetDurationSent = targetDuration; - auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration); + auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration.ns()); if (!ret.isOk()) { ALOGW("Failed to set power hint target work duration with error: %s", ret.exceptionMessage().c_str()); @@ -758,64 +756,40 @@ void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDuration) { } } -bool AidlPowerHalWrapper::shouldReportActualDurations() { - // Report if we have never reported before or are approaching a stale session - if (!mLastActualDurationSent.has_value() || - (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) { - return true; - } - - if (!mActualDuration.has_value()) { - return false; - } - // Report if the change in actual duration exceeds the threshold - return abs(*mActualDuration - *mLastActualDurationSent) > mAllowedActualDeviation; -} - -void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDuration, nsecs_t timestamp) { +void AidlPowerHalWrapper::sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) { ATRACE_CALL(); - - if (actualDuration < 0 || !isPowerHintSessionRunning()) { + if (actualDuration < 0ns || !isPowerHintSessionRunning()) { ALOGV("Failed to send actual work duration, skipping"); return; } - const nsecs_t reportedDuration = actualDuration; - - mActualDuration = reportedDuration; + mActualDuration = actualDuration; WorkDuration duration; - duration.durationNanos = reportedDuration; - duration.timeStampNanos = timestamp; + duration.durationNanos = actualDuration.ns(); + duration.timeStampNanos = timestamp.ns(); mPowerHintQueue.push_back(duration); if (sTraceHintSessionData) { - ATRACE_INT64("Measured duration", actualDuration); - ATRACE_INT64("Target error term", actualDuration - mTargetDuration); + ATRACE_INT64("Measured duration", actualDuration.ns()); + ATRACE_INT64("Target error term", Duration{actualDuration - mTargetDuration}.ns()); - ATRACE_INT64("Reported duration", reportedDuration); - ATRACE_INT64("Reported target", mLastTargetDurationSent); - ATRACE_INT64("Reported target error term", reportedDuration - mLastTargetDurationSent); + ATRACE_INT64("Reported duration", actualDuration.ns()); + ATRACE_INT64("Reported target", mLastTargetDurationSent.ns()); + ATRACE_INT64("Reported target error term", + Duration{actualDuration - mLastTargetDurationSent}.ns()); } ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64 " with error: %" PRId64, - reportedDuration, mLastTargetDurationSent, reportedDuration - mLastTargetDurationSent); - - // This rate limiter queues similar duration reports to the powerhal into - // batches to avoid excessive binder calls. The criteria to send a given batch - // are outlined in shouldReportActualDurationsNow() - if (shouldReportActualDurations()) { - ALOGV("Sending hint update batch"); - mLastActualReportTimestamp = systemTime(); - auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue); - if (!ret.isOk()) { - ALOGW("Failed to report actual work durations with error: %s", - ret.exceptionMessage().c_str()); - mShouldReconnectHal = true; - } - mPowerHintQueue.clear(); - // We save the actual duration here for rate limiting - mLastActualDurationSent = actualDuration; + actualDuration.ns(), mLastTargetDurationSent.ns(), + Duration{actualDuration - mLastTargetDurationSent}.ns()); + + auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue); + if (!ret.isOk()) { + ALOGW("Failed to report actual work durations with error: %s", + ret.exceptionMessage().c_str()); + mShouldReconnectHal = true; } + mPowerHintQueue.clear(); } bool AidlPowerHalWrapper::shouldReconnectHAL() { @@ -826,14 +800,10 @@ std::vector<int32_t> AidlPowerHalWrapper::getPowerHintSessionThreadIds() { return mPowerHintThreadIds; } -std::optional<int64_t> AidlPowerHalWrapper::getTargetWorkDuration() { +std::optional<Duration> AidlPowerHalWrapper::getTargetWorkDuration() { return mTargetDuration; } -void AidlPowerHalWrapper::setAllowedActualDeviation(nsecs_t allowedDeviation) { - mAllowedActualDeviation = allowedDeviation; -} - const bool AidlPowerHalWrapper::sTraceHintSessionData = base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false); @@ -844,7 +814,7 @@ PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { // Grab old hint session values before we destroy any existing wrapper std::vector<int32_t> oldPowerHintSessionThreadIds; - std::optional<int64_t> oldTargetWorkDuration; + std::optional<Duration> oldTargetWorkDuration; if (mHalWrapper != nullptr) { oldPowerHintSessionThreadIds = mHalWrapper->getPowerHintSessionThreadIds(); diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index 6e25f787d7..1c9d123a1f 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -27,6 +27,7 @@ #include <android/hardware/power/IPower.h> #include <compositionengine/impl/OutputCompositionState.h> +#include <scheduler/Time.h> #include <ui/DisplayIdentification.h> #include "../Scheduler/OneShotTimer.h" @@ -53,7 +54,7 @@ public: virtual bool supportsPowerHintSession() = 0; virtual bool isPowerHintSessionRunning() = 0; // Sends a power hint that updates to the target work duration for the frame - virtual void setTargetWorkDuration(nsecs_t targetDuration) = 0; + virtual void setTargetWorkDuration(Duration targetDuration) = 0; // Sends a power hint for the actual known work duration at the end of the frame virtual void sendActualWorkDuration() = 0; // Sends a power hint for the upcoming frame predicted from previous frame timing @@ -65,33 +66,33 @@ public: // Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0; // Reports the start and end times of a hwc validate call this frame for a given display - virtual void setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime, - nsecs_t validateEndTime) = 0; + virtual void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime, + TimePoint validateEndTime) = 0; // Reports the start and end times of a hwc present call this frame for a given display - virtual void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, - nsecs_t presentEndTime) = 0; + virtual void setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime, + TimePoint presentEndTime) = 0; // Reports the expected time that the current frame will present to the display - virtual void setExpectedPresentTime(nsecs_t expectedPresentTime) = 0; + virtual void setExpectedPresentTime(TimePoint expectedPresentTime) = 0; // Reports the most recent present fence time and end time once known - virtual void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) = 0; + virtual void setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) = 0; // Reports whether a display used client composition this frame virtual void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) = 0; // Reports whether a given display skipped validation this frame virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0; // Reports when a hwc present is delayed, and the time that it will resume - virtual void setHwcPresentDelayedTime( - DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) = 0; + virtual void setHwcPresentDelayedTime(DisplayId displayId, + TimePoint earliestFrameStartTime) = 0; // Reports the start delay for SurfaceFlinger this frame - virtual void setFrameDelay(nsecs_t frameDelayDuration) = 0; + virtual void setFrameDelay(Duration frameDelayDuration) = 0; // Reports the SurfaceFlinger commit start time this frame - virtual void setCommitStart(nsecs_t commitStartTime) = 0; + virtual void setCommitStart(TimePoint commitStartTime) = 0; // Reports the SurfaceFlinger composite end time this frame - virtual void setCompositeEnd(nsecs_t compositeEndTime) = 0; + virtual void setCompositeEnd(TimePoint compositeEndTime) = 0; // Reports the list of the currently active displays virtual void setDisplays(std::vector<DisplayId>& displayIds) = 0; // Sets the target duration for the entire pipeline including the gpu - virtual void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) = 0; + virtual void setTotalFrameTargetWorkDuration(Duration targetDuration) = 0; }; namespace impl { @@ -111,11 +112,11 @@ public: virtual void restartPowerHintSession() = 0; virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0; virtual bool startPowerHintSession() = 0; - virtual void setTargetWorkDuration(nsecs_t targetDuration) = 0; - virtual void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) = 0; + virtual void setTargetWorkDuration(Duration targetDuration) = 0; + virtual void sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) = 0; virtual bool shouldReconnectHAL() = 0; virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0; - virtual std::optional<nsecs_t> getTargetWorkDuration() = 0; + virtual std::optional<Duration> getTargetWorkDuration() = 0; }; PowerAdvisor(SurfaceFlinger& flinger); @@ -129,29 +130,27 @@ public: bool usePowerHintSession() override; bool supportsPowerHintSession() override; bool isPowerHintSessionRunning() override; - void setTargetWorkDuration(nsecs_t targetDuration) override; + void setTargetWorkDuration(Duration targetDuration) override; void sendActualWorkDuration() override; void sendPredictedWorkDuration() override; void enablePowerHint(bool enabled) override; bool startPowerHintSession(const std::vector<int32_t>& threadIds) override; void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime); - void setHwcValidateTiming(DisplayId displayId, nsecs_t valiateStartTime, - nsecs_t validateEndTime) override; - void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, - nsecs_t presentEndTime) override; + void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime, + TimePoint validateEndTime) override; + void setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime, + TimePoint presentEndTime) override; void setSkippedValidate(DisplayId displayId, bool skipped) override; void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override; - void setExpectedPresentTime(nsecs_t expectedPresentTime) override; - void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) override; - void setHwcPresentDelayedTime( - DisplayId displayId, - std::chrono::steady_clock::time_point earliestFrameStartTime) override; - - void setFrameDelay(nsecs_t frameDelayDuration) override; - void setCommitStart(nsecs_t commitStartTime) override; - void setCompositeEnd(nsecs_t compositeEndTime) override; + void setExpectedPresentTime(TimePoint expectedPresentTime) override; + void setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) override; + void setHwcPresentDelayedTime(DisplayId displayId, TimePoint earliestFrameStartTime) override; + + void setFrameDelay(Duration frameDelayDuration) override; + void setCommitStart(TimePoint commitStartTime) override; + void setCompositeEnd(TimePoint compositeEndTime) override; void setDisplays(std::vector<DisplayId>& displayIds) override; - void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) override; + void setTotalFrameTargetWorkDuration(Duration targetDuration) override; private: friend class PowerAdvisorTest; @@ -178,44 +177,45 @@ private: // Higher-level timing data used for estimation struct DisplayTimeline { // The start of hwc present, or the start of validate if it happened there instead - nsecs_t hwcPresentStartTime = -1; + TimePoint hwcPresentStartTime; // The end of hwc present or validate, whichever one actually presented - nsecs_t hwcPresentEndTime = -1; + TimePoint hwcPresentEndTime; // How long the actual hwc present was delayed after hwcPresentStartTime - nsecs_t hwcPresentDelayDuration = 0; + Duration hwcPresentDelayDuration{0ns}; // When we think we started waiting for the present fence after calling into hwc present and // after potentially waiting for the earliest present time - nsecs_t presentFenceWaitStartTime = -1; + TimePoint presentFenceWaitStartTime; // How long we ran after we finished waiting for the fence but before hwc present finished - nsecs_t postPresentFenceHwcPresentDuration = 0; + Duration postPresentFenceHwcPresentDuration{0ns}; // Are we likely to have waited for the present fence during composition bool probablyWaitsForPresentFence = false; // Estimate one frame's timeline from that of a previous frame - DisplayTimeline estimateTimelineFromReference(nsecs_t fenceTime, nsecs_t displayStartTime); + DisplayTimeline estimateTimelineFromReference(TimePoint fenceTime, + TimePoint displayStartTime); }; struct GpuTimeline { - nsecs_t duration = 0; - nsecs_t startTime = -1; + Duration duration{0ns}; + TimePoint startTime; }; // Power hint session data recorded from the pipeline struct DisplayTimingData { std::unique_ptr<FenceTime> gpuEndFenceTime; - std::optional<nsecs_t> gpuStartTime; - std::optional<nsecs_t> lastValidGpuEndTime; - std::optional<nsecs_t> lastValidGpuStartTime; - std::optional<nsecs_t> hwcPresentStartTime; - std::optional<nsecs_t> hwcPresentEndTime; - std::optional<nsecs_t> hwcValidateStartTime; - std::optional<nsecs_t> hwcValidateEndTime; - std::optional<nsecs_t> hwcPresentDelayedTime; + std::optional<TimePoint> gpuStartTime; + std::optional<TimePoint> lastValidGpuEndTime; + std::optional<TimePoint> lastValidGpuStartTime; + std::optional<TimePoint> hwcPresentStartTime; + std::optional<TimePoint> hwcPresentEndTime; + std::optional<TimePoint> hwcValidateStartTime; + std::optional<TimePoint> hwcValidateEndTime; + std::optional<TimePoint> hwcPresentDelayedTime; bool usedClientComposition = false; bool skippedValidate = false; // Calculate high-level timing milestones from more granular display timing data - DisplayTimeline calculateDisplayTimeline(nsecs_t fenceTime); + DisplayTimeline calculateDisplayTimeline(TimePoint fenceTime); // Estimate the gpu duration for a given display from previous gpu timing data - std::optional<GpuTimeline> estimateGpuTiming(std::optional<nsecs_t> previousEnd); + std::optional<GpuTimeline> estimateGpuTiming(std::optional<TimePoint> previousEndTime); }; template <class T, size_t N> @@ -240,30 +240,31 @@ private: }; // Filter and sort the display ids by a given property - std::vector<DisplayId> getOrderedDisplayIds(std::optional<nsecs_t> DisplayTimingData::*sortBy); + std::vector<DisplayId> getOrderedDisplayIds( + std::optional<TimePoint> DisplayTimingData::*sortBy); // Estimates a frame's total work duration including gpu time. // Runs either at the beginning or end of a frame, using the most recent data available - std::optional<nsecs_t> estimateWorkDuration(bool earlyHint); + std::optional<Duration> estimateWorkDuration(bool earlyHint); // There are two different targets and actual work durations we care about, // this normalizes them together and takes the max of the two - nsecs_t combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration); + Duration combineTimingEstimates(Duration totalDuration, Duration flingerDuration); std::unordered_map<DisplayId, DisplayTimingData> mDisplayTimingData; // Current frame's delay - nsecs_t mFrameDelayDuration = 0; + Duration mFrameDelayDuration{0ns}; // Last frame's post-composition duration - nsecs_t mLastPostcompDuration = 0; + Duration mLastPostcompDuration{0ns}; // Buffer of recent commit start times - RingBuffer<nsecs_t, 2> mCommitStartTimes; + RingBuffer<TimePoint, 2> mCommitStartTimes; // Buffer of recent expected present times - RingBuffer<nsecs_t, 2> mExpectedPresentTimes; - // Most recent present fence time, set at the end of the frame once known - nsecs_t mLastPresentFenceTime = -1; - // Most recent present fence time, set at the end of the frame once known - nsecs_t mLastSfPresentEndTime = -1; - // Target for the entire pipeline including gpu - std::optional<nsecs_t> mTotalFrameTargetDuration; + RingBuffer<TimePoint, 2> mExpectedPresentTimes; + // Most recent present fence time, provided by SF after composition engine finishes presenting + TimePoint mLastPresentFenceTime; + // Most recent composition engine present end time, returned with the present fence from SF + TimePoint mLastSfPresentEndTime; + // Target duration for the entire pipeline including gpu + std::optional<Duration> mTotalFrameTargetDuration; // Updated list of display IDs std::vector<DisplayId> mDisplayIds; @@ -273,11 +274,11 @@ private: // An adjustable safety margin which pads the "actual" value sent to PowerHAL, // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error - static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 1ms; + static constexpr const Duration kTargetSafetyMargin{1ms}; // How long we expect hwc to run after the present call until it waits for the fence - static constexpr const std::chrono::nanoseconds kFenceWaitStartDelayValidated = 150us; - static constexpr const std::chrono::nanoseconds kFenceWaitStartDelaySkippedValidate = 250us; + static constexpr const Duration kFenceWaitStartDelayValidated{150us}; + static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us}; }; class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper { @@ -294,21 +295,17 @@ public: void restartPowerHintSession() override; void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override; bool startPowerHintSession() override; - void setTargetWorkDuration(nsecs_t targetDuration) override; - void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) override; + void setTargetWorkDuration(Duration targetDuration) override; + void sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) override; bool shouldReconnectHAL() override; std::vector<int32_t> getPowerHintSessionThreadIds() override; - std::optional<nsecs_t> getTargetWorkDuration() override; + std::optional<Duration> getTargetWorkDuration() override; private: friend class AidlPowerHalWrapperTest; bool checkPowerHintSessionSupported(); void closePowerHintSession(); - bool shouldReportActualDurations(); - - // Used for testing - void setAllowedActualDeviation(nsecs_t); const sp<hardware::power::IPower> mPowerHal = nullptr; bool mHasExpensiveRendering = false; @@ -323,24 +320,15 @@ private: // Queue of actual durations saved to report std::vector<hardware::power::WorkDuration> mPowerHintQueue; // The latest values we have received for target and actual - nsecs_t mTargetDuration = kDefaultTarget.count(); - std::optional<nsecs_t> mActualDuration; + Duration mTargetDuration = kDefaultTargetDuration; + std::optional<Duration> mActualDuration; // The list of thread ids, stored so we can restart the session from this class if needed std::vector<int32_t> mPowerHintThreadIds; bool mSupportsPowerHint = false; - // Keep track of the last messages sent for rate limiter change detection - std::optional<nsecs_t> mLastActualDurationSent; - // Timestamp of the last report we sent, used to avoid stale sessions - nsecs_t mLastActualReportTimestamp = 0; - nsecs_t mLastTargetDurationSent = kDefaultTarget.count(); - // Max amount the error term can vary without causing an actual value report - nsecs_t mAllowedActualDeviation = -1; + Duration mLastTargetDurationSent = kDefaultTargetDuration; // Whether we should emit ATRACE_INT data for hint sessions static const bool sTraceHintSessionData; - static constexpr const std::chrono::nanoseconds kDefaultTarget = 16ms; - // Amount of time after the last message was sent before the session goes stale - // actually 100ms but we use 80 here to ideally avoid going stale - static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms; + static constexpr Duration kDefaultTargetDuration{16ms}; }; } // namespace impl diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp deleted file mode 100644 index e8c590e3c4..0000000000 --- a/services/surfaceflinger/EffectLayer.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -// #define LOG_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "EffectLayer" - -#include "EffectLayer.h" - -#include <stdint.h> -#include <stdlib.h> -#include <sys/types.h> - -#include <compositionengine/CompositionEngine.h> -#include <compositionengine/LayerFECompositionState.h> -#include <renderengine/RenderEngine.h> -#include <ui/GraphicBuffer.h> -#include <utils/Errors.h> -#include <utils/Log.h> - -#include "DisplayDevice.h" -#include "SurfaceFlinger.h" - -namespace android { -// --------------------------------------------------------------------------- - -EffectLayer::EffectLayer(const LayerCreationArgs& args) - : Layer(args), - mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {} - -EffectLayer::~EffectLayer() = default; - -std::vector<compositionengine::LayerFE::LayerSettings> EffectLayer::prepareClientCompositionList( - compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { - std::vector<compositionengine::LayerFE::LayerSettings> results; - std::optional<compositionengine::LayerFE::LayerSettings> layerSettings = - prepareClientComposition(targetSettings); - // Nothing to render. - if (!layerSettings) { - return {}; - } - - // set the shadow for the layer if needed - prepareShadowClientComposition(*layerSettings, targetSettings.viewport); - - // If fill bounds are occluded or the fill color is invalid skip the fill settings. - if (targetSettings.realContentIsVisible && fillsColor()) { - // Set color for color fill settings. - layerSettings->source.solidColor = getColor().rgb; - results.push_back(*layerSettings); - } else if (hasBlur() || drawShadows()) { - layerSettings->skipContentDraw = true; - results.push_back(*layerSettings); - } - - return results; -} - -bool EffectLayer::isVisible() const { - return !isHiddenByPolicy() && (getAlpha() > 0.0_hf || hasBlur()) && hasSomethingToDraw(); -} - -bool EffectLayer::setColor(const half3& color) { - if (mDrawingState.color.r == color.r && mDrawingState.color.g == color.g && - mDrawingState.color.b == color.b) { - return false; - } - - mDrawingState.sequence++; - mDrawingState.color.r = color.r; - mDrawingState.color.g = color.g; - mDrawingState.color.b = color.b; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool EffectLayer::setDataspace(ui::Dataspace dataspace) { - if (mDrawingState.dataspace == dataspace) { - return false; - } - - mDrawingState.sequence++; - mDrawingState.dataspace = dataspace; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -void EffectLayer::preparePerFrameCompositionState() { - Layer::preparePerFrameCompositionState(); - - auto* compositionState = editCompositionState(); - compositionState->color = getColor(); - compositionState->compositionType = - aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR; -} - -sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const { - // There's no need to get a CE Layer if the EffectLayer isn't going to draw anything. In that - // case, it acts more like a ContainerLayer so returning a null CE Layer makes more sense - if (hasSomethingToDraw()) { - return asLayerFE(); - } else { - return nullptr; - } -} - -compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() { - return mCompositionState.get(); -} - -const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const { - return mCompositionState.get(); -} - -bool EffectLayer::isOpaque(const Layer::State& s) const { - // Consider the layer to be opaque if its opaque flag is set or its effective - // alpha (considering the alpha of its parents as well) is 1.0; - return (s.flags & layer_state_t::eLayerOpaque) != 0 || (fillsColor() && getAlpha() == 1.0_hf); -} - -ui::Dataspace EffectLayer::getDataSpace() const { - return mDrawingState.dataspace; -} - -sp<Layer> EffectLayer::createClone() { - sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer( - LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata())); - layer->setInitialValuesForClone(this); - return layer; -} - -bool EffectLayer::fillsColor() const { - return mDrawingState.color.r >= 0.0_hf && mDrawingState.color.g >= 0.0_hf && - mDrawingState.color.b >= 0.0_hf; -} - -bool EffectLayer::hasBlur() const { - return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0; -} - -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h deleted file mode 100644 index 1dcb633251..0000000000 --- a/services/surfaceflinger/EffectLayer.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ -#pragma once - -#include <sys/types.h> - -#include <cstdint> - -#include "Layer.h" - -namespace android { - -// A layer that can render a combination of the following effects. -// * fill the bounds of the layer with a color -// * render a shadow cast by the bounds of the layer -// If no effects are enabled, the layer is considered to be invisible. -class EffectLayer : public Layer { -public: - explicit EffectLayer(const LayerCreationArgs&); - ~EffectLayer() override; - - sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override; - compositionengine::LayerFECompositionState* editCompositionState() override; - - const char* getType() const override { return "EffectLayer"; } - bool isVisible() const override; - - bool setColor(const half3& color) override; - - bool setDataspace(ui::Dataspace dataspace) override; - - ui::Dataspace getDataSpace() const override; - - bool isOpaque(const Layer::State& s) const override; - -protected: - /* - * compositionengine::LayerFE overrides - */ - const compositionengine::LayerFECompositionState* getCompositionState() const override; - void preparePerFrameCompositionState() override; - std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList( - compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) override; - - std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState; - - sp<Layer> createClone() override; - -private: - // Returns true if there is a valid color to fill. - bool fillsColor() const; - // Returns true if this layer has a blur value. - bool hasBlur() const; - bool hasSomethingToDraw() const { return fillsColor() || drawShadows() || hasBlur(); } -}; - -} // namespace android diff --git a/services/surfaceflinger/FpsReporter.cpp b/services/surfaceflinger/FpsReporter.cpp index e12835f0f6..155cf4da58 100644 --- a/services/surfaceflinger/FpsReporter.cpp +++ b/services/surfaceflinger/FpsReporter.cpp @@ -56,14 +56,15 @@ void FpsReporter::dispatchLayerFps() { mFlinger.mCurrentState.traverse([&](Layer* layer) { auto& currentState = layer->getDrawingState(); - if (currentState.metadata.has(METADATA_TASK_ID)) { - int32_t taskId = currentState.metadata.getInt32(METADATA_TASK_ID, 0); + if (currentState.metadata.has(gui::METADATA_TASK_ID)) { + int32_t taskId = currentState.metadata.getInt32(gui::METADATA_TASK_ID, 0); if (seenTasks.count(taskId) == 0) { // localListeners is expected to be tiny for (TrackedListener& listener : localListeners) { if (listener.taskId == taskId) { seenTasks.insert(taskId); - listenersAndLayersToReport.push_back({listener, sp<Layer>(layer)}); + listenersAndLayersToReport.push_back( + {listener, sp<Layer>::fromExisting(layer)}); break; } } @@ -90,7 +91,7 @@ void FpsReporter::binderDied(const wp<IBinder>& who) { void FpsReporter::addListener(const sp<gui::IFpsListener>& listener, int32_t taskId) { sp<IBinder> asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(this); + asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); std::lock_guard lock(mMutex); mListeners.emplace(wp<IBinder>(asBinder), TrackedListener{listener, taskId}); } diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 66beff2953..c73a75c756 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -109,11 +109,11 @@ std::string jankTypeBitmaskToString(int32_t jankType) { jankType &= ~JankType::DisplayHAL; } if (jankType & JankType::SurfaceFlingerCpuDeadlineMissed) { - janks.emplace_back("SurfaceFlinger CPU Deadline Missed"); + janks.emplace_back("SurfaceFlinger deadline missed (while in HWC)"); jankType &= ~JankType::SurfaceFlingerCpuDeadlineMissed; } if (jankType & JankType::SurfaceFlingerGpuDeadlineMissed) { - janks.emplace_back("SurfaceFlinger GPU Deadline Missed"); + janks.emplace_back("SurfaceFlinger deadline missed (while in GPU comp)"); jankType &= ~JankType::SurfaceFlingerGpuDeadlineMissed; } if (jankType & JankType::AppDeadlineMissed) { @@ -289,7 +289,7 @@ nsecs_t getMinTime(PredictionState predictionState, TimelineItem predictions, minTime = std::min(minTime, actuals.endTime); } if (actuals.presentTime != 0) { - minTime = std::min(minTime, actuals.endTime); + minTime = std::min(minTime, actuals.presentTime); } return minTime; } @@ -986,11 +986,8 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& mJankClassificationThresholds.presentThreshold) { // Classify CPU vs GPU if SF wasn't stuffed or if SF was stuffed but this frame // was presented more than a vsync late. - if (mGpuFence != FenceTime::NO_FENCE && - mSurfaceFlingerActuals.endTime - mSurfaceFlingerActuals.startTime < - mRefreshRate.getPeriodNsecs()) { - // If SF was in GPU composition and the CPU work finished before the vsync - // period, classify it as GPU deadline missed. + if (mGpuFence != FenceTime::NO_FENCE) { + // If SF was in GPU composition, classify it as GPU deadline missed. mJankType = JankType::SurfaceFlingerGpuDeadlineMissed; } else { mJankType = JankType::SurfaceFlingerCpuDeadlineMissed; diff --git a/services/surfaceflinger/HdrLayerInfoReporter.cpp b/services/surfaceflinger/HdrLayerInfoReporter.cpp index c06e300cdc..c88554ee52 100644 --- a/services/surfaceflinger/HdrLayerInfoReporter.cpp +++ b/services/surfaceflinger/HdrLayerInfoReporter.cpp @@ -51,7 +51,7 @@ void HdrLayerInfoReporter::binderDied(const wp<IBinder>& who) { void HdrLayerInfoReporter::addListener(const sp<gui::IHdrLayerInfoListener>& listener) { sp<IBinder> asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(this); + asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); std::lock_guard lock(mMutex); mListeners.emplace(wp<IBinder>(asBinder), TrackedListener{listener, HdrLayerInfo{}}); } diff --git a/services/surfaceflinger/HwcSlotGenerator.cpp b/services/surfaceflinger/HwcSlotGenerator.cpp new file mode 100644 index 0000000000..939c35b8b3 --- /dev/null +++ b/services/surfaceflinger/HwcSlotGenerator.cpp @@ -0,0 +1,106 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "HwcSlotGenerator" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <gui/BufferQueue.h> + +#include "HwcSlotGenerator.h" + +namespace android { + +HwcSlotGenerator::HwcSlotGenerator() { + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + mFreeHwcCacheSlots.push(i); + } +} + +void HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) { + std::lock_guard lock(mMutex); + if (!clientCacheId.isValid()) { + ALOGE("invalid process, failed to erase buffer"); + return; + } + eraseBufferLocked(clientCacheId); +} + +int HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) { + std::lock_guard<std::mutex> lock(mMutex); + auto itr = mCachedBuffers.find(clientCacheId); + if (itr == mCachedBuffers.end()) { + return addCachedBuffer(clientCacheId); + } + auto& [hwcCacheSlot, counter] = itr->second; + counter = mCounter++; + return hwcCacheSlot; +} + +int HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex) { + if (!clientCacheId.isValid()) { + ALOGE("invalid process, returning invalid slot"); + return BufferQueue::INVALID_BUFFER_SLOT; + } + + ClientCache::getInstance().registerErasedRecipient(clientCacheId, + wp<ErasedRecipient>::fromExisting(this)); + + int hwcCacheSlot = getFreeHwcCacheSlot(); + mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++}; + return hwcCacheSlot; +} + +int HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) { + if (mFreeHwcCacheSlots.empty()) { + evictLeastRecentlyUsed(); + } + + int hwcCacheSlot = mFreeHwcCacheSlots.top(); + mFreeHwcCacheSlots.pop(); + return hwcCacheSlot; +} + +void HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) { + uint64_t minCounter = UINT_MAX; + client_cache_t minClientCacheId = {}; + for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) { + const auto& [hwcCacheSlot, counter] = slotCounter; + if (counter < minCounter) { + minCounter = counter; + minClientCacheId = clientCacheId; + } + } + eraseBufferLocked(minClientCacheId); + + ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId, + wp<ErasedRecipient>::fromExisting(this)); +} + +void HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex) { + auto itr = mCachedBuffers.find(clientCacheId); + if (itr == mCachedBuffers.end()) { + return; + } + auto& [hwcCacheSlot, counter] = itr->second; + + // TODO send to hwc cache and resources + + mFreeHwcCacheSlots.push(hwcCacheSlot); + mCachedBuffers.erase(clientCacheId); +} + +} // namespace android diff --git a/services/surfaceflinger/HwcSlotGenerator.h b/services/surfaceflinger/HwcSlotGenerator.h new file mode 100644 index 0000000000..5a1b6d7d9d --- /dev/null +++ b/services/surfaceflinger/HwcSlotGenerator.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#pragma once + +#include <functional> +#include <mutex> +#include <stack> +#include <unordered_map> + +#include "ClientCache.h" + +namespace android { + +class HwcSlotGenerator : public ClientCache::ErasedRecipient { +public: + HwcSlotGenerator(); + void bufferErased(const client_cache_t& clientCacheId); + int getHwcCacheSlot(const client_cache_t& clientCacheId); + +private: + friend class SlotGenerationTest; + int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex); + int getFreeHwcCacheSlot() REQUIRES(mMutex); + void evictLeastRecentlyUsed() REQUIRES(mMutex); + void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex); + + struct CachedBufferHash { + std::size_t operator()(const client_cache_t& clientCacheId) const { + return std::hash<uint64_t>{}(clientCacheId.id); + } + }; + + std::mutex mMutex; + + std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>, + CachedBufferHash> + mCachedBuffers GUARDED_BY(mMutex); + std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex); + + // The cache increments this counter value when a slot is updated or used. + // Used to track the least recently-used buffer + uint64_t mCounter = 0; +}; +} // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0c4b012fe8..410e43846d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -29,6 +29,7 @@ #include <android-base/stringprintf.h> #include <android/native_window.h> #include <binder/IPCThreadState.h> +#include <compositionengine/CompositionEngine.h> #include <compositionengine/Display.h> #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/OutputLayer.h> @@ -39,8 +40,10 @@ #include <ftl/enum.h> #include <ftl/fake_guard.h> #include <gui/BufferItem.h> +#include <gui/GLConsumer.h> #include <gui/LayerDebugInfo.h> #include <gui/Surface.h> +#include <gui/TraceUtils.h> #include <math.h> #include <private/android_filesystem_config.h> #include <renderengine/RenderEngine.h> @@ -62,31 +65,89 @@ #include <mutex> #include <sstream> -#include "BufferLayer.h" -#include "Colorizer.h" #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" -#include "EffectLayer.h" #include "FrameTimeline.h" #include "FrameTracer/FrameTracer.h" #include "LayerProtoHelper.h" -#include "LayerRejecter.h" -#include "MonitoredProducer.h" #include "SurfaceFlinger.h" #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" #define DEBUG_RESIZE 0 +#define EARLY_RELEASE_ENABLED false namespace android { namespace { constexpr int kDumpTableRowLength = 159; + +static constexpr float defaultMaxLuminance = 1000.0; + const ui::Transform kIdentityTransform; + +constexpr mat4 inverseOrientation(uint32_t transform) { + const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); + const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + mat4 tr; + + if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + tr = tr * rot90; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { + tr = tr * flipH; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { + tr = tr * flipV; + } + return inverse(tr); +} + +bool assignTransform(ui::Transform* dst, ui::Transform& from) { + if (*dst == from) { + return false; + } + *dst = from; + return true; +} + +TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { + using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; + using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; + const auto frameRateCompatibility = [frameRate] { + switch (frameRate.type) { + case Layer::FrameRateCompatibility::Default: + return FrameRateCompatibility::Default; + case Layer::FrameRateCompatibility::ExactOrMultiple: + return FrameRateCompatibility::ExactOrMultiple; + default: + return FrameRateCompatibility::Undefined; + } + }(); + + const auto seamlessness = [frameRate] { + switch (frameRate.seamlessness) { + case scheduler::Seamlessness::OnlySeamless: + return Seamlessness::ShouldBeSeamless; + case scheduler::Seamlessness::SeamedAndSeamless: + return Seamlessness::NotRequired; + default: + return Seamlessness::Undefined; + } + }(); + + return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), + .frameRateCompatibility = frameRateCompatibility, + .seamlessness = seamlessness}; +} + } // namespace using namespace ftl::flag_operators; using base::StringAppendF; +using gui::GameMode; +using gui::LayerMetadata; using gui::WindowInfo; using PresentState = frametimeline::SurfaceFrame::PresentState; @@ -95,11 +156,17 @@ std::atomic<int32_t> Layer::sSequence{1}; Layer::Layer(const LayerCreationArgs& args) : sequence(args.sequence.value_or(sSequence++)), - mFlinger(args.flinger), + mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)), mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)), mClientRef(args.client), - mWindowType(static_cast<WindowInfo::Type>(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))), - mLayerCreationFlags(args.flags) { + mWindowType(static_cast<WindowInfo::Type>( + args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))), + mLayerCreationFlags(args.flags), + mBorderEnabled(false), + mTextureName(args.textureName), + mHwcSlotGenerator(sp<HwcSlotGenerator>::make()) { + ALOGV("Creating Layer %s", getDebugName()); + uint32_t layerFlags = 0; if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; @@ -110,16 +177,11 @@ Layer::Layer(const LayerCreationArgs& args) sSequence = *args.sequence + 1; } mDrawingState.flags = layerFlags; - mDrawingState.active_legacy.transform.set(0, 0); mDrawingState.crop.makeInvalid(); - mDrawingState.requestedCrop = mDrawingState.crop; mDrawingState.z = 0; mDrawingState.color.a = 1.0f; mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK; mDrawingState.sequence = 0; - mDrawingState.requested_legacy = mDrawingState.active_legacy; - mDrawingState.width = UINT32_MAX; - mDrawingState.height = UINT32_MAX; mDrawingState.transform.set(0, 0); mDrawingState.frameNumber = 0; mDrawingState.bufferTransform = 0; @@ -128,6 +190,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.acquireFence = sp<Fence>::make(-1); mDrawingState.acquireFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence); mDrawingState.dataspace = ui::Dataspace::UNKNOWN; + mDrawingState.dataspaceRequested = false; mDrawingState.hdrMetadata.validTypes = 0; mDrawingState.surfaceDamageRegion = Region::INVALID_REGION; mDrawingState.cornerRadius = 0.0f; @@ -145,6 +208,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.isTrustedOverlay = false; mDrawingState.dropInputMode = gui::DropInputMode::NONE; mDrawingState.dimmingEnabled = true; + mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -152,22 +216,33 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.color.g = -1.0_hf; mDrawingState.color.b = -1.0_hf; } - CompositorTiming compositorTiming; - args.flinger->getCompositorTiming(&compositorTiming); - mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval); + + mFrameTracker.setDisplayRefreshPeriod( + args.flinger->mScheduler->getVsyncPeriodFromRefreshRateConfigs()); mCallingPid = args.callingPid; mCallingUid = args.callingUid; if (mCallingUid == AID_GRAPHICS || mCallingUid == AID_SYSTEM) { // If the system didn't send an ownerUid, use the callingUid for the ownerUid. - mOwnerUid = args.metadata.getInt32(METADATA_OWNER_UID, mCallingUid); - mOwnerPid = args.metadata.getInt32(METADATA_OWNER_PID, mCallingPid); + mOwnerUid = args.metadata.getInt32(gui::METADATA_OWNER_UID, mCallingUid); + mOwnerPid = args.metadata.getInt32(gui::METADATA_OWNER_PID, mCallingPid); } else { // A create layer request from a non system request cannot specify the owner uid mOwnerUid = mCallingUid; mOwnerPid = mCallingPid; } + + mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); + mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; + mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp; + mDrawingState.dataspace = ui::Dataspace::V0_SRGB; + + mSnapshot->sequence = sequence; + mSnapshot->name = getDebugName(); + mSnapshot->textureName = mTextureName; + mSnapshot->premultipliedAlpha = mPremultipliedAlpha; + mSnapshot->transform = {}; } void Layer::onFirstRef() { @@ -175,6 +250,28 @@ void Layer::onFirstRef() { } Layer::~Layer() { + // The original layer and the clone layer share the same texture and buffer. Therefore, only + // one of the layers, in this case the original layer, needs to handle the deletion. The + // original layer and the clone should be removed at the same time so there shouldn't be any + // issue with the clone layer trying to use the texture. + if (mBufferInfo.mBuffer != nullptr) { + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber, + mBufferInfo.mFence, + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( + mOwnerUid)); + } + if (!isClone()) { + // The original layer and the clone layer share the same texture. Therefore, only one of + // the layers, in this case the original layer, needs to handle the deletion. The original + // layer and the clone should be removed at the same time so there shouldn't be any issue + // with the clone layer trying to use the deleted texture. + mFlinger->deleteTextureAsync(mTextureName); + } + const int32_t layerId = getSequence(); + mFlinger->mTimeStats->onDestroy(layerId); + mFlinger->mFrameTracer->onDestroy(layerId); + sp<Client> c(mClientRef.promote()); if (c != 0) { c->detachLayer(this); @@ -207,13 +304,6 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, // callbacks // --------------------------------------------------------------------------- -/* - * onLayerDisplayed is only meaningful for BufferLayer, but, is called through - * Layer. So, the implementation is done in BufferLayer. When called on a - * EffectLayer object, it's essentially a NOP. - */ -void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult>) {} - void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) { if (mDrawingState.zOrderRelativeOf == nullptr) { return; @@ -226,7 +316,7 @@ void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) { } if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) { - strongRelative->removeZOrderRelative(this); + strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this)); mFlinger->setTransactionFlags(eTraversalNeeded); setZOrderRelativeOf(nullptr); } @@ -238,13 +328,13 @@ void Layer::removeFromCurrentState() { mFlinger->mScheduler->deregisterLayer(this); } - mFlinger->markLayerPendingRemovalLocked(this); + mFlinger->markLayerPendingRemovalLocked(sp<Layer>::fromExisting(this)); } sp<Layer> Layer::getRootLayer() { sp<Layer> parent = getParent(); if (parent == nullptr) { - return this; + return sp<Layer>::fromExisting(this); } return parent->getRootLayer(); } @@ -287,7 +377,7 @@ sp<IBinder> Layer::getHandle() { return nullptr; } mGetHandleCalled = true; - return new Handle(mFlinger, this); + return sp<Handle>::make(mFlinger, sp<Layer>::fromExisting(this)); } // --------------------------------------------------------------------------- @@ -379,6 +469,10 @@ void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform, for (const sp<Layer>& child : mDrawingChildren) { child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius); } + + if (mPotentialCursor) { + prepareCursorCompositionState(); + } } Rect Layer::getCroppedBufferSize(const State& s) const { @@ -406,7 +500,7 @@ void Layer::prepareBasicGeometryCompositionState() { const auto& drawingState{getDrawingState()}; const auto alpha = static_cast<float>(getAlpha()); const bool opaque = isOpaque(drawingState); - const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; + const bool usesRoundedCorners = hasRoundedCorners(); auto blendMode = Hwc2::IComposerClient::BlendMode::NONE; if (!opaque || alpha != 1.0f) { @@ -414,40 +508,40 @@ void Layer::prepareBasicGeometryCompositionState() { : Hwc2::IComposerClient::BlendMode::COVERAGE; } - auto* compositionState = editCompositionState(); - compositionState->outputFilter = getOutputFilter(); - compositionState->isVisible = isVisible(); - compositionState->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f; - compositionState->shadowRadius = mEffectiveShadowRadius; + auto* snapshot = editLayerSnapshot(); + snapshot->outputFilter = getOutputFilter(); + snapshot->isVisible = isVisible(); + snapshot->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f; + snapshot->shadowRadius = mEffectiveShadowRadius; - compositionState->contentDirty = contentDirty; + snapshot->contentDirty = contentDirty; contentDirty = false; - compositionState->geomLayerBounds = mBounds; - compositionState->geomLayerTransform = getTransform(); - compositionState->geomInverseLayerTransform = compositionState->geomLayerTransform.inverse(); - compositionState->transparentRegionHint = getActiveTransparentRegion(drawingState); + snapshot->geomLayerBounds = mBounds; + snapshot->geomLayerTransform = getTransform(); + snapshot->geomInverseLayerTransform = snapshot->geomLayerTransform.inverse(); + snapshot->transparentRegionHint = getActiveTransparentRegion(drawingState); - compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode); - compositionState->alpha = alpha; - compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius; - compositionState->blurRegions = drawingState.blurRegions; - compositionState->stretchEffect = getStretchEffect(); + snapshot->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode); + snapshot->alpha = alpha; + snapshot->backgroundBlurRadius = drawingState.backgroundBlurRadius; + snapshot->blurRegions = drawingState.blurRegions; + snapshot->stretchEffect = getStretchEffect(); } void Layer::prepareGeometryCompositionState() { const auto& drawingState{getDrawingState()}; - auto* compositionState = editCompositionState(); + auto* snapshot = editLayerSnapshot(); - compositionState->geomBufferSize = getBufferSize(drawingState); - compositionState->geomContentCrop = getBufferCrop(); - compositionState->geomCrop = getCrop(drawingState); - compositionState->geomBufferTransform = getBufferTransform(); - compositionState->geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse(); - compositionState->geomUsesSourceCrop = usesSourceCrop(); - compositionState->isSecure = isSecure(); + snapshot->geomBufferSize = getBufferSize(drawingState); + snapshot->geomContentCrop = getBufferCrop(); + snapshot->geomCrop = getCrop(drawingState); + snapshot->geomBufferTransform = getBufferTransform(); + snapshot->geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse(); + snapshot->geomUsesSourceCrop = usesSourceCrop(); + snapshot->isSecure = isSecure(); - compositionState->metadata.clear(); + snapshot->metadata.clear(); const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata(); for (const auto& [key, mandatory] : supportedMetadata) { const auto& genericLayerMetadataCompatibilityMap = @@ -463,50 +557,90 @@ void Layer::prepareGeometryCompositionState() { continue; } - compositionState->metadata - .emplace(key, compositionengine::GenericLayerMetadataEntry{mandatory, it->second}); + snapshot->metadata.emplace(key, + compositionengine::GenericLayerMetadataEntry{mandatory, + it->second}); } } void Layer::preparePerFrameCompositionState() { const auto& drawingState{getDrawingState()}; - auto* compositionState = editCompositionState(); + auto* snapshot = editLayerSnapshot(); - compositionState->forceClientComposition = false; + snapshot->forceClientComposition = false; - compositionState->isColorspaceAgnostic = isColorSpaceAgnostic(); - compositionState->dataspace = getDataSpace(); - compositionState->colorTransform = getColorTransform(); - compositionState->colorTransformIsIdentity = !hasColorTransform(); - compositionState->surfaceDamage = surfaceDamageRegion; - compositionState->hasProtectedContent = isProtected(); - compositionState->dimmingEnabled = isDimmingEnabled(); + snapshot->isColorspaceAgnostic = isColorSpaceAgnostic(); + snapshot->dataspace = getDataSpace(); + snapshot->colorTransform = getColorTransform(); + snapshot->colorTransformIsIdentity = !hasColorTransform(); + snapshot->surfaceDamage = surfaceDamageRegion; + snapshot->hasProtectedContent = isProtected(); + snapshot->dimmingEnabled = isDimmingEnabled(); - const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; + const bool usesRoundedCorners = hasRoundedCorners(); - compositionState->isOpaque = - isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf; + snapshot->isOpaque = isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf; // Force client composition for special cases known only to the front-end. // Rounded corners no longer force client composition, since we may use a // hole punch so that the layer will appear to have rounded corners. if (isHdrY410() || drawShadows() || drawingState.blurRegions.size() > 0 || - compositionState->stretchEffect.hasEffect()) { - compositionState->forceClientComposition = true; + snapshot->stretchEffect.hasEffect()) { + snapshot->forceClientComposition = true; } // If there are no visible region changes, we still need to update blur parameters. - compositionState->blurRegions = drawingState.blurRegions; - compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius; + snapshot->blurRegions = drawingState.blurRegions; + snapshot->backgroundBlurRadius = drawingState.backgroundBlurRadius; // Layer framerate is used in caching decisions. // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in // LayerFECompositionState where it would be visible to Flattener. - compositionState->fps = mFlinger->getLayerFramerate(systemTime(), getSequence()); + snapshot->fps = mFlinger->getLayerFramerate(systemTime(), getSequence()); + + if (hasBufferOrSidebandStream()) { + preparePerFrameBufferCompositionState(); + } else { + preparePerFrameEffectsCompositionState(); + } +} + +void Layer::preparePerFrameBufferCompositionState() { + // Sideband layers + auto* snapshot = editLayerSnapshot(); + if (snapshot->sidebandStream.get() && !snapshot->sidebandStreamHasFrame) { + snapshot->compositionType = + aidl::android::hardware::graphics::composer3::Composition::SIDEBAND; + return; + } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) { + snapshot->compositionType = + aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION; + } else { + // Normal buffer layers + snapshot->hdrMetadata = mBufferInfo.mHdrMetadata; + snapshot->compositionType = mPotentialCursor + ? aidl::android::hardware::graphics::composer3::Composition::CURSOR + : aidl::android::hardware::graphics::composer3::Composition::DEVICE; + } + + snapshot->buffer = getBuffer(); + snapshot->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) + ? 0 + : mBufferInfo.mBufferSlot; + snapshot->acquireFence = mBufferInfo.mFence; + snapshot->frameNumber = mBufferInfo.mFrameNumber; + snapshot->sidebandStreamHasFrame = false; +} + +void Layer::preparePerFrameEffectsCompositionState() { + auto* snapshot = editLayerSnapshot(); + snapshot->color = getColor(); + snapshot->compositionType = + aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR; } void Layer::prepareCursorCompositionState() { const State& drawingState{getDrawingState()}; - auto* compositionState = editCompositionState(); + auto* snapshot = editLayerSnapshot(); // Apply the layer's transform, followed by the display's global transform // Here we're guaranteed that the layer's transform preserves rects @@ -515,52 +649,13 @@ void Layer::prepareCursorCompositionState() { Rect bounds = reduce(win, getActiveTransparentRegion(drawingState)); Rect frame(getTransform().transform(bounds)); - compositionState->cursorFrame = frame; + snapshot->cursorFrame = frame; } sp<compositionengine::LayerFE> Layer::asLayerFE() const { - return const_cast<compositionengine::LayerFE*>( + compositionengine::LayerFE* layerFE = const_cast<compositionengine::LayerFE*>( static_cast<const compositionengine::LayerFE*>(this)); -} - -sp<compositionengine::LayerFE> Layer::getCompositionEngineLayerFE() const { - return nullptr; -} - -compositionengine::LayerFECompositionState* Layer::editCompositionState() { - return nullptr; -} - -const compositionengine::LayerFECompositionState* Layer::getCompositionState() const { - return nullptr; -} - -bool Layer::onPreComposition(nsecs_t) { - return false; -} - -void Layer::prepareCompositionState(compositionengine::LayerFE::StateSubset subset) { - using StateSubset = compositionengine::LayerFE::StateSubset; - - switch (subset) { - case StateSubset::BasicGeometry: - prepareBasicGeometryCompositionState(); - break; - - case StateSubset::GeometryAndContent: - prepareBasicGeometryCompositionState(); - prepareGeometryCompositionState(); - preparePerFrameCompositionState(); - break; - - case StateSubset::Content: - preparePerFrameCompositionState(); - break; - - case StateSubset::Cursor: - prepareCursorCompositionState(); - break; - } + return sp<compositionengine::LayerFE>::fromExisting(layerFE); } const char* Layer::getDebugName() const { @@ -572,32 +667,54 @@ const char* Layer::getDebugName() const { // --------------------------------------------------------------------------- std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { - if (!getCompositionState()) { + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const { + std::optional<compositionengine::LayerFE::LayerSettings> layerSettings = + prepareClientCompositionInternal(targetSettings); + // Nothing to render. + if (!layerSettings) { return {}; } - FloatRect bounds = getBounds(); - half alpha = getAlpha(); + // HWC requests to clear this layer. + if (targetSettings.clearContent) { + prepareClearClientComposition(*layerSettings, false /* blackout */); + return layerSettings; + } + + // set the shadow for the layer if needed + prepareShadowClientComposition(*layerSettings, targetSettings.viewport); + + return layerSettings; +} + +std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionInternal( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const { + ATRACE_CALL(); + + const auto* snapshot = getLayerSnapshot(); + if (!snapshot) { + return {}; + } compositionengine::LayerFE::LayerSettings layerSettings; - layerSettings.geometry.boundaries = bounds; - layerSettings.geometry.positionTransform = getTransform().asMatrix4(); + layerSettings.geometry.boundaries = + reduce(snapshot->geomLayerBounds, snapshot->transparentRegionHint); + layerSettings.geometry.positionTransform = snapshot->geomLayerTransform.asMatrix4(); // skip drawing content if the targetSettings indicate the content will be occluded const bool drawContent = targetSettings.realContentIsVisible || targetSettings.clearContent; layerSettings.skipContentDraw = !drawContent; if (hasColorTransform()) { - layerSettings.colorTransform = getColorTransform(); + layerSettings.colorTransform = snapshot->colorTransform; } - const auto roundedCornerState = getRoundedCornerState(); + const auto& roundedCornerState = snapshot->roundedCorner; layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius; layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect; - layerSettings.alpha = alpha; - layerSettings.sourceDataspace = getDataSpace(); + layerSettings.alpha = snapshot->alpha; + layerSettings.sourceDataspace = snapshot->dataspace; // Override the dataspace transfer from 170M to sRGB if the device configuration requests this. // We do this here instead of in buffer info so that dumpsys can still report layers that are @@ -614,26 +731,31 @@ std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCom layerSettings.whitePointNits = targetSettings.whitePointNits; switch (targetSettings.blurSetting) { case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled: - layerSettings.backgroundBlurRadius = getBackgroundBlurRadius(); - layerSettings.blurRegions = getBlurRegions(); - layerSettings.blurRegionTransform = - getActiveTransform(getDrawingState()).inverse().asMatrix4(); + layerSettings.backgroundBlurRadius = snapshot->backgroundBlurRadius; + layerSettings.blurRegions = snapshot->blurRegions; + layerSettings.blurRegionTransform = snapshot->geomInverseLayerTransform.asMatrix4(); break; case LayerFE::ClientCompositionTargetSettings::BlurSetting::BackgroundBlurOnly: - layerSettings.backgroundBlurRadius = getBackgroundBlurRadius(); + layerSettings.backgroundBlurRadius = snapshot->backgroundBlurRadius; break; case LayerFE::ClientCompositionTargetSettings::BlurSetting::BlurRegionsOnly: - layerSettings.blurRegions = getBlurRegions(); - layerSettings.blurRegionTransform = - getActiveTransform(getDrawingState()).inverse().asMatrix4(); + layerSettings.blurRegions = snapshot->blurRegions; + layerSettings.blurRegionTransform = snapshot->geomInverseLayerTransform.asMatrix4(); break; case LayerFE::ClientCompositionTargetSettings::BlurSetting::Disabled: default: break; } - layerSettings.stretchEffect = getStretchEffect(); + layerSettings.stretchEffect = snapshot->stretchEffect; // Record the name of the layer for debugging further down the stack. - layerSettings.name = getName(); + layerSettings.name = snapshot->name; + + if (hasEffect() && !hasBufferOrSidebandStream()) { + prepareEffectsClientComposition(layerSettings, targetSettings); + return layerSettings; + } + + prepareBufferStateClientComposition(layerSettings, targetSettings); return layerSettings; } @@ -647,31 +769,132 @@ void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, // If layer is blacked out, force alpha to 1 so that we draw a black color layer. layerSettings.alpha = blackout ? 1.0f : 0.0f; - layerSettings.name = getName(); + layerSettings.name = getLayerSnapshot()->name; } -// TODO(b/188891810): This method now only ever returns 0 or 1 layers so we should return -// std::optional instead of a vector. Additionally, we should consider removing -// this method entirely in favor of calling prepareClientComposition directly. -std::vector<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionList( - compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { - std::optional<compositionengine::LayerFE::LayerSettings> layerSettings = - prepareClientComposition(targetSettings); - // Nothing to render. - if (!layerSettings) { - return {}; +void Layer::prepareEffectsClientComposition( + compositionengine::LayerFE::LayerSettings& layerSettings, + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const { + // If fill bounds are occluded or the fill color is invalid skip the fill settings. + if (targetSettings.realContentIsVisible && fillsColor()) { + // Set color for color fill settings. + layerSettings.source.solidColor = getColor().rgb; + } else if (hasBlur() || drawShadows()) { + layerSettings.skipContentDraw = true; } +} - // HWC requests to clear this layer. - if (targetSettings.clearContent) { - prepareClearClientComposition(*layerSettings, false /* blackout */); - return {*layerSettings}; +void Layer::prepareBufferStateClientComposition( + compositionengine::LayerFE::LayerSettings& layerSettings, + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const { + ATRACE_CALL(); + const auto* snapshot = getLayerSnapshot(); + if (CC_UNLIKELY(!snapshot->externalTexture)) { + // If there is no buffer for the layer or we have sidebandstream where there is no + // activeBuffer, then we need to return LayerSettings. + return; + } + const bool blackOutLayer = + (snapshot->hasProtectedContent && !targetSettings.supportsProtectedContent) || + ((snapshot->isSecure || snapshot->hasProtectedContent) && !targetSettings.isSecure); + const bool bufferCanBeUsedAsHwTexture = + snapshot->externalTexture->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; + if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { + ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", + snapshot->name.c_str()); + prepareClearClientComposition(layerSettings, true /* blackout */); + return; } - // set the shadow for the layer if needed - prepareShadowClientComposition(*layerSettings, targetSettings.viewport); + layerSettings.source.buffer.buffer = snapshot->externalTexture; + layerSettings.source.buffer.isOpaque = snapshot->contentOpaque; + layerSettings.source.buffer.fence = snapshot->acquireFence; + layerSettings.source.buffer.textureName = snapshot->textureName; + layerSettings.source.buffer.usePremultipliedAlpha = snapshot->premultipliedAlpha; + layerSettings.source.buffer.isY410BT2020 = snapshot->isHdrY410; + bool hasSmpte2086 = snapshot->hdrMetadata.validTypes & HdrMetadata::SMPTE2086; + bool hasCta861_3 = snapshot->hdrMetadata.validTypes & HdrMetadata::CTA861_3; + float maxLuminance = 0.f; + if (hasSmpte2086 && hasCta861_3) { + maxLuminance = std::min(snapshot->hdrMetadata.smpte2086.maxLuminance, + snapshot->hdrMetadata.cta8613.maxContentLightLevel); + } else if (hasSmpte2086) { + maxLuminance = snapshot->hdrMetadata.smpte2086.maxLuminance; + } else if (hasCta861_3) { + maxLuminance = snapshot->hdrMetadata.cta8613.maxContentLightLevel; + } else { + switch (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + case HAL_DATASPACE_TRANSFER_HLG: + // Behavior-match previous releases for HDR content + maxLuminance = defaultMaxLuminance; + break; + } + } + layerSettings.source.buffer.maxLuminanceNits = maxLuminance; + layerSettings.frameNumber = snapshot->frameNumber; + layerSettings.bufferId = snapshot->externalTexture->getId(); + + const bool useFiltering = targetSettings.needsFiltering || + snapshot->geomLayerTransform.needsBilinearFiltering() || snapshot->bufferNeedsFiltering; + + // Query the texture matrix given our current filtering mode. + float textureMatrix[16]; + getDrawingTransformMatrix(useFiltering, textureMatrix); + + if (snapshot->geomBufferUsesDisplayInverseTransform) { + /* + * the code below applies the primary display's inverse transform to + * the texture transform + */ + uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags(); + mat4 tr = inverseOrientation(transform); + + /** + * TODO(b/36727915): This is basically a hack. + * + * Ensure that regardless of the parent transformation, + * this buffer is always transformed from native display + * orientation to display orientation. For example, in the case + * of a camera where the buffer remains in native orientation, + * we want the pixels to always be upright. + */ + const auto parentTransform = snapshot->transform; + tr = tr * inverseOrientation(parentTransform.getOrientation()); + + // and finally apply it to the original texture matrix + const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr); + memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); + } - return {*layerSettings}; + const Rect win{layerSettings.geometry.boundaries}; + float bufferWidth = snapshot->bufferSize.getWidth(); + float bufferHeight = snapshot->bufferSize.getHeight(); + + // Layers can have a "buffer size" of [0, 0, -1, -1] when no display frame has + // been set and there is no parent layer bounds. In that case, the scale is meaningless so + // ignore them. + if (!snapshot->bufferSize.isValid()) { + bufferWidth = float(win.right) - float(win.left); + bufferHeight = float(win.bottom) - float(win.top); + } + + const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; + const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; + const float translateY = float(win.top) / bufferHeight; + const float translateX = float(win.left) / bufferWidth; + + // Flip y-coordinates because GLConsumer expects OpenGL convention. + mat4 tr = mat4::translate(vec4(.5f, .5f, 0.f, 1.f)) * mat4::scale(vec4(1.f, -1.f, 1.f, 1.f)) * + mat4::translate(vec4(-.5f, -.5f, 0.f, 1.f)) * + mat4::translate(vec4(translateX, translateY, 0.f, 1.f)) * + mat4::scale(vec4(scaleWidth, scaleHeight, 1.0f, 1.0f)); + + layerSettings.source.buffer.useTextureFiltering = useFiltering; + layerSettings.source.buffer.textureTransform = + mat4(static_cast<const float*>(textureMatrix)) * tr; + + return; } aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionType( @@ -721,7 +944,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { if (s.sequence != mLastCommittedTxSequence) { // invalidate and recompute the visible regions if needed - mLastCommittedTxSequence = s.sequence; + mLastCommittedTxSequence = s.sequence; flags |= eVisibleRegion; this->contentDirty = true; @@ -729,6 +952,10 @@ uint32_t Layer::doTransaction(uint32_t flags) { mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering(); } + if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) { + mFlinger->mUpdateInputInfo = true; + } + commitTransaction(mDrawingState); return flags; @@ -758,16 +985,6 @@ void Layer::setTransactionFlags(uint32_t mask) { mTransactionFlags |= mask; } -bool Layer::setPosition(float x, float y) { - if (mDrawingState.transform.tx() == x && mDrawingState.transform.ty() == y) return false; - mDrawingState.sequence++; - mDrawingState.transform.set(x, y); - - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - bool Layer::setChildLayer(const sp<Layer>& childLayer, int32_t z) { ssize_t idx = mCurrentChildren.indexOf(childLayer); if (idx < 0) { @@ -807,7 +1024,7 @@ bool Layer::setLayer(int32_t z) { if (mDrawingState.zOrderRelativeOf != nullptr) { sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote(); if (strongRelative != nullptr) { - strongRelative->removeZOrderRelative(this); + strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this)); } setZOrderRelativeOf(nullptr); } @@ -865,10 +1082,10 @@ bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relati auto oldZOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote(); if (oldZOrderRelativeOf != nullptr) { - oldZOrderRelativeOf->removeZOrderRelative(this); + oldZOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this)); } setZOrderRelativeOf(relative); - relative->addZOrderRelative(this); + relative->addZOrderRelative(wp<Layer>::fromExisting(this)); setTransactionFlags(eTransactionNeeded); @@ -879,7 +1096,7 @@ bool Layer::setTrustedOverlay(bool isTrustedOverlay) { if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false; mDrawingState.isTrustedOverlay = isTrustedOverlay; mDrawingState.modified = true; - mFlinger->mInputInfoChanged = true; + mFlinger->mUpdateInputInfo = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -892,20 +1109,6 @@ bool Layer::isTrustedOverlay() const { return (p != nullptr) && p->isTrustedOverlay(); } -bool Layer::setSize(uint32_t w, uint32_t h) { - if (mDrawingState.requested_legacy.w == w && mDrawingState.requested_legacy.h == h) - return false; - mDrawingState.requested_legacy.w = w; - mDrawingState.requested_legacy.h = h; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - - // record the new size, from this point on, when the client request - // a buffer, it'll get the new size. - setDefaultBufferSize(mDrawingState.requested_legacy.w, mDrawingState.requested_legacy.h); - return true; -} - bool Layer::setAlpha(float alpha) { if (mDrawingState.color.a == alpha) return false; mDrawingState.sequence++; @@ -975,20 +1178,10 @@ bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) { setTransactionFlags(eTransactionNeeded); return true; } -bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) { - ui::Transform t; - t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - - mDrawingState.sequence++; - mDrawingState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - mDrawingState.modified = true; - - setTransactionFlags(eTransactionNeeded); - return true; -} bool Layer::setTransparentRegionHint(const Region& transparent) { - mDrawingState.requestedTransparentRegion_legacy = transparent; + mDrawingState.sequence++; + mDrawingState.transparentRegionHint = transparent; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; @@ -1017,9 +1210,8 @@ bool Layer::setFlags(uint32_t flags, uint32_t mask) { } bool Layer::setCrop(const Rect& crop) { - if (mDrawingState.requestedCrop == crop) return false; + if (mDrawingState.crop == crop) return false; mDrawingState.sequence++; - mDrawingState.requestedCrop = crop; mDrawingState.crop = crop; mDrawingState.modified = true; @@ -1087,6 +1279,19 @@ int32_t Layer::getFrameRateSelectionPriority() const { return Layer::PRIORITY_UNSET; } +bool Layer::setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility) { + if (mDrawingState.defaultFrameRateCompatibility == compatibility) return false; + mDrawingState.defaultFrameRateCompatibility = compatibility; + mDrawingState.modified = true; + mFlinger->mScheduler->setDefaultFrameRateCompatibility(this); + setTransactionFlags(eTransactionNeeded); + return true; +} + +scheduler::LayerInfo::FrameRateCompatibility Layer::getDefaultFrameRateCompatibility() const { + return mDrawingState.defaultFrameRateCompatibility; +} + bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE; }; @@ -1151,6 +1356,28 @@ StretchEffect Layer::getStretchEffect() const { return StretchEffect{}; } +bool Layer::enableBorder(bool shouldEnable, float width, const half4& color) { + if (mBorderEnabled == shouldEnable && mBorderWidth == width && mBorderColor == color) { + return false; + } + mBorderEnabled = shouldEnable; + mBorderWidth = width; + mBorderColor = color; + return true; +} + +bool Layer::isBorderEnabled() { + return mBorderEnabled; +} + +float Layer::getBorderWidth() { + return mBorderWidth; +} + +const half4& Layer::getBorderColor() { + return mBorderColor; +} + bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) { // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate const auto frameRate = [&] { @@ -1193,7 +1420,7 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* tran void Layer::updateTreeHasFrameRateVote() { const auto root = [&]() -> sp<Layer> { - sp<Layer> layer = this; + sp<Layer> layer = sp<Layer>::fromExisting(this); while (auto parent = layer->getParent()) { layer = parent; } @@ -1399,16 +1626,15 @@ void Layer::updateTransformHint(ui::Transform::RotationFlags transformHint) { // ---------------------------------------------------------------------------- // TODO(marissaw): add new layer state info to layer debugging -LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { +gui::LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { using namespace std::string_literals; - LayerDebugInfo info; + gui::LayerDebugInfo info; const State& ds = getDrawingState(); info.mName = getName(); sp<Layer> parent = mDrawingParent.promote(); info.mParentName = parent ? parent->getName() : "none"s; info.mType = getType(); - info.mTransparentRegion = ds.activeTransparentRegion_legacy; info.mVisibleRegion = getVisibleRegion(display); info.mSurfaceDamageRegion = surfaceDamageRegion; @@ -1416,8 +1642,6 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { info.mX = ds.transform.tx(); info.mY = ds.transform.ty(); info.mZ = ds.z; - info.mWidth = ds.width; - info.mHeight = ds.height; info.mCrop = ds.crop; info.mColor = ds.color; info.mFlags = ds.flags; @@ -1551,8 +1775,9 @@ size_t Layer::getChildrenCount() const { void Layer::setGameModeForTree(GameMode gameMode) { const auto& currentState = getDrawingState(); - if (currentState.metadata.has(METADATA_GAME_MODE)) { - gameMode = static_cast<GameMode>(currentState.metadata.getInt32(METADATA_GAME_MODE, 0)); + if (currentState.metadata.has(gui::METADATA_GAME_MODE)) { + gameMode = + static_cast<GameMode>(currentState.metadata.getInt32(gui::METADATA_GAME_MODE, 0)); } setGameMode(gameMode); for (const sp<Layer>& child : mCurrentChildren) { @@ -1565,7 +1790,7 @@ void Layer::addChild(const sp<Layer>& layer) { setTransactionFlags(eTransactionNeeded); mCurrentChildren.add(layer); - layer->setParent(this); + layer->setParent(sp<Layer>::fromExisting(this)); layer->setGameModeForTree(mGameMode); updateTreeHasFrameRateVote(); } @@ -1610,11 +1835,11 @@ bool Layer::reparent(const sp<IBinder>& newParentHandle) { sp<Layer> parent = getParent(); if (parent != nullptr) { - parent->removeChild(this); + parent->removeChild(sp<Layer>::fromExisting(this)); } if (newParentHandle != nullptr) { - newParent->addChild(this); + newParent->addChild(sp<Layer>::fromExisting(this)); if (!newParent->isRemovedFromCurrentState()) { addToCurrentState(); } else { @@ -1896,8 +2121,11 @@ half4 Layer::getColor() const { } int32_t Layer::getBackgroundBlurRadius() const { - const auto& p = mDrawingParent.promote(); + if (getDrawingState().backgroundBlurRadius == 0) { + return 0; + } + const auto& p = mDrawingParent.promote(); half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; return parentAlpha * getDrawingState().backgroundBlurRadius; } @@ -1917,27 +2145,22 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { const auto& parent = mDrawingParent.promote(); if (parent != nullptr) { parentSettings = parent->getRoundedCornerState(); - if (parentSettings.radius > 0) { + if (parentSettings.hasRoundedCorners()) { ui::Transform t = getActiveTransform(getDrawingState()); t = t.inverse(); parentSettings.cropRect = t.transform(parentSettings.cropRect); - // The rounded corners shader only accepts 1 corner radius for performance reasons, - // but a transform matrix can define horizontal and vertical scales. - // Let's take the average between both of them and pass into the shader, practically we - // never do this type of transformation on windows anyway. - auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]); - auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]); - parentSettings.radius *= (scaleX + scaleY) / 2.0f; + parentSettings.radius.x *= t.getScaleX(); + parentSettings.radius.y *= t.getScaleY(); } } // Get layer settings Rect layerCropRect = getCroppedBufferSize(getDrawingState()); - const float radius = getDrawingState().cornerRadius; + const vec2 radius(getDrawingState().cornerRadius, getDrawingState().cornerRadius); RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius); - const bool layerSettingsValid = layerSettings.radius > 0 && layerCropRect.isValid(); + const bool layerSettingsValid = layerSettings.hasRoundedCorners() && layerCropRect.isValid(); - if (layerSettingsValid && parentSettings.radius > 0) { + if (layerSettingsValid && parentSettings.hasRoundedCorners()) { // If the parent and the layer have rounded corner settings, use the parent settings if the // parent crop is entirely inside the layer crop. // This has limitations and cause rendering artifacts. See b/200300845 for correct fix. @@ -1951,43 +2174,25 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { } } else if (layerSettingsValid) { return layerSettings; - } else if (parentSettings.radius > 0) { + } else if (parentSettings.hasRoundedCorners()) { return parentSettings; } return {}; } void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster, - const Rect& layerStackRect) { - renderengine::ShadowSettings state = mFlinger->mDrawingState.globalShadowSettings; - - // Note: this preserves existing behavior of shadowing the entire layer and not cropping it if - // transparent regions are present. This may not be necessary since shadows are only cast by - // SurfaceFlinger's EffectLayers, which do not typically use transparent regions. - state.boundaries = mBounds; + const Rect& layerStackRect) const { + const auto* snapshot = getLayerSnapshot(); + renderengine::ShadowSettings state = snapshot->shadowSettings; + if (state.length <= 0.f || (state.ambientColor.a <= 0.f && state.spotColor.a <= 0.f)) { + return; + } // Shift the spot light x-position to the middle of the display and then // offset it by casting layer's screen pos. - state.lightPos.x = (layerStackRect.width() / 2.f) - mScreenBounds.left; - state.lightPos.y -= mScreenBounds.top; - - state.length = mEffectiveShadowRadius; - - if (state.length > 0.f) { - const float casterAlpha = caster.alpha; - const bool casterIsOpaque = - ((caster.source.buffer.buffer != nullptr) && caster.source.buffer.isOpaque); - - // If the casting layer is translucent, we need to fill in the shadow underneath the layer. - // Otherwise the generated shadow will only be shown around the casting layer. - state.casterIsTranslucent = !casterIsOpaque || (casterAlpha < 1.0f); - state.ambientColor *= casterAlpha; - state.spotColor *= casterAlpha; - - if (state.ambientColor.a > 0.f && state.spotColor.a > 0.f) { - caster.shadow = state; - } - } + state.lightPos.x = (layerStackRect.width() / 2.f) - snapshot->transformedBounds.left; + state.lightPos.y -= snapshot->transformedBounds.top; + caster.shadow = state; } bool Layer::findInHierarchy(const sp<Layer>& l) { @@ -2017,7 +2222,7 @@ void Layer::commitChildList() { zOrderRelativeOf->mName.c_str()); ALOGE("Severing rel Z loop, potentially dangerous"); mDrawingState.isRelativeOf = false; - zOrderRelativeOf->removeZOrderRelative(this); + zOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this)); } } } @@ -2027,7 +2232,7 @@ void Layer::setInputInfo(const WindowInfo& info) { mDrawingState.inputInfo = info; mDrawingState.touchableRegionCrop = fromHandle(info.touchableRegionCropHandle.promote()); mDrawingState.modified = true; - mFlinger->mInputInfoChanged = true; + mFlinger->mUpdateInputInfo = true; setTransactionFlags(eTransactionNeeded); } @@ -2069,10 +2274,9 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo) { layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace()))); layerInfo->set_queued_frames(getQueuedFrameCount()); layerInfo->set_curr_frame(mCurrentFrameNumber); - layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); - layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); - layerInfo->set_corner_radius(getRoundedCornerState().radius); + layerInfo->set_corner_radius( + (getRoundedCornerState().radius.x + getRoundedCornerState().radius.y) / 2.0); layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); layerInfo->set_is_trusted_overlay(isTrustedOverlay()); LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); @@ -2118,7 +2322,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet } } - LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, + LayerProtoHelper::writeToProto(state.transparentRegionHint, [&]() { return layerInfo->mutable_transparent_region(); }); layerInfo->set_layer_stack(getLayerStack().id); @@ -2128,9 +2332,6 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet return layerInfo->mutable_requested_position(); }); - LayerProtoHelper::writeSizeToProto(state.width, state.height, - [&]() { return layerInfo->mutable_size(); }); - LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); }); layerInfo->set_is_opaque(isOpaque(state)); @@ -2190,14 +2391,6 @@ bool Layer::isRemovedFromCurrentState() const { return mRemovedFromDrawingState; } -ui::Transform Layer::getInputTransform() const { - return getTransform(); -} - -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. @@ -2296,7 +2489,7 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDi } void Layer::fillTouchOcclusionMode(WindowInfo& info) { - sp<Layer> p = this; + sp<Layer> p = sp<Layer>::fromExisting(this); while (p != nullptr && !p->hasInputInfo()) { p = p->mDrawingParent.promote(); } @@ -2436,7 +2629,7 @@ WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) { // 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; + info.inputConfig |= WindowInfo::InputConfig::CLONE; if (const sp<Layer> clonedRoot = getClonedRoot()) { const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds}); info.touchableRegion = info.touchableRegion.intersect(rect); @@ -2448,7 +2641,7 @@ WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) { sp<Layer> Layer::getClonedRoot() { if (mClonedChild != nullptr) { - return this; + return sp<Layer>::fromExisting(this); } if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) { return nullptr; @@ -2461,10 +2654,6 @@ bool Layer::hasInputInfo() const { mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); } -bool Layer::canReceiveInput() const { - return !isHiddenByPolicy(); -} - compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( const DisplayDevice* display) const { if (!display) return nullptr; @@ -2479,6 +2668,40 @@ Region Layer::getVisibleRegion(const DisplayDevice* display) const { void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom) { cloneDrawingState(clonedFrom.get()); mClonedFrom = clonedFrom; + mPremultipliedAlpha = clonedFrom->mPremultipliedAlpha; + mPotentialCursor = clonedFrom->mPotentialCursor; + mProtectedByApp = clonedFrom->mProtectedByApp; + updateCloneBufferInfo(); +} + +void Layer::updateCloneBufferInfo() { + if (!isClone() || !isClonedFromAlive()) { + return; + } + + sp<Layer> clonedFrom = getClonedFrom(); + mBufferInfo = clonedFrom->mBufferInfo; + mSidebandStream = clonedFrom->mSidebandStream; + surfaceDamageRegion = clonedFrom->surfaceDamageRegion; + mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load(); + mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber; + + // After buffer info is updated, the drawingState from the real layer needs to be copied into + // the cloned. This is because some properties of drawingState can change when latchBuffer is + // called. However, copying the drawingState would also overwrite the cloned layer's relatives + // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in + // the cloned drawingState again. + wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf; + SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives; + wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop; + WindowInfo tmpInputInfo = mDrawingState.inputInfo; + + cloneDrawingState(clonedFrom.get()); + + mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop; + mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf; + mDrawingState.zOrderRelatives = tmpZOrderRelatives; + mDrawingState.inputInfo = tmpInputInfo; } void Layer::updateMirrorInfo() { @@ -2502,7 +2725,7 @@ void Layer::updateMirrorInfo() { } mClonedChild->updateClonedDrawingState(clonedLayersMap); - mClonedChild->updateClonedChildren(this, clonedLayersMap); + mClonedChild->updateClonedChildren(sp<Layer>::fromExisting(this), clonedLayersMap); mClonedChild->updateClonedRelatives(clonedLayersMap); } @@ -2513,7 +2736,7 @@ void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayer if (isClonedFromAlive()) { sp<Layer> clonedFrom = getClonedFrom(); cloneDrawingState(clonedFrom.get()); - clonedLayersMap.emplace(clonedFrom, this); + clonedLayersMap.emplace(clonedFrom, sp<Layer>::fromExisting(this)); } // The clone layer may have children in drawingState since they may have been created and @@ -2557,7 +2780,7 @@ void Layer::updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLa if (clonedLayersMap.count(cropLayer) == 0) { // Real layer had a crop layer but it's not in the cloned hierarchy. Just set to // self as crop layer to avoid going outside bounds. - mDrawingState.touchableRegionCrop = this; + mDrawingState.touchableRegionCrop = wp<Layer>::fromExisting(this); } else { const sp<Layer>& clonedCropLayer = clonedLayersMap.at(cropLayer); mDrawingState.touchableRegionCrop = clonedCropLayer; @@ -2569,7 +2792,7 @@ void Layer::updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLa } void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) { - mDrawingState.zOrderRelativeOf = nullptr; + mDrawingState.zOrderRelativeOf = wp<Layer>(); mDrawingState.zOrderRelatives.clear(); if (!isClonedFromAlive()) { @@ -2605,7 +2828,7 @@ void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLa void Layer::addChildToDrawing(const sp<Layer>& layer) { mDrawingChildren.add(layer); - layer->mDrawingParent = this; + layer->mDrawingParent = sp<Layer>::fromExisting(this); } Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) { @@ -2616,6 +2839,8 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp return FrameRateCompatibility::ExactOrMultiple; case ANATIVEWINDOW_FRAME_RATE_EXACT: return FrameRateCompatibility::Exact; + case ANATIVEWINDOW_FRAME_RATE_MIN: + return FrameRateCompatibility::Min; case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: return FrameRateCompatibility::NoVote; default: @@ -2665,7 +2890,7 @@ wp<Layer> Layer::fromHandle(const sp<IBinder>& handleBinder) { } // We can safely cast this binder since its local and we verified its interface descriptor. - sp<Handle> handle = static_cast<Handle*>(handleBinder.get()); + sp<Handle> handle = sp<Handle>::cast(handleBinder); return handle->owner; } @@ -2684,18 +2909,1375 @@ void Layer::cloneDrawingState(const Layer* from) { mDrawingState.callbackHandles = {}; } +void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, + const sp<GraphicBuffer>& buffer, uint64_t framenumber, + const sp<Fence>& releaseFence, + uint32_t currentMaxAcquiredBufferCount) { + if (!listener) { + return; + } + ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); + listener->onReleaseBuffer({buffer->getId(), framenumber}, + releaseFence ? releaseFence : Fence::NO_FENCE, + currentMaxAcquiredBufferCount); +} + +void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) { + // If we are displayed on multiple displays in a single composition cycle then we would + // need to do careful tracking to enable the use of the mLastClientCompositionFence. + // 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 (mClearClientCompositionFenceOnLayerDisplayed) { + mLastClientCompositionFence = nullptr; + } else { + mClearClientCompositionFenceOnLayerDisplayed = true; + } + + // The previous release fence notifies the client that SurfaceFlinger is done with the previous + // buffer that was presented on this layer. The first transaction that came in this frame that + // replaced the previous buffer on this layer needs this release fence, because the fence will + // let the client know when that previous buffer is removed from the screen. + // + // Every other transaction on this layer does not need a release fence because no other + // Transactions that were set on this layer this frame are going to have their preceding buffer + // removed from the display this frame. + // + // For example, if we have 3 transactions this frame. The first transaction doesn't contain a + // buffer so it doesn't need a previous release fence because the layer still needs the previous + // buffer. The second transaction contains a buffer so it needs a previous release fence because + // the previous buffer will be released this frame. The third transaction also contains a + // buffer. It replaces the buffer in the second transaction. The buffer in the second + // transaction will now no longer be presented so it is released immediately and the third + // transaction doesn't need a previous release fence. + sp<CallbackHandle> ch; + for (auto& handle : mDrawingState.callbackHandles) { + if (handle->releasePreviousBuffer && + mDrawingState.releaseBufferEndpoint == handle->listener) { + ch = handle; + break; + } + } + + // Prevent tracing the same release multiple times. + if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { + mPreviousReleasedFrameNumber = mPreviousFrameNumber; + } + + if (ch != nullptr) { + ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; + ch->previousReleaseFences.emplace_back(std::move(futureFenceResult)); + ch->name = mName; + } +} + +void Layer::onSurfaceFrameCreated( + const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) { + while (mPendingJankClassifications.size() >= kPendingClassificationMaxSurfaceFrames) { + // Too many SurfaceFrames pending classification. The front of the deque is probably not + // tracked by FrameTimeline and will never be presented. This will only result in a memory + // leak. + ALOGW("Removing the front of pending jank deque from layer - %s to prevent memory leak", + mName.c_str()); + std::string miniDump = mPendingJankClassifications.front()->miniDump(); + ALOGD("Head SurfaceFrame mini dump\n%s", miniDump.c_str()); + mPendingJankClassifications.pop_front(); + } + mPendingJankClassifications.emplace_back(surfaceFrame); +} + +void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { + for (const auto& handle : mDrawingState.callbackHandles) { + handle->transformHint = mTransformHint; + handle->dequeueReadyTime = dequeueReadyTime; + handle->currentMaxAcquiredBufferCount = + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); + ATRACE_FORMAT_INSTANT("releasePendingBuffer %s - %" PRIu64, getDebugName(), + handle->previousReleaseCallbackId.framenumber); + } + + for (auto& handle : mDrawingState.callbackHandles) { + if (handle->releasePreviousBuffer && + mDrawingState.releaseBufferEndpoint == handle->listener) { + handle->previousReleaseCallbackId = mPreviousReleaseCallbackId; + break; + } + } + + std::vector<JankData> jankData; + jankData.reserve(mPendingJankClassifications.size()); + while (!mPendingJankClassifications.empty() && + mPendingJankClassifications.front()->getJankType()) { + std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame = + mPendingJankClassifications.front(); + mPendingJankClassifications.pop_front(); + jankData.emplace_back( + JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value())); + } + + mFlinger->getTransactionCallbackInvoker().addCallbackHandles(mDrawingState.callbackHandles, + jankData); + mDrawingState.callbackHandles = {}; +} + +bool Layer::willPresentCurrentTransaction() const { + // Returns true if the most recent Transaction applied to CurrentState will be presented. + return (getSidebandStreamChanged() || getAutoRefresh() || + (mDrawingState.modified && + (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr))); +} + +bool Layer::setTransform(uint32_t transform) { + if (mDrawingState.bufferTransform == transform) return false; + mDrawingState.bufferTransform = transform; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setTransformToDisplayInverse(bool transformToDisplayInverse) { + if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false; + mDrawingState.sequence++; + mDrawingState.transformToDisplayInverse = transformToDisplayInverse; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setBufferCrop(const Rect& bufferCrop) { + if (mDrawingState.bufferCrop == bufferCrop) return false; + + mDrawingState.sequence++; + mDrawingState.bufferCrop = bufferCrop; + + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setDestinationFrame(const Rect& destinationFrame) { + if (mDrawingState.destinationFrame == destinationFrame) return false; + + mDrawingState.sequence++; + mDrawingState.destinationFrame = destinationFrame; + + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +// Translate destination frame into scale and position. If a destination frame is not set, use the +// provided scale and position +bool Layer::updateGeometry() { + if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) || + mDrawingState.destinationFrame.isEmpty()) { + // If destination frame is not set, use the requested transform set via + // Layer::setPosition and Layer::setMatrix. + return assignTransform(&mDrawingState.transform, mRequestedTransform); + } + + Rect destRect = mDrawingState.destinationFrame; + int32_t destW = destRect.width(); + int32_t destH = destRect.height(); + if (destRect.left < 0) { + destRect.left = 0; + destRect.right = destW; + } + if (destRect.top < 0) { + destRect.top = 0; + destRect.bottom = destH; + } + + if (!mDrawingState.buffer) { + ui::Transform t; + t.set(destRect.left, destRect.top); + return assignTransform(&mDrawingState.transform, t); + } + + uint32_t bufferWidth = mDrawingState.buffer->getWidth(); + uint32_t bufferHeight = mDrawingState.buffer->getHeight(); + // Undo any transformations on the buffer. + if (mDrawingState.bufferTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); + if (mDrawingState.transformToDisplayInverse) { + if (invTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + } + + float sx = destW / static_cast<float>(bufferWidth); + float sy = destH / static_cast<float>(bufferHeight); + ui::Transform t; + t.set(sx, 0, 0, sy); + t.set(destRect.left, destRect.top); + return assignTransform(&mDrawingState.transform, t); +} + +bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) { + if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy && + mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) { + return false; + } + + mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); + + mDrawingState.sequence++; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + + return true; +} + +bool Layer::setPosition(float x, float y) { + if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) { + return false; + } + + mRequestedTransform.set(x, y); + + mDrawingState.sequence++; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + + return true; +} + +bool Layer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer, + const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, + bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime, + const FrameTimelineInfo& info) { + ATRACE_FORMAT("setBuffer %s - hasBuffer=%s", getDebugName(), (buffer ? "true" : "false")); + if (!buffer) { + return false; + } + + const bool frameNumberChanged = + bufferData.flags.test(BufferData::BufferDataChange::frameNumberChanged); + const uint64_t frameNumber = + frameNumberChanged ? bufferData.frameNumber : mDrawingState.frameNumber + 1; + ATRACE_FORMAT_INSTANT("setBuffer %s - %" PRIu64, getDebugName(), frameNumber); + + if (mDrawingState.buffer) { + mReleasePreviousBuffer = true; + if (!mBufferInfo.mBuffer || + (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) || + mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) { + // If mDrawingState has a buffer, and we are about to update again + // before swapping to drawing state, then the first buffer will be + // dropped and we should decrement the pending buffer count and + // call any release buffer callbacks if set. + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, + mDrawingState.acquireFence, + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( + mOwnerUid)); + decrementPendingBufferCount(); + if (mDrawingState.bufferSurfaceFrameTX != nullptr && + mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) { + addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX); + mDrawingState.bufferSurfaceFrameTX.reset(); + } + } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) { + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, + mLastClientCompositionFence, + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( + mOwnerUid)); + mLastClientCompositionFence = nullptr; + } + } + + mDrawingState.frameNumber = frameNumber; + mDrawingState.releaseBufferListener = bufferData.releaseBufferListener; + mDrawingState.buffer = std::move(buffer); + mDrawingState.clientCacheId = bufferData.cachedBuffer; + + mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) + ? bufferData.acquireFence + : Fence::NO_FENCE; + mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(mDrawingState.acquireFence); + if (mDrawingState.acquireFenceTime->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { + // We latched this buffer unsiganled, so we need to pass the acquire fence + // on the callback instead of just the acquire time, since it's unknown at + // this point. + mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFence; + } else { + mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime(); + } + + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + + const int32_t layerId = getSequence(); + mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(), + mOwnerUid, postTime, getGameMode()); + mDrawingState.desiredPresentTime = desiredPresentTime; + mDrawingState.isAutoTimestamp = isAutoTimestamp; + + const nsecs_t presentTime = [&] { + if (!isAutoTimestamp) return desiredPresentTime; + + const auto prediction = + mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(info.vsyncId); + if (prediction.has_value()) return prediction->presentTime; + + return static_cast<nsecs_t>(0); + }(); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); + + setFrameTimelineVsyncForBufferTransaction(info, postTime); + + if (dequeueTime && *dequeueTime != 0) { + const uint64_t bufferId = mDrawingState.buffer->getId(); + mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); + mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime, + FrameTracer::FrameEvent::DEQUEUE); + mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime, + FrameTracer::FrameEvent::QUEUE); + } + + mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint; + return true; +} + +bool Layer::setDataspace(ui::Dataspace dataspace) { + mDrawingState.dataspaceRequested = true; + if (mDrawingState.dataspace == dataspace) return false; + mDrawingState.dataspace = dataspace; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) { + if (mDrawingState.hdrMetadata == hdrMetadata) return false; + mDrawingState.hdrMetadata = hdrMetadata; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setSurfaceDamageRegion(const Region& surfaceDamage) { + mDrawingState.surfaceDamageRegion = surfaceDamage; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setApi(int32_t api) { + if (mDrawingState.api == api) return false; + mDrawingState.api = api; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setSidebandStream(const sp<NativeHandle>& sidebandStream) { + if (mDrawingState.sidebandStream == sidebandStream) return false; + + if (mDrawingState.sidebandStream != nullptr && sidebandStream == nullptr) { + mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); + } else if (sidebandStream != nullptr) { + mFlinger->mTunnelModeEnabledReporter->incrementTunnelModeCount(); + } + + mDrawingState.sidebandStream = sidebandStream; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + if (!mSidebandStreamChanged.exchange(true)) { + // mSidebandStreamChanged was false + mFlinger->onLayerUpdate(); + } + return true; +} + bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) { + // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return if (handles.empty()) { + mReleasePreviousBuffer = false; return false; } + const bool willPresent = willPresentCurrentTransaction(); + for (const auto& handle : handles) { - mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle); + // If this transaction set a buffer on this layer, release its previous buffer + handle->releasePreviousBuffer = mReleasePreviousBuffer; + + // If this layer will be presented in this frame + if (willPresent) { + // If this transaction set an acquire fence on this layer, set its acquire time + handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence; + handle->frameNumber = mDrawingState.frameNumber; + + // Store so latched time and release fence can be set + mDrawingState.callbackHandles.push_back(handle); + + } else { // If this layer will NOT need to be relatched and presented this frame + // Notify the transaction completed thread this handle is done + mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle); + } + } + + mReleasePreviousBuffer = false; + mCallbackHandleAcquireTimeOrFence = -1; + + return willPresent; +} + +Rect Layer::getBufferSize(const State& /*s*/) const { + // for buffer state layers we use the display frame size as the buffer size. + + if (mBufferInfo.mBuffer == nullptr) { + return Rect::INVALID_RECT; + } + + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + + // Undo any transformations on the buffer and return the result. + if (mBufferInfo.mTransform & ui::Transform::ROT_90) { + std::swap(bufWidth, bufHeight); + } + + if (getTransformToDisplayInverse()) { + uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); + if (invTransform & ui::Transform::ROT_90) { + std::swap(bufWidth, bufHeight); + } + } + + return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight)); +} + +FloatRect Layer::computeSourceBounds(const FloatRect& parentBounds) const { + if (mBufferInfo.mBuffer == nullptr) { + return parentBounds; + } + + return getBufferSize(getDrawingState()).toFloatRect(); +} + +bool Layer::fenceHasSignaled() const { + if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { + return true; + } + + const bool fenceSignaled = + getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled; + if (!fenceSignaled) { + mFlinger->mTimeStats->incrementLatchSkipped(getSequence(), + TimeStats::LatchSkipReason::LateAcquire); + } + + return fenceSignaled; +} + +bool Layer::onPreComposition(nsecs_t refreshStartTime, bool /* updatingOutputGeometryThisFrame */) { + for (const auto& handle : mDrawingState.callbackHandles) { + handle->refreshStartTime = refreshStartTime; + } + return hasReadyFrame(); +} + +void Layer::setAutoRefresh(bool autoRefresh) { + mDrawingState.autoRefresh = autoRefresh; +} + +bool Layer::latchSidebandStream(bool& recomputeVisibleRegions) { + // We need to update the sideband stream if the layer has both a buffer and a sideband stream. + auto* snapshot = editLayerSnapshot(); + snapshot->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get(); + + if (mSidebandStreamChanged.exchange(false)) { + const State& s(getDrawingState()); + // mSidebandStreamChanged was true + mSidebandStream = s.sidebandStream; + snapshot->sidebandStream = mSidebandStream; + if (mSidebandStream != nullptr) { + setTransactionFlags(eTransactionNeeded); + mFlinger->setTransactionFlags(eTraversalNeeded); + } + recomputeVisibleRegions = true; + + return true; + } + return false; +} + +bool Layer::hasFrameUpdate() const { + const State& c(getDrawingState()); + return (mDrawingStateModified || mDrawingState.modified) && + (c.buffer != nullptr || c.bgColorLayer != nullptr); +} + +void Layer::updateTexImage(nsecs_t latchTime) { + const State& s(getDrawingState()); + + if (!s.buffer) { + if (s.bgColorLayer) { + for (auto& handle : mDrawingState.callbackHandles) { + handle->latchTime = latchTime; + } + } + return; + } + + for (auto& handle : mDrawingState.callbackHandles) { + if (handle->frameNumber == mDrawingState.frameNumber) { + handle->latchTime = latchTime; + } + } + + const int32_t layerId = getSequence(); + const uint64_t bufferId = mDrawingState.buffer->getId(); + const uint64_t frameNumber = mDrawingState.frameNumber; + const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence); + mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence); + mFlinger->mTimeStats->setLatchTime(layerId, frameNumber, latchTime); + + mFlinger->mFrameTracer->traceFence(layerId, bufferId, frameNumber, acquireFence, + FrameTracer::FrameEvent::ACQUIRE_FENCE); + mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, latchTime, + FrameTracer::FrameEvent::LATCH); + + auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX; + if (bufferSurfaceFrame != nullptr && + bufferSurfaceFrame->getPresentState() != PresentState::Presented) { + // Update only if the bufferSurfaceFrame wasn't already presented. A Presented + // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we + // are processing the next state. + addSurfaceFramePresentedForBuffer(bufferSurfaceFrame, + mDrawingState.acquireFenceTime->getSignalTime(), + latchTime); + mDrawingState.bufferSurfaceFrameTX.reset(); + } + + std::deque<sp<CallbackHandle>> remainingHandles; + mFlinger->getTransactionCallbackInvoker() + .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles); + mDrawingState.callbackHandles = remainingHandles; + + mDrawingStateModified = false; +} + +void Layer::gatherBufferInfo() { + if (!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) { + decrementPendingBufferCount(); + } + + mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber}; + mBufferInfo.mBuffer = mDrawingState.buffer; + mBufferInfo.mFence = mDrawingState.acquireFence; + mBufferInfo.mFrameNumber = mDrawingState.frameNumber; + mBufferInfo.mPixelFormat = + !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat(); + mBufferInfo.mFrameLatencyNeeded = true; + mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime; + mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence); + mBufferInfo.mFence = mDrawingState.acquireFence; + mBufferInfo.mTransform = mDrawingState.bufferTransform; + auto lastDataspace = mBufferInfo.mDataspace; + mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace); + if (lastDataspace != mBufferInfo.mDataspace) { + mFlinger->mSomeDataspaceChanged = true; + } + mBufferInfo.mCrop = computeBufferCrop(mDrawingState); + mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion; + mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata; + mBufferInfo.mApi = mDrawingState.api; + mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse; + mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(mDrawingState.clientCacheId); +} + +Rect Layer::computeBufferCrop(const State& s) { + if (s.buffer && !s.bufferCrop.isEmpty()) { + Rect bufferCrop; + s.buffer->getBounds().intersect(s.bufferCrop, &bufferCrop); + return bufferCrop; + } else if (s.buffer) { + return s.buffer->getBounds(); + } else { + return s.bufferCrop; + } +} + +sp<Layer> Layer::createClone() { + LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); + args.textureName = mTextureName; + sp<Layer> layer = mFlinger->getFactory().createBufferStateLayer(args); + layer->mHwcSlotGenerator = mHwcSlotGenerator; + layer->setInitialValuesForClone(sp<Layer>::fromExisting(this)); + return layer; +} + +bool Layer::bufferNeedsFiltering() const { + const State& s(getDrawingState()); + if (!s.buffer) { + return false; + } + + int32_t bufferWidth = static_cast<int32_t>(s.buffer->getWidth()); + int32_t bufferHeight = static_cast<int32_t>(s.buffer->getHeight()); + + // Undo any transformations on the buffer and return the result. + if (s.bufferTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + + if (s.transformToDisplayInverse) { + uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); + if (invTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + } + + const Rect layerSize{getBounds()}; + int32_t layerWidth = layerSize.getWidth(); + int32_t layerHeight = layerSize.getHeight(); + + // Align the layer orientation with the buffer before comparism + if (mTransformHint & ui::Transform::ROT_90) { + std::swap(layerWidth, layerHeight); + } + + return layerWidth != bufferWidth || layerHeight != bufferHeight; +} + +void Layer::decrementPendingBufferCount() { + int32_t pendingBuffers = --mPendingBufferTransactions; + tracePendingBufferCount(pendingBuffers); +} + +void Layer::tracePendingBufferCount(int32_t pendingBuffers) { + ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); +} + +/* + * We don't want to send the layer's transform to input, but rather the + * parent's transform. This is because Layer's transform is + * information about how the buffer is placed on screen. The parent's + * transform makes more sense to send since it's information about how the + * layer is placed on screen. This transform is used by input to determine + * how to go from screen space back to window space. + */ +ui::Transform Layer::getInputTransform() const { + if (!hasBufferOrSidebandStream()) { + return getTransform(); + } + sp<Layer> parent = mDrawingParent.promote(); + if (parent == nullptr) { + return ui::Transform(); + } + + return parent->getTransform(); +} + +/** + * Similar to getInputTransform, we need to update the bounds to include the transform. + * This is because bounds don't include the buffer transform, where the input assumes + * that's already included. + */ +Rect Layer::getInputBounds() const { + if (!hasBufferOrSidebandStream()) { + return getCroppedBufferSize(getDrawingState()); + } + + Rect bufferBounds = getCroppedBufferSize(getDrawingState()); + if (mDrawingState.transform.getType() == ui::Transform::IDENTITY || !bufferBounds.isValid()) { + return bufferBounds; + } + return mDrawingState.transform.transform(bufferBounds); +} + +bool Layer::simpleBufferUpdate(const layer_state_t& s) const { + const uint64_t requiredFlags = layer_state_t::eBufferChanged; + + const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged | + layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged | + layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged | + layer_state_t::eLayerStackChanged | layer_state_t::eAutoRefreshChanged | + layer_state_t::eReparent; + + const uint64_t allowedFlags = layer_state_t::eHasListenerCallbacksChanged | + layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFrameRateChanged | + layer_state_t::eSurfaceDamageRegionChanged | layer_state_t::eApiChanged | + layer_state_t::eMetadataChanged | layer_state_t::eDropInputModeChanged | + layer_state_t::eInputInfoChanged; + + if ((s.what & requiredFlags) != requiredFlags) { + ALOGV("%s: false [missing required flags 0x%" PRIx64 "]", __func__, + (s.what | requiredFlags) & ~s.what); + return false; + } + + if (s.what & deniedFlags) { + ALOGV("%s: false [has denied flags 0x%" PRIx64 "]", __func__, s.what & deniedFlags); + return false; } + if (s.what & allowedFlags) { + ALOGV("%s: [has allowed flags 0x%" PRIx64 "]", __func__, s.what & allowedFlags); + } + + if (s.what & layer_state_t::ePositionChanged) { + if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) { + ALOGV("%s: false [ePositionChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eAlphaChanged) { + if (mDrawingState.color.a != s.alpha) { + ALOGV("%s: false [eAlphaChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eColorTransformChanged) { + if (mDrawingState.colorTransform != s.colorTransform) { + ALOGV("%s: false [eColorTransformChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eBackgroundColorChanged) { + if (mDrawingState.bgColorLayer || s.bgColorAlpha != 0) { + ALOGV("%s: false [eBackgroundColorChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eMatrixChanged) { + if (mRequestedTransform.dsdx() != s.matrix.dsdx || + mRequestedTransform.dtdy() != s.matrix.dtdy || + mRequestedTransform.dtdx() != s.matrix.dtdx || + mRequestedTransform.dsdy() != s.matrix.dsdy) { + ALOGV("%s: false [eMatrixChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eCornerRadiusChanged) { + if (mDrawingState.cornerRadius != s.cornerRadius) { + ALOGV("%s: false [eCornerRadiusChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) { + if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) { + ALOGV("%s: false [eBackgroundBlurRadiusChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eTransformChanged) { + if (mDrawingState.bufferTransform != s.transform) { + ALOGV("%s: false [eTransformChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eTransformToDisplayInverseChanged) { + if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) { + ALOGV("%s: false [eTransformToDisplayInverseChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eCropChanged) { + if (mDrawingState.crop != s.crop) { + ALOGV("%s: false [eCropChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eDataspaceChanged) { + if (mDrawingState.dataspace != s.dataspace) { + ALOGV("%s: false [eDataspaceChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eHdrMetadataChanged) { + if (mDrawingState.hdrMetadata != s.hdrMetadata) { + ALOGV("%s: false [eHdrMetadataChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eSidebandStreamChanged) { + if (mDrawingState.sidebandStream != s.sidebandStream) { + ALOGV("%s: false [eSidebandStreamChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eColorSpaceAgnosticChanged) { + if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) { + ALOGV("%s: false [eColorSpaceAgnosticChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eShadowRadiusChanged) { + if (mDrawingState.shadowRadius != s.shadowRadius) { + ALOGV("%s: false [eShadowRadiusChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eFixedTransformHintChanged) { + if (mDrawingState.fixedTransformHint != s.fixedTransformHint) { + ALOGV("%s: false [eFixedTransformHintChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eTrustedOverlayChanged) { + if (mDrawingState.isTrustedOverlay != s.isTrustedOverlay) { + ALOGV("%s: false [eTrustedOverlayChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eStretchChanged) { + StretchEffect temp = s.stretchEffect; + temp.sanitize(); + if (mDrawingState.stretchEffect != temp) { + ALOGV("%s: false [eStretchChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eBufferCropChanged) { + if (mDrawingState.bufferCrop != s.bufferCrop) { + ALOGV("%s: false [eBufferCropChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eDestinationFrameChanged) { + if (mDrawingState.destinationFrame != s.destinationFrame) { + ALOGV("%s: false [eDestinationFrameChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eDimmingEnabledChanged) { + if (mDrawingState.dimmingEnabled != s.dimmingEnabled) { + ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__); + return false; + } + } + + ALOGV("%s: true", __func__); return true; } +bool Layer::isHdrY410() const { + // pixel format is HDR Y410 masquerading as RGBA_1010102 + return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ && + mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA && + mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102); +} + +sp<compositionengine::LayerFE> Layer::getCompositionEngineLayerFE() const { + // There's no need to get a CE Layer if the layer isn't going to draw anything. + if (hasSomethingToDraw()) { + return asLayerFE(); + } else { + return nullptr; + } +} + +const Layer::LayerSnapshot* Layer::getLayerSnapshot() const { + return mSnapshot.get(); +} + +Layer::LayerSnapshot* Layer::editLayerSnapshot() { + return mSnapshot.get(); +} +const compositionengine::LayerFECompositionState* Layer::getCompositionState() const { + return mSnapshot.get(); +} + +void Layer::useSurfaceDamage() { + if (mFlinger->mForceFullDamage) { + surfaceDamageRegion = Region::INVALID_REGION; + } else { + surfaceDamageRegion = mBufferInfo.mSurfaceDamage; + } +} + +void Layer::useEmptyDamage() { + surfaceDamageRegion.clear(); +} + +bool Layer::isOpaque(const Layer::State& s) const { + // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the + // layer's opaque flag. + if (!hasSomethingToDraw()) { + return false; + } + + // if the layer has the opaque flag, then we're always opaque + if ((s.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque) { + return true; + } + + // If the buffer has no alpha channel, then we are opaque + if (hasBufferOrSidebandStream() && isOpaqueFormat(getPixelFormat())) { + return true; + } + + // Lastly consider the layer opaque if drawing a color with alpha == 1.0 + return fillsColor() && getAlpha() == 1.0_hf; +} + +bool Layer::canReceiveInput() const { + return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f); +} + +bool Layer::isVisible() const { + if (!hasSomethingToDraw()) { + return false; + } + + if (isHiddenByPolicy()) { + return false; + } + + return getAlpha() > 0.0f || hasBlur(); +} + +void Layer::onPostComposition(const DisplayDevice* display, + const std::shared_ptr<FenceTime>& glDoneFence, + const std::shared_ptr<FenceTime>& presentFence, + const CompositorTiming& compositorTiming) { + // mFrameLatencyNeeded is true when a new frame was latched for the + // composition. + if (!mBufferInfo.mFrameLatencyNeeded) return; + + for (const auto& handle : mDrawingState.callbackHandles) { + handle->gpuCompositionDoneFence = glDoneFence; + handle->compositorTiming = compositorTiming; + } + + // Update mFrameTracker. + nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; + mFrameTracker.setDesiredPresentTime(desiredPresentTime); + + const int32_t layerId = getSequence(); + mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime); + + const auto outputLayer = findOutputLayerForDisplay(display); + if (outputLayer && outputLayer->requiresClientComposition()) { + nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp; + mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, + clientCompositionTimestamp, + FrameTracer::FrameEvent::FALLBACK_COMPOSITION); + // Update the SurfaceFrames in the drawing state + if (mDrawingState.bufferSurfaceFrameTX) { + mDrawingState.bufferSurfaceFrameTX->setGpuComposition(); + } + for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { + surfaceFrame->setGpuComposition(); + } + } + + std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime; + if (frameReadyFence->isValid()) { + mFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); + } else { + // There was no fence for this frame, so assume that it was ready + // to be presented at the desired present time. + mFrameTracker.setFrameReadyTime(desiredPresentTime); + } + + if (display) { + const Fps refreshRate = display->refreshRateConfigs().getActiveModePtr()->getFps(); + const std::optional<Fps> renderRate = + mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); + + const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate); + const auto gameMode = getGameMode(); + + if (presentFence->isValid()) { + mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, + refreshRate, renderRate, vote, gameMode); + mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, + presentFence, + FrameTracer::FrameEvent::PRESENT_FENCE); + mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); + } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); + displayId && mFlinger->getHwComposer().isConnected(*displayId)) { + // The HWC doesn't support present fences, so use the present timestamp instead. + const nsecs_t presentTimestamp = + mFlinger->getHwComposer().getPresentTimestamp(*displayId); + + const nsecs_t now = systemTime(CLOCK_MONOTONIC); + const nsecs_t vsyncPeriod = display->getVsyncPeriodFromHWC(); + const nsecs_t actualPresentTime = now - ((now - presentTimestamp) % vsyncPeriod); + + mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, + refreshRate, renderRate, vote, gameMode); + mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), + mCurrentFrameNumber, actualPresentTime, + FrameTracer::FrameEvent::PRESENT_FENCE); + mFrameTracker.setActualPresentTime(actualPresentTime); + } + } + + mFrameTracker.advanceFrame(); + mBufferInfo.mFrameLatencyNeeded = false; +} + +bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) { + ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(), + getDrawingState().frameNumber); + + bool refreshRequired = latchSidebandStream(recomputeVisibleRegions); + + if (refreshRequired) { + return refreshRequired; + } + + // If the head buffer's acquire fence hasn't signaled yet, return and + // try again later + if (!fenceHasSignaled()) { + ATRACE_NAME("!fenceHasSignaled()"); + mFlinger->onLayerUpdate(); + return false; + } + + updateTexImage(latchTime); + if (mDrawingState.buffer == nullptr) { + return false; + } + + // Capture the old state of the layer for comparisons later + BufferInfo oldBufferInfo = mBufferInfo; + const bool oldOpacity = isOpaque(mDrawingState); + mPreviousFrameNumber = mCurrentFrameNumber; + mCurrentFrameNumber = mDrawingState.frameNumber; + gatherBufferInfo(); + + if (oldBufferInfo.mBuffer == nullptr) { + // the first time we receive a buffer, we need to trigger a + // geometry invalidation. + recomputeVisibleRegions = true; + } + + if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) || + (mBufferInfo.mTransform != oldBufferInfo.mTransform) || + (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) || + (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) { + recomputeVisibleRegions = true; + } + + if (oldBufferInfo.mBuffer != nullptr) { + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + if (bufWidth != oldBufferInfo.mBuffer->getWidth() || + bufHeight != oldBufferInfo.mBuffer->getHeight()) { + recomputeVisibleRegions = true; + } + } + + if (oldOpacity != isOpaque(mDrawingState)) { + recomputeVisibleRegions = true; + } + + return true; +} + +bool Layer::hasReadyFrame() const { + return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh(); +} + +bool Layer::isProtected() const { + return (mBufferInfo.mBuffer != nullptr) && + (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); +} + +// As documented in libhardware header, formats in the range +// 0x100 - 0x1FF are specific to the HAL implementation, and +// are known to have no alpha channel +// TODO: move definition for device-specific range into +// hardware.h, instead of using hard-coded values here. +#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) + +bool Layer::isOpaqueFormat(PixelFormat format) { + if (HARDWARE_IS_DEVICE_FORMAT(format)) { + return true; + } + switch (format) { + case PIXEL_FORMAT_RGBA_8888: + case PIXEL_FORMAT_BGRA_8888: + case PIXEL_FORMAT_RGBA_FP16: + case PIXEL_FORMAT_RGBA_1010102: + case PIXEL_FORMAT_R_8: + return false; + } + // in all other case, we have no blending (also for unknown formats) + return true; +} + +bool Layer::needsFiltering(const DisplayDevice* display) const { + if (!hasBufferOrSidebandStream()) { + return false; + } + const auto outputLayer = findOutputLayerForDisplay(display); + if (outputLayer == nullptr) { + return false; + } + + // We need filtering if the sourceCrop rectangle size does not match the + // displayframe rectangle size (not a 1:1 render) + const auto& compositionState = outputLayer->getState(); + const auto displayFrame = compositionState.displayFrame; + const auto sourceCrop = compositionState.sourceCrop; + return sourceCrop.getHeight() != displayFrame.getHeight() || + sourceCrop.getWidth() != displayFrame.getWidth(); +} + +bool Layer::needsFilteringForScreenshots(const DisplayDevice* display, + const ui::Transform& inverseParentTransform) const { + if (!hasBufferOrSidebandStream()) { + return false; + } + const auto outputLayer = findOutputLayerForDisplay(display); + if (outputLayer == nullptr) { + return false; + } + + // We need filtering if the sourceCrop rectangle size does not match the + // viewport rectangle size (not a 1:1 render) + const auto& compositionState = outputLayer->getState(); + const ui::Transform& displayTransform = display->getTransform(); + const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse(); + // Undo the transformation of the displayFrame so that we're back into + // layer-stack space. + const Rect frame = inverseTransform.transform(compositionState.displayFrame); + const FloatRect sourceCrop = compositionState.sourceCrop; + + int32_t frameHeight = frame.getHeight(); + int32_t frameWidth = frame.getWidth(); + // If the display transform had a rotational component then undo the + // rotation so that the orientation matches the source crop. + if (displayTransform.getOrientation() & ui::Transform::ROT_90) { + std::swap(frameHeight, frameWidth); + } + return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth; +} + +void Layer::latchAndReleaseBuffer() { + if (hasReadyFrame()) { + bool ignored = false; + latchBuffer(ignored, systemTime()); + } + releasePendingBuffer(systemTime()); +} + +PixelFormat Layer::getPixelFormat() const { + return mBufferInfo.mPixelFormat; +} + +bool Layer::getTransformToDisplayInverse() const { + return mBufferInfo.mTransformToDisplayInverse; +} + +Rect Layer::getBufferCrop() const { + // this is the crop rectangle that applies to the buffer + // itself (as opposed to the window) + if (!mBufferInfo.mCrop.isEmpty()) { + // if the buffer crop is defined, we use that + return mBufferInfo.mCrop; + } else if (mBufferInfo.mBuffer != nullptr) { + // otherwise we use the whole buffer + return mBufferInfo.mBuffer->getBounds(); + } else { + // if we don't have a buffer yet, we use an empty/invalid crop + return Rect(); + } +} + +uint32_t Layer::getBufferTransform() const { + return mBufferInfo.mTransform; +} + +ui::Dataspace Layer::getDataSpace() const { + return mDrawingState.dataspaceRequested ? getRequestedDataSpace() : ui::Dataspace::UNKNOWN; +} + +ui::Dataspace Layer::getRequestedDataSpace() const { + return hasBufferOrSidebandStream() ? mBufferInfo.mDataspace : mDrawingState.dataspace; +} + +ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) { + ui::Dataspace updatedDataspace = dataspace; + // translate legacy dataspaces to modern dataspaces + switch (dataspace) { + case ui::Dataspace::SRGB: + updatedDataspace = ui::Dataspace::V0_SRGB; + break; + case ui::Dataspace::SRGB_LINEAR: + updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR; + break; + case ui::Dataspace::JFIF: + updatedDataspace = ui::Dataspace::V0_JFIF; + break; + case ui::Dataspace::BT601_625: + updatedDataspace = ui::Dataspace::V0_BT601_625; + break; + case ui::Dataspace::BT601_525: + updatedDataspace = ui::Dataspace::V0_BT601_525; + break; + case ui::Dataspace::BT709: + updatedDataspace = ui::Dataspace::V0_BT709; + break; + default: + break; + } + + return updatedDataspace; +} + +sp<GraphicBuffer> Layer::getBuffer() const { + return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; +} + +void Layer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) const { + sp<GraphicBuffer> buffer = getBuffer(); + if (!buffer) { + ALOGE("Buffer should not be null!"); + return; + } + GLConsumer::computeTransformMatrix(outMatrix, buffer->getWidth(), buffer->getHeight(), + buffer->getPixelFormat(), mBufferInfo.mCrop, + mBufferInfo.mTransform, filteringEnabled); +} + +void Layer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) { + mTransformHint = getFixedTransformHint(); + if (mTransformHint == ui::Transform::ROT_INVALID) { + mTransformHint = displayTransformHint; + } +} + +const std::shared_ptr<renderengine::ExternalTexture>& Layer::getExternalTexture() const { + return mBufferInfo.mBuffer; +} + +bool Layer::setColor(const half3& color) { + if (mDrawingState.color.r == color.r && mDrawingState.color.g == color.g && + mDrawingState.color.b == color.b) { + return false; + } + + mDrawingState.sequence++; + mDrawingState.color.r = color.r; + mDrawingState.color.g = color.g; + mDrawingState.color.b = color.b; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::fillsColor() const { + return !hasBufferOrSidebandStream() && mDrawingState.color.r >= 0.0_hf && + mDrawingState.color.g >= 0.0_hf && mDrawingState.color.b >= 0.0_hf; +} + +bool Layer::hasBlur() const { + return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0; +} + +void Layer::updateSnapshot(bool updateGeometry) { + if (!getCompositionEngineLayerFE()) { + return; + } + + auto* snapshot = editLayerSnapshot(); + if (updateGeometry) { + prepareBasicGeometryCompositionState(); + prepareGeometryCompositionState(); + snapshot->roundedCorner = getRoundedCornerState(); + snapshot->stretchEffect = getStretchEffect(); + snapshot->transformedBounds = mScreenBounds; + if (mEffectiveShadowRadius > 0.f) { + snapshot->shadowSettings = mFlinger->mDrawingState.globalShadowSettings; + + // Note: this preserves existing behavior of shadowing the entire layer and not cropping + // it if transparent regions are present. This may not be necessary since shadows are + // typically cast by layers without transparent regions. + snapshot->shadowSettings.boundaries = mBounds; + + const float casterAlpha = snapshot->alpha; + const bool casterIsOpaque = + ((mBufferInfo.mBuffer != nullptr) && isOpaque(mDrawingState)); + + // If the casting layer is translucent, we need to fill in the shadow underneath the + // layer. Otherwise the generated shadow will only be shown around the casting layer. + snapshot->shadowSettings.casterIsTranslucent = !casterIsOpaque || (casterAlpha < 1.0f); + snapshot->shadowSettings.ambientColor *= casterAlpha; + snapshot->shadowSettings.spotColor *= casterAlpha; + } + snapshot->shadowSettings.length = mEffectiveShadowRadius; + } + snapshot->contentOpaque = isOpaque(mDrawingState); + snapshot->isHdrY410 = isHdrY410(); + snapshot->bufferNeedsFiltering = bufferNeedsFiltering(); + sp<Layer> p = mDrawingParent.promote(); + if (p != nullptr) { + snapshot->transform = p->getTransform(); + } else { + snapshot->transform.reset(); + } + snapshot->bufferSize = getBufferSize(mDrawingState); + snapshot->externalTexture = mBufferInfo.mBuffer; + preparePerFrameCompositionState(); +} + +void Layer::updateMetadataSnapshot(const LayerMetadata& parentMetadata) { + mSnapshot->layerMetadata = parentMetadata; + mSnapshot->layerMetadata.merge(mDrawingState.metadata); + for (const sp<Layer>& child : mDrawingChildren) { + child->updateMetadataSnapshot(mSnapshot->layerMetadata); + } +} + +void Layer::updateRelativeMetadataSnapshot(const LayerMetadata& relativeLayerMetadata, + std::unordered_set<Layer*>& visited) { + if (visited.find(this) != visited.end()) { + ALOGW("Cycle containing layer %s detected in z-order relatives", getDebugName()); + return; + } + visited.insert(this); + + mSnapshot->relativeLayerMetadata = relativeLayerMetadata; + + if (mDrawingState.zOrderRelatives.empty()) { + return; + } + LayerMetadata childRelativeLayerMetadata = mSnapshot->relativeLayerMetadata; + childRelativeLayerMetadata.merge(mSnapshot->layerMetadata); + for (wp<Layer> weakRelative : mDrawingState.zOrderRelatives) { + sp<Layer> relative = weakRelative.promote(); + if (!relative) { + continue; + } + relative->updateRelativeMetadataSnapshot(childRelativeLayerMetadata, visited); + } +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index c547da06cb..4ff86e5dd6 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -17,8 +17,8 @@ #pragma once #include <android/gui/DropInputMode.h> +#include <android/gui/ISurfaceComposerClient.h> #include <gui/BufferQueue.h> -#include <gui/ISurfaceComposerClient.h> #include <gui/LayerState.h> #include <gui/WindowInfo.h> #include <layerproto/LayerProtoHeader.h> @@ -38,6 +38,7 @@ #include <utils/Timers.h> #include <compositionengine/LayerFE.h> +#include <compositionengine/LayerFECompositionState.h> #include <scheduler/Fps.h> #include <scheduler/Seamlessness.h> @@ -48,13 +49,10 @@ #include <vector> #include "Client.h" -#include "ClientCache.h" -#include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/HWComposer.h" #include "FrameTracker.h" +#include "HwcSlotGenerator.h" #include "LayerVector.h" -#include "MonitoredProducer.h" -#include "RenderArea.h" #include "Scheduler/LayerInfo.h" #include "SurfaceFlinger.h" #include "Tracing/LayerTracing.h" @@ -69,13 +67,16 @@ class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; -class LayerDebugInfo; namespace compositionengine { class OutputLayer; struct LayerFECompositionState; } +namespace gui { +class LayerDebugInfo; +} + namespace impl { class SurfaceInterceptor; } @@ -134,70 +135,73 @@ public: struct RoundedCornerState { RoundedCornerState() = default; - RoundedCornerState(FloatRect cropRect, float radius) + RoundedCornerState(const FloatRect& cropRect, const vec2& radius) : cropRect(cropRect), radius(radius) {} // Rounded rectangle in local layer coordinate space. FloatRect cropRect = FloatRect(); // Radius of the rounded rectangle. - float radius = 0.0f; + vec2 radius; + bool hasRoundedCorners() const { return radius.x > 0.0f && radius.y > 0.0f; } + }; + + // LayerSnapshot stores Layer state used by Composition Engine and Render Engine. Composition + // Engine uses a pointer to LayerSnapshot (as LayerFECompositionState*) and the LayerSettings + // passed to Render Engine are created using properties stored on this struct. + // + // TODO(b/238781169) Implement LayerFE as a separate subclass. Migrate LayerSnapshot to that + // LayerFE subclass. + struct LayerSnapshot : public compositionengine::LayerFECompositionState { + int32_t sequence; + std::string name; + uint32_t textureName; + bool contentOpaque; + RoundedCornerState roundedCorner; + StretchEffect stretchEffect; + FloatRect transformedBounds; + renderengine::ShadowSettings shadowSettings; + bool premultipliedAlpha; + bool isHdrY410; + bool bufferNeedsFiltering; + ui::Transform transform; + Rect bufferSize; + std::shared_ptr<renderengine::ExternalTexture> externalTexture; + LayerMetadata layerMetadata; + LayerMetadata relativeLayerMetadata; }; using FrameRate = scheduler::LayerInfo::FrameRate; using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; struct State { - Geometry active_legacy; - Geometry requested_legacy; int32_t z; - ui::LayerStack layerStack; - uint32_t flags; - uint8_t reserved[2]; int32_t sequence; // changes when visible regions can change bool modified; - // Crop is expressed in layer space coordinate. Rect crop; - Rect requestedCrop; - - // the transparentRegion hint is a bit special, it's latched only - // when we receive a buffer -- this is because it's "content" - // dependent. - Region activeTransparentRegion_legacy; - Region requestedTransparentRegion_legacy; - LayerMetadata metadata; - // If non-null, a Surface this Surface's Z-order is interpreted relative to. wp<Layer> zOrderRelativeOf; bool isRelativeOf{false}; // A list of surfaces whose Z-order is interpreted relative to ours. SortedVector<wp<Layer>> zOrderRelatives; - half4 color; float cornerRadius; int backgroundBlurRadius; - gui::WindowInfo inputInfo; wp<Layer> touchableRegionCrop; - // dataspace is only used by BufferStateLayer and EffectLayer ui::Dataspace dataspace; + bool dataspaceRequested; - // The fields below this point are only used by BufferStateLayer uint64_t frameNumber; - uint32_t width; - uint32_t height; ui::Transform transform; - uint32_t bufferTransform; bool transformToDisplayInverse; - Region transparentRegionHint; - std::shared_ptr<renderengine::ExternalTexture> buffer; client_cache_t clientCacheId; sp<Fence> acquireFence; @@ -205,11 +209,9 @@ public: HdrMetadata hdrMetadata; Region surfaceDamageRegion; int32_t api; - sp<NativeHandle> sidebandStream; mat4 colorTransform; bool hasColorTransform; - // pointer to background color layer that, if set, appears below the buffer state layer // and the buffer state layer's children. Z order will be set to // INT_MIN @@ -232,6 +234,8 @@ public: // Priority of the layer assigned by Window Manager. int32_t frameRateSelectionPriority; + // Default frame rate compatibility used to set the layer refresh rate votetype. + FrameRateCompatibility defaultFrameRateCompatibility; FrameRate frameRate; // The combined frame rate of parents / children of this layer @@ -251,7 +255,6 @@ public: // When the transaction was posted nsecs_t postTime; - sp<ITransactionCompletedListener> releaseBufferListener; // SurfaceFrame that tracks the timeline of Transactions that contain a Buffer. Only one // such SurfaceFrame exists because only one buffer can be presented on the layer per vsync. @@ -272,16 +275,11 @@ public: // Whether or not this layer is a trusted overlay for input bool isTrustedOverlay; - Rect bufferCrop; Rect destinationFrame; - sp<IBinder> releaseBufferEndpoint; - gui::DropInputMode dropInputMode; - bool autoRefresh = false; - bool dimmingEnabled = true; }; @@ -332,43 +330,17 @@ public: static void miniDumpHeader(std::string& result); // Provide unique string for each class type in the Layer hierarchy - virtual const char* getType() const = 0; + virtual const char* getType() const { return "Layer"; } // true if this layer is visible, false otherwise - virtual bool isVisible() const = 0; + virtual bool isVisible() const; - virtual sp<Layer> createClone() = 0; + virtual sp<Layer> createClone(); - // Geometry setting functions. - // - // The following group of functions are used to specify the layers - // bounds, and the mapping of the texture on to those bounds. According - // to various settings changes to them may apply immediately, or be delayed until - // a pending resize is completed by the producer submitting a buffer. For example - // if we were to change the buffer size, and update the matrix ahead of the - // new buffer arriving, then we would be stretching the buffer to a different - // aspect before and after the buffer arriving, which probably isn't what we wanted. - // - // The first set of geometry functions are controlled by the scaling mode, described - // in window.h. The scaling mode may be set by the client, as it submits buffers. - // - // Put simply, if our scaling mode is SCALING_MODE_FREEZE, then - // matrix updates will not be applied while a resize is pending - // and the size and transform will remain in their previous state - // until a new buffer is submitted. If the scaling mode is another value - // then the old-buffer will immediately be scaled to the pending size - // and the new matrix will be immediately applied following this scaling - // transformation. - - // Set the default buffer size for the assosciated Producer, in pixels. This is - // also the rendered size of the layer prior to any transformations. Parent - // or local matrix transformations will not affect the size of the buffer, - // but may affect it's on-screen size or clipping. - virtual bool setSize(uint32_t w, uint32_t h); // Set a 2x2 transformation matrix on the layer. This transform // will be applied after parent transforms, but before any final // producer specified transform. - virtual bool setMatrix(const layer_state_t::matrix22_t& matrix); + bool setMatrix(const layer_state_t::matrix22_t& matrix); // This second set of geometry attributes are controlled by // setGeometryAppliesWithResize, and their default mode is to be @@ -378,9 +350,9 @@ public: // setPosition operates in parent buffer space (pre parent-transform) or display // space for top-level layers. - virtual bool setPosition(float x, float y); + bool setPosition(float x, float y); // Buffer space - virtual bool setCrop(const Rect& crop); + bool setCrop(const Rect& crop); // TODO(b/38182121): Could we eliminate the various latching modes by // using the layer hierarchy? @@ -389,7 +361,7 @@ public: virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ); virtual bool setAlpha(float alpha); - virtual bool setColor(const half3& /*color*/) { return false; }; + bool setColor(const half3& /*color*/); // Set rounded corner radius for this layer and its children. // @@ -401,7 +373,7 @@ public: // is specified in pixels. virtual bool setBackgroundBlurRadius(int backgroundBlurRadius); virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions); - virtual bool setTransparentRegionHint(const Region& transparent); + bool setTransparentRegionHint(const Region& transparent); virtual bool setTrustedOverlay(bool); virtual bool setFlags(uint32_t flags, uint32_t mask); virtual bool setLayerStack(ui::LayerStack); @@ -415,44 +387,46 @@ public: virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; } virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; }; - // Used only to set BufferStateLayer state - virtual bool setTransform(uint32_t /*transform*/) { return false; }; - virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; - virtual bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */, - const BufferData& /* bufferData */, nsecs_t /* postTime */, - nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, - std::optional<nsecs_t> /* dequeueTime */, - const FrameTimelineInfo& /*info*/) { - return false; - }; - virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; }; - virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; }; - virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; }; - virtual bool setApi(int32_t /*api*/) { return false; }; - virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; }; - virtual bool setTransactionCompletedListeners( - const std::vector<sp<CallbackHandle>>& /*handles*/); + bool setTransform(uint32_t /*transform*/); + bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/); + bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */, + const BufferData& /* bufferData */, nsecs_t /* postTime */, + nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, + std::optional<nsecs_t> /* dequeueTime */, const FrameTimelineInfo& /*info*/); + bool setDataspace(ui::Dataspace /*dataspace*/); + bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/); + bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/); + bool setApi(int32_t /*api*/); + bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/); + bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& /*handles*/); virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace); virtual bool setColorSpaceAgnostic(const bool agnostic); virtual bool setDimmingEnabled(const bool dimmingEnabled); + virtual bool setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility); virtual bool setFrameRateSelectionPriority(int32_t priority); virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); - virtual void setAutoRefresh(bool /* autoRefresh */) {} + void setAutoRefresh(bool /* autoRefresh */); bool setDropInputMode(gui::DropInputMode); // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; - virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; } + // + virtual FrameRateCompatibility getDefaultFrameRateCompatibility() const; + // + ui::Dataspace getDataSpace() const; + ui::Dataspace getRequestedDataSpace() const; virtual sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const; - virtual compositionengine::LayerFECompositionState* editCompositionState(); + + const LayerSnapshot* getLayerSnapshot() const; + LayerSnapshot* editLayerSnapshot(); // If we have received a new buffer this frame, we will pass its surface // damage down to hardware composer. Otherwise, we must send a region with // one empty rect. - virtual void useSurfaceDamage() {} - virtual void useEmptyDamage() {} + void useSurfaceDamage(); + void useEmptyDamage(); Region getVisibleRegion(const DisplayDevice*) const; /* @@ -462,18 +436,18 @@ public: * pixel format includes an alpha channel) and the "opaque" flag set * on the layer. It does not examine the current plane alpha value. */ - virtual bool isOpaque(const Layer::State&) const { return false; } + bool isOpaque(const Layer::State&) const; /* * Returns whether this layer can receive input. */ - virtual bool canReceiveInput() const; + bool canReceiveInput() const; /* * isProtected - true if the layer may contain protected contents in the * GRALLOC_USAGE_PROTECTED sense. */ - virtual bool isProtected() const { return false; } + bool isProtected() const; /* * isFixedSize - true if content has a fixed size @@ -483,21 +457,19 @@ public: /* * usesSourceCrop - true if content should use a source crop */ - virtual bool usesSourceCrop() const { return false; } + bool usesSourceCrop() const { return hasBufferOrSidebandStream(); } // Most layers aren't created from the main thread, and therefore need to // grab the SF state lock to access HWC, but ContainerLayer does, so we need // to avoid grabbing the lock again to avoid deadlock virtual bool isCreatedFromMainThread() const { return false; } - uint32_t getActiveWidth(const Layer::State& s) const { return s.width; } - uint32_t getActiveHeight(const Layer::State& s) const { return s.height; } ui::Transform getActiveTransform(const Layer::State& s) const { return s.transform; } - virtual Region getActiveTransparentRegion(const Layer::State& s) const { - return s.activeTransparentRegion_legacy; + Region getActiveTransparentRegion(const Layer::State& s) const { + return s.transparentRegionHint; } - virtual Rect getCrop(const Layer::State& s) const { return s.crop; } - virtual bool needsFiltering(const DisplayDevice*) const { return false; } + Rect getCrop(const Layer::State& s) const { return s.crop; } + bool needsFiltering(const DisplayDevice*) const; // True if this layer requires filtering // This method is distinct from needsFiltering() in how the filter @@ -508,32 +480,25 @@ public: // different. // If the parent transform needs to be undone when capturing the layer, then // the inverse parent transform is also required. - virtual bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const { - return false; - } - - virtual void updateCloneBufferInfo(){}; - - virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {} + bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const; - virtual bool isHdrY410() const { return false; } + // from graphics API + ui::Dataspace translateDataspace(ui::Dataspace dataspace); + void updateCloneBufferInfo(); + uint64_t mPreviousFrameNumber = 0; - virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; } + bool isHdrY410() const; /* * called after composition. * returns true if the layer latched a new buffer this frame. */ - virtual void onPostComposition(const DisplayDevice*, - const std::shared_ptr<FenceTime>& /*glDoneFence*/, - const std::shared_ptr<FenceTime>& /*presentFence*/, - const CompositorTiming&) {} + void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& /*glDoneFence*/, + const std::shared_ptr<FenceTime>& /*presentFence*/, + const CompositorTiming&); // If a buffer was replaced this frame, release the former buffer - virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { } - - virtual void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& /*glDoneFence*/, - const CompositorTiming& /*compositorTiming*/) {} + void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/); /* * latchBuffer - called each time the screen is redrawn and returns whether @@ -541,88 +506,119 @@ public: * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/, - nsecs_t /*expectedPresentTime*/) { - return false; - } + bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/); - virtual void latchAndReleaseBuffer() {} + /* + * Calls latchBuffer if the buffer has a frame queued and then releases the buffer. + * This is used if the buffer is just latched and releases to free up the buffer + * and will not be shown on screen. + * Should only be called on the main thread. + */ + void latchAndReleaseBuffer(); /* * returns the rectangle that crops the content of the layer and scales it * to the layer's size. */ - virtual Rect getBufferCrop() const { return Rect(); } + Rect getBufferCrop() const; /* * Returns the transform applied to the buffer. */ - virtual uint32_t getBufferTransform() const { return 0; } + uint32_t getBufferTransform() const; - virtual sp<GraphicBuffer> getBuffer() const { return nullptr; } - virtual const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const { - return mDrawingState.buffer; - }; + sp<GraphicBuffer> getBuffer() const; + const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const; - virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; } + ui::Transform::RotationFlags getTransformHint() const { return mTransformHint; } /* * Returns if a frame is ready */ - virtual bool hasReadyFrame() const { return false; } + bool hasReadyFrame() const; virtual int32_t getQueuedFrameCount() const { return 0; } /** * Returns active buffer size in the correct orientation. Buffer size is determined by undoing - * any buffer transformations. If the layer has no buffer then return INVALID_RECT. + * any buffer transformations. Returns Rect::INVALID_RECT if the layer has no buffer or the + * layer does not have a display frame and its parent is not bounded. */ - virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; } + Rect getBufferSize(const Layer::State&) const; /** * Returns the source bounds. If the bounds are not defined, it is inferred from the * buffer size. Failing that, the bounds are determined from the passed in parent bounds. * For the root layer, this is the display viewport size. */ - virtual FloatRect computeSourceBounds(const FloatRect& parentBounds) const { - return parentBounds; - } + FloatRect computeSourceBounds(const FloatRect& parentBounds) const; virtual FrameRate getFrameRateForLayerTree() const; - virtual bool getTransformToDisplayInverse() const { return false; } + bool getTransformToDisplayInverse() const; // Returns how rounded corners should be drawn for this layer. // A layer can override its parent's rounded corner settings if the parent's rounded // corner crop does not intersect with its own rounded corner crop. virtual RoundedCornerState getRoundedCornerState() const; - bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } + bool hasRoundedCorners() const override { return getRoundedCornerState().hasRoundedCorners(); } - virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; } + PixelFormat getPixelFormat() const; /** - * Return whether this layer needs an input info. For most layer types - * this is only true if they explicitly set an input-info but BufferLayer - * overrides this so we can generate input-info for Buffered layers that don't - * have them (for input occlusion detection checks). + * Return whether this layer needs an input info. We generate InputWindowHandles for all + * non-cursor buffered layers regardless of whether they have an InputChannel. This is to enable + * the InputDispatcher to do PID based occlusion detection. */ - virtual bool needsInputInfo() const { return hasInputInfo(); } + bool needsInputInfo() const { + return (hasInputInfo() || hasBufferOrSidebandStream()) && !mPotentialCursor; + } // Implements RefBase. void onFirstRef() override; + struct BufferInfo { + nsecs_t mDesiredPresentTime; + std::shared_ptr<FenceTime> mFenceTime; + sp<Fence> mFence; + uint32_t mTransform{0}; + ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN}; + Rect mCrop; + uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; + Region mSurfaceDamage; + HdrMetadata mHdrMetadata; + int mApi; + PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; + bool mTransformToDisplayInverse{false}; + + std::shared_ptr<renderengine::ExternalTexture> mBuffer; + uint64_t mFrameNumber; + int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; + + bool mFrameLatencyNeeded{false}; + }; + + BufferInfo mBufferInfo; + // implements compositionengine::LayerFE - const compositionengine::LayerFECompositionState* getCompositionState() const override; - bool onPreComposition(nsecs_t) override; - void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override; - std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList( - compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override; + const compositionengine::LayerFECompositionState* getCompositionState() const; + bool fenceHasSignaled() const; + // Called before composition. updatingOutputGeometryThisFrame is used by ARC++'s Layer subclass. + bool onPreComposition(nsecs_t refreshStartTime, bool updatingOutputGeometryThisFrame); + std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&) const override; + void onLayerDisplayed(ftl::SharedFuture<FenceResult>); void setWasClientComposed(const sp<Fence>& fence) override { mLastClientCompositionFence = fence; mClearClientCompositionFenceOnLayerDisplayed = false; } + const LayerMetadata* getMetadata() const override { return &mSnapshot->layerMetadata; } + + const LayerMetadata* getRelativeMetadata() const override { + return &mSnapshot->relativeLayerMetadata; + } + const char* getDebugName() const override; bool setShadowRadius(float shadowRadius); @@ -735,7 +731,7 @@ public: inline const State& getDrawingState() const { return mDrawingState; } inline State& getDrawingState() { return mDrawingState; } - LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const; + gui::LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const; void miniDump(std::string& result, const DisplayDevice&) const; void dumpFrameStats(std::string& result) const; @@ -889,14 +885,33 @@ public: bool setStretchEffect(const StretchEffect& effect); StretchEffect getStretchEffect() const; - - virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; } - virtual bool setDestinationFrame(const Rect& /* destinationFrame */) { return false; } - virtual std::atomic<int32_t>* getPendingBufferCounter() { return nullptr; } - virtual std::string getPendingBufferCounterName() { return ""; } - virtual bool updateGeometry() { return false; } - - virtual bool simpleBufferUpdate(const layer_state_t&) const { return false; } + bool enableBorder(bool shouldEnable, float width, const half4& color); + bool isBorderEnabled(); + float getBorderWidth(); + const half4& getBorderColor(); + + bool setBufferCrop(const Rect& /* bufferCrop */); + bool setDestinationFrame(const Rect& /* destinationFrame */); + // See mPendingBufferTransactions + void decrementPendingBufferCount(); + std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBufferTransactions; } + std::string getPendingBufferCounterName() { return mBlastTransactionName; } + bool updateGeometry(); + + bool simpleBufferUpdate(const layer_state_t&) const; + + static bool isOpaqueFormat(PixelFormat format); + + // Updates the LayerSnapshot. This must be called prior to sending layer data to + // CompositionEngine or RenderEngine (i.e. before calling CompositionEngine::present or + // Layer::prepareClientComposition). + // + // TODO(b/238781169) Remove direct calls to RenderEngine::drawLayers that don't go through + // CompositionEngine to create a single path for composing layers. + void updateSnapshot(bool updateGeometry); + void updateMetadataSnapshot(const LayerMetadata& parentMetadata); + void updateRelativeMetadataSnapshot(const LayerMetadata& relativeLayerMetadata, + std::unordered_set<Layer*>& visited); protected: friend class impl::SurfaceInterceptor; @@ -910,16 +925,12 @@ protected: friend class TransactionSurfaceFrameTest; virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom); - virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings&); - virtual void preparePerFrameCompositionState(); + void preparePerFrameCompositionState(); + void preparePerFrameBufferCompositionState(); + void preparePerFrameEffectsCompositionState(); virtual void commitTransaction(State& stateToCommit); - virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {} - - // Returns mCurrentScaling mode (originating from the - // Client) or mOverrideScalingMode mode (originating from - // the Surface Controller) if set. - virtual uint32_t getEffectiveScalingMode() const { return 0; } + void gatherBufferInfo(); + void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&); sp<compositionengine::LayerFE> asLayerFE() const; sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; } @@ -937,7 +948,8 @@ protected: // Modifies the passed in layer settings to clear the contents. If the blackout flag is set, // the settings clears the content with a solid black fill. void prepareClearClientComposition(LayerFE::LayerSettings&, bool blackout) const; - void prepareShadowClientComposition(LayerFE::LayerSettings& caster, const Rect& layerStackRect); + void prepareShadowClientComposition(LayerFE::LayerSettings& caster, + const Rect& layerStackRect) const; void prepareBasicGeometryCompositionState(); void prepareGeometryCompositionState(); @@ -971,7 +983,7 @@ protected: * "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input * in this layer's space, regardless of the specified crop layer. */ - virtual Rect getInputBounds() const; + Rect getInputBounds() const; // constant sp<SurfaceFlinger> mFlinger; @@ -1042,7 +1054,14 @@ protected: sp<Fence> mLastClientCompositionFence; bool mClearClientCompositionFenceOnLayerDisplayed = false; private: - virtual void setTransformHint(ui::Transform::RotationFlags) {} + friend class SlotGenerationTest; + friend class TransactionFrameTracerTest; + friend class TransactionSurfaceFrameTest; + + bool getAutoRefresh() const { return mDrawingState.autoRefresh; } + bool getSidebandStreamChanged() const { return mSidebandStreamChanged; } + + std::atomic<bool> mSidebandStreamChanged{false}; // Returns true if the layer can draw shadows on its border. virtual bool canDrawShadows() const { return true; } @@ -1087,6 +1106,52 @@ private: // Fills in the frame and transform info for the gui::WindowInfo. void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& screenToDisplay); + // Computes the transform matrix using the setFilteringEnabled to determine whether the + // transform matrix should be computed for use with bilinear filtering. + void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) const; + + inline void tracePendingBufferCount(int32_t pendingBuffers); + + // Latch sideband stream and returns true if the dirty region should be updated. + bool latchSidebandStream(bool& recomputeVisibleRegions); + + bool hasFrameUpdate() const; + + void updateTexImage(nsecs_t latchTime); + + // Crop that applies to the buffer + Rect computeBufferCrop(const State& s); + + bool willPresentCurrentTransaction() const; + + // Returns true if the transformed buffer size does not match the layer size and we need + // to apply filtering. + bool bufferNeedsFiltering() const; + + void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, + const sp<GraphicBuffer>& buffer, uint64_t framenumber, + const sp<Fence>& releaseFence, + uint32_t currentMaxAcquiredBufferCount); + + std::optional<compositionengine::LayerFE::LayerSettings> prepareClientCompositionInternal( + compositionengine::LayerFE::ClientCompositionTargetSettings&) const; + // Returns true if there is a valid color to fill. + bool fillsColor() const; + // Returns true if this layer has a blur value. + bool hasBlur() const; + bool hasEffect() const { return fillsColor() || drawShadows() || hasBlur(); } + bool hasBufferOrSidebandStream() const { + return ((mSidebandStream != nullptr) || (mBufferInfo.mBuffer != nullptr)); + } + + bool hasSomethingToDraw() const { return hasEffect() || hasBufferOrSidebandStream(); } + void prepareBufferStateClientComposition( + compositionengine::LayerFE::LayerSettings&, + compositionengine::LayerFE::ClientCompositionTargetSettings&) const; + void prepareEffectsClientComposition( + compositionengine::LayerFE::LayerSettings&, + compositionengine::LayerFE::ClientCompositionTargetSettings&) const; + // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling, which is // a transform from the current layer coordinate space to display(screen) coordinate space. @@ -1130,7 +1195,55 @@ private: bool mIsAtRoot = false; uint32_t mLayerCreationFlags; + bool findInHierarchy(const sp<Layer>&); + + bool mBorderEnabled = false; + float mBorderWidth; + half4 mBorderColor; + + void setTransformHint(ui::Transform::RotationFlags); + + const uint32_t mTextureName; + + // Transform hint provided to the producer. This must be accessed holding + // the mStateLock. + ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0; + + ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; + uint64_t mPreviousReleasedFrameNumber = 0; + + uint64_t mPreviousBarrierFrameNumber = 0; + + bool mReleasePreviousBuffer = false; + + // Stores the last set acquire fence signal time used to populate the callback handle's acquire + // time. + std::variant<nsecs_t, sp<Fence>> mCallbackHandleAcquireTimeOrFence = -1; + + std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications; + // An upper bound on the number of SurfaceFrames in the pending classifications deque. + static constexpr int kPendingClassificationMaxSurfaceFrames = 25; + + const std::string mBlastTransactionName{"BufferTX - " + mName}; + // This integer is incremented everytime a buffer arrives at the server for this layer, + // and decremented when a buffer is dropped or latched. When changed the integer is exported + // to systrace with ATRACE_INT and mBlastTransactionName. This way when debugging perf it is + // possible to see when a buffer arrived at the server, and in which frame it latched. + // + // You can understand the trace this way: + // - If the integer increases, a buffer arrived at the server. + // - If the integer decreases in latchBuffer, that buffer was latched + // - If the integer decreases in setBuffer or doTransaction, a buffer was dropped + std::atomic<int32_t> mPendingBufferTransactions{0}; + + // Contains requested position and matrix updates. This will be applied if the client does + // not specify a destination frame. + ui::Transform mRequestedTransform; + + sp<HwcSlotGenerator> mHwcSlotGenerator; + + std::unique_ptr<LayerSnapshot> mSnapshot = std::make_unique<LayerSnapshot>(); }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp deleted file mode 100644 index 1c0263ba0b..0000000000 --- a/services/surfaceflinger/LayerRejecter.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#include "LayerRejecter.h" - -#include <gui/BufferItem.h> -#include <system/window.h> - -#define DEBUG_RESIZE 0 - -namespace android { - -LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current, - bool& recomputeVisibleRegions, bool stickySet, const std::string& name, - bool transformToDisplayInverse) - : mFront(front), - mCurrent(current), - mRecomputeVisibleRegions(recomputeVisibleRegions), - mStickyTransformSet(stickySet), - mName(name), - mTransformToDisplayInverse(transformToDisplayInverse) {} - -bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) { - if (buf == nullptr) { - return false; - } - - uint32_t bufWidth = buf->getWidth(); - uint32_t bufHeight = buf->getHeight(); - - // check that we received a buffer of the right size - // (Take the buffer's orientation into account) - if (item.mTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - - if (mTransformToDisplayInverse) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - } - - int actualScalingMode = item.mScalingMode; - bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE; - if (mFront.active_legacy != mFront.requested_legacy) { - if (isFixedSize || - (bufWidth == mFront.requested_legacy.w && bufHeight == mFront.requested_legacy.h)) { - // Here we pretend the transaction happened by updating the - // current and drawing states. Drawing state is only accessed - // in this thread, no need to have it locked - mFront.active_legacy = mFront.requested_legacy; - - // We also need to update the current state so that - // we don't end-up overwriting the drawing state with - // this stale current state during the next transaction - // - // NOTE: We don't need to hold the transaction lock here - // because State::active_legacy is only accessed from this thread. - mCurrent.active_legacy = mFront.active_legacy; - mCurrent.modified = true; - - // recompute visible region - mRecomputeVisibleRegions = true; - - if (mFront.crop != mFront.requestedCrop) { - mFront.crop = mFront.requestedCrop; - mCurrent.crop = mFront.requestedCrop; - mRecomputeVisibleRegions = true; - } - } - - ALOGD_IF(DEBUG_RESIZE, - "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n" - " drawing={ active_legacy ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} " - "(%4d,%4d) " - "}\n" - " requested_legacy={ wh={%4u,%4u} }}\n", - mName.c_str(), bufWidth, bufHeight, item.mTransform, item.mScalingMode, - mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop.left, mFront.crop.top, - mFront.crop.right, mFront.crop.bottom, mFront.crop.getWidth(), - mFront.crop.getHeight(), mFront.requested_legacy.w, mFront.requested_legacy.h); - } - - if (!isFixedSize && !mStickyTransformSet) { - if (mFront.active_legacy.w != bufWidth || mFront.active_legacy.h != bufHeight) { - // reject this buffer - ALOGE("[%s] rejecting buffer: " - "bufWidth=%d, bufHeight=%d, front.active_legacy.{w=%d, h=%d}", - mName.c_str(), bufWidth, bufHeight, mFront.active_legacy.w, - mFront.active_legacy.h); - return true; - } - } - - // if the transparent region has changed (this test is - // conservative, but that's fine, worst case we're doing - // a bit of extra work), we latch the new one and we - // trigger a visible-region recompute. - // - // We latch the transparent region here, instead of above where we latch - // the rest of the geometry because it is only content but not necessarily - // resize dependent. - if (!mFront.activeTransparentRegion_legacy.hasSameRects( - mFront.requestedTransparentRegion_legacy)) { - mFront.activeTransparentRegion_legacy = mFront.requestedTransparentRegion_legacy; - - // We also need to update the current state so that - // we don't end-up overwriting the drawing state with - // this stale current state during the next transaction - // - // NOTE: We don't need to hold the transaction lock here - // because State::active_legacy is only accessed from this thread. - mCurrent.activeTransparentRegion_legacy = mFront.activeTransparentRegion_legacy; - - // recompute visible region - mRecomputeVisibleRegions = true; - } - - return false; -} - -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h deleted file mode 100644 index 4981f451d9..0000000000 --- a/services/surfaceflinger/LayerRejecter.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#pragma once - -#include "Layer.h" -#include "BufferLayerConsumer.h" - -namespace android { - -class LayerRejecter : public BufferLayerConsumer::BufferRejecter { -public: - LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions, - bool stickySet, const std::string& name, - bool transformToDisplayInverse); - - virtual bool reject(const sp<GraphicBuffer>&, const BufferItem&); - -private: - Layer::State& mFront; - Layer::State& mCurrent; - bool& mRecomputeVisibleRegions; - const bool mStickyTransformSet; - const std::string& mName; - const bool mTransformToDisplayInverse; -}; - -} // namespace android diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp index 896f25404d..6bc7dc1dd7 100644 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -17,7 +17,6 @@ #include <ui/GraphicTypes.h> #include <ui/Transform.h> -#include "ContainerLayer.h" #include "DisplayDevice.h" #include "Layer.h" #include "LayerRenderArea.h" @@ -110,8 +109,9 @@ void LayerRenderArea::render(std::function<void()> drawLayers) { // layer which has no properties set and which does not draw. // We hold the statelock as the reparent-for-drawing operation modifies the // hierarchy and there could be readers on Binder threads, like dump. - sp<ContainerLayer> screenshotParentLayer = mFlinger.getFactory().createContainerLayer( - {&mFlinger, nullptr, "Screenshot Parent"s, 0, LayerMetadata()}); + auto screenshotParentLayer = mFlinger.getFactory().createEffectLayer( + {&mFlinger, nullptr, "Screenshot Parent"s, ISurfaceComposerClient::eNoColorFill, + LayerMetadata()}); { Mutex::Autolock _l(mFlinger.mStateLock); reparentForDrawing(mLayer, screenshotParentLayer, sourceCrop); diff --git a/services/surfaceflinger/LocklessQueue.h b/services/surfaceflinger/LocklessQueue.h new file mode 100644 index 0000000000..6b633607ae --- /dev/null +++ b/services/surfaceflinger/LocklessQueue.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#pragma once +#include <atomic> +#include <optional> + +template <typename T> +// Single consumer multi producer stack. We can understand the two operations independently to see +// why they are without race condition. +// +// push is responsible for maintaining a linked list stored in mPush, and called from multiple +// threads without lock. We can see that if two threads never observe the same value from +// mPush.load, it just functions as a normal linked list. In the case where two threads observe the +// same value, one of them has to execute the compare_exchange first. The one that doesn't execute +// the compare exchange first, will receive false from compare_exchange. previousHead is updated (by +// compare_exchange) to the most recent value of mPush, and we try again. It's relatively clear to +// see that the process can repeat with an arbitrary number of threads. +// +// Pop is much simpler. If mPop is empty (as it begins) it atomically exchanges +// the entire push list with null. This is safe, since the only other reader (push) +// of mPush will retry if it changes in between it's read and atomic compare. We +// then store the list and pop one element. +// +// If we already had something in the pop list we just pop directly. +class LocklessQueue { +public: + class Entry { + public: + T mValue; + std::atomic<Entry*> mNext; + Entry(T value) : mValue(value) {} + }; + std::atomic<Entry*> mPush = nullptr; + std::atomic<Entry*> mPop = nullptr; + bool isEmpty() { return (mPush.load() == nullptr) && (mPop.load() == nullptr); } + + void push(T value) { + Entry* entry = new Entry(value); + Entry* previousHead = mPush.load(/*std::memory_order_relaxed*/); + do { + entry->mNext = previousHead; + } while (!mPush.compare_exchange_weak(previousHead, entry)); /*std::memory_order_release*/ + } + std::optional<T> pop() { + Entry* popped = mPop.load(/*std::memory_order_acquire*/); + if (popped) { + // Single consumer so this is fine + mPop.store(popped->mNext /* , std::memory_order_release */); + auto value = popped->mValue; + delete popped; + return std::move(value); + } else { + Entry* grabbedList = mPush.exchange(nullptr /* , std::memory_order_acquire */); + if (!grabbedList) return std::nullopt; + // Reverse the list + while (grabbedList->mNext) { + Entry* next = grabbedList->mNext; + grabbedList->mNext = popped; + popped = grabbedList; + grabbedList = next; + } + mPop.store(popped /* , std::memory_order_release */); + auto value = grabbedList->mValue; + delete grabbedList; + return std::move(value); + } + } +}; diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp deleted file mode 100644 index df76f50112..0000000000 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2014 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#include "MonitoredProducer.h" -#include "Layer.h" -#include "SurfaceFlinger.h" - -#include "Scheduler/MessageQueue.h" - -namespace android { - -MonitoredProducer::MonitoredProducer(const sp<IGraphicBufferProducer>& producer, - const sp<SurfaceFlinger>& flinger, - const wp<Layer>& layer) : - mProducer(producer), - mFlinger(flinger), - mLayer(layer) {} - -MonitoredProducer::~MonitoredProducer() {} - -status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { - return mProducer->requestBuffer(slot, buf); -} - -status_t MonitoredProducer::setMaxDequeuedBufferCount( - int maxDequeuedBuffers) { - return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers); -} - -status_t MonitoredProducer::setAsyncMode(bool async) { - return mProducer->setAsyncMode(async); -} - -status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, - PixelFormat format, uint64_t usage, - uint64_t* outBufferAge, - FrameEventHistoryDelta* outTimestamps) { - return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps); -} - -status_t MonitoredProducer::detachBuffer(int slot) { - return mProducer->detachBuffer(slot); -} - -status_t MonitoredProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence) { - return mProducer->detachNextBuffer(outBuffer, outFence); -} - -status_t MonitoredProducer::attachBuffer(int* outSlot, - const sp<GraphicBuffer>& buffer) { - return mProducer->attachBuffer(outSlot, buffer); -} - -status_t MonitoredProducer::queueBuffer(int slot, const QueueBufferInput& input, - QueueBufferOutput* output) { - return mProducer->queueBuffer(slot, input, output); -} - -status_t MonitoredProducer::cancelBuffer(int slot, const sp<Fence>& fence) { - return mProducer->cancelBuffer(slot, fence); -} - -int MonitoredProducer::query(int what, int* value) { - return mProducer->query(what, value); -} - -status_t MonitoredProducer::connect(const sp<IProducerListener>& listener, - int api, bool producerControlledByApp, QueueBufferOutput* output) { - return mProducer->connect(listener, api, producerControlledByApp, output); -} - -status_t MonitoredProducer::disconnect(int api, DisconnectMode mode) { - return mProducer->disconnect(api, mode); -} - -status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) { - return mProducer->setSidebandStream(stream); -} - -void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage) { - mProducer->allocateBuffers(width, height, format, usage); -} - -status_t MonitoredProducer::allowAllocation(bool allow) { - return mProducer->allowAllocation(allow); -} - -status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) { - return mProducer->setGenerationNumber(generationNumber); -} - -String8 MonitoredProducer::getConsumerName() const { - return mProducer->getConsumerName(); -} - -status_t MonitoredProducer::setSharedBufferMode(bool sharedBufferMode) { - return mProducer->setSharedBufferMode(sharedBufferMode); -} - -status_t MonitoredProducer::setAutoRefresh(bool autoRefresh) { - return mProducer->setAutoRefresh(autoRefresh); -} - -status_t MonitoredProducer::setDequeueTimeout(nsecs_t timeout) { - return mProducer->setDequeueTimeout(timeout); -} - -status_t MonitoredProducer::setLegacyBufferDrop(bool drop) { - return mProducer->setLegacyBufferDrop(drop); -} - -status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence, float outTransformMatrix[16]) { - return mProducer->getLastQueuedBuffer(outBuffer, outFence, - outTransformMatrix); -} - -status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, - Rect* outRect, uint32_t* outTransform) { - return mProducer->getLastQueuedBuffer(outBuffer, outFence, outRect, outTransform); -} - -void MonitoredProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) { - mProducer->getFrameTimestamps(outDelta); -} - -status_t MonitoredProducer::getUniqueId(uint64_t* outId) const { - return mProducer->getUniqueId(outId); -} - -status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const { - return mProducer->getConsumerUsage(outUsage); -} - -status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) { - return mProducer->setAutoPrerotation(autoPrerotation); -} - -IBinder* MonitoredProducer::onAsBinder() { - return this; -} - -sp<Layer> MonitoredProducer::getLayer() const { - return mLayer.promote(); -} - -// --------------------------------------------------------------------------- -}; // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h deleted file mode 100644 index 3778277fd3..0000000000 --- a/services/surfaceflinger/MonitoredProducer.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_MONITORED_PRODUCER_H -#define ANDROID_MONITORED_PRODUCER_H - -#include <gui/IGraphicBufferProducer.h> - -namespace android { - -class IProducerListener; -class NativeHandle; -class SurfaceFlinger; -class Layer; - -// MonitoredProducer wraps an IGraphicBufferProducer so that SurfaceFlinger will -// be notified upon its destruction -class MonitoredProducer : public BnGraphicBufferProducer { -public: - MonitoredProducer(const sp<IGraphicBufferProducer>& producer, - const sp<SurfaceFlinger>& flinger, - const wp<Layer>& layer); - virtual ~MonitoredProducer(); - - // From IGraphicBufferProducer - virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); - virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); - virtual status_t setAsyncMode(bool async); - virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, - PixelFormat format, uint64_t usage, uint64_t* outBufferAge, - FrameEventHistoryDelta* outTimestamps); - virtual status_t detachBuffer(int slot); - virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence); - virtual status_t attachBuffer(int* outSlot, - const sp<GraphicBuffer>& buffer); - virtual status_t queueBuffer(int slot, const QueueBufferInput& input, - QueueBufferOutput* output); - virtual status_t cancelBuffer(int slot, const sp<Fence>& fence); - virtual int query(int what, int* value); - virtual status_t connect(const sp<IProducerListener>& token, int api, - bool producerControlledByApp, QueueBufferOutput* output); - virtual status_t disconnect(int api, DisconnectMode mode); - virtual status_t setSidebandStream(const sp<NativeHandle>& stream); - virtual void allocateBuffers(uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage); - virtual status_t allowAllocation(bool allow); - virtual status_t setGenerationNumber(uint32_t generationNumber); - virtual String8 getConsumerName() const override; - virtual status_t setDequeueTimeout(nsecs_t timeout) override; - virtual status_t setLegacyBufferDrop(bool drop) override; - virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence, float outTransformMatrix[16]) override; - virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, - Rect* outRect, uint32_t* outTransform) override; - virtual IBinder* onAsBinder(); - virtual status_t setSharedBufferMode(bool sharedBufferMode) override; - virtual status_t setAutoRefresh(bool autoRefresh) override; - virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override; - virtual status_t getUniqueId(uint64_t* outId) const override; - virtual status_t getConsumerUsage(uint64_t* outUsage) const override; - virtual status_t setAutoPrerotation(bool autoPrerotation) override; - - // The Layer which created this producer, and on which queued Buffer's will be displayed. - sp<Layer> getLayer() const; - -private: - sp<IGraphicBufferProducer> mProducer; - sp<SurfaceFlinger> mFlinger; - // The Layer which created this producer, and on which queued Buffer's will be displayed. - wp<Layer> mLayer; -}; - -}; // namespace android - -#endif // ANDROID_MONITORED_PRODUCER_H diff --git a/services/surfaceflinger/NativeWindowSurface.cpp b/services/surfaceflinger/NativeWindowSurface.cpp index 3fff9283ee..a6a3eec8ff 100644 --- a/services/surfaceflinger/NativeWindowSurface.cpp +++ b/services/surfaceflinger/NativeWindowSurface.cpp @@ -30,7 +30,7 @@ std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( class NativeWindowSurface final : public surfaceflinger::NativeWindowSurface { public: explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer) - : mSurface(new Surface(producer, /* controlledByApp */ false)) {} + : mSurface(sp<Surface>::make(producer, /* controlledByApp */ false)) {} ~NativeWindowSurface() override = default; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index a9180d4483..9b19afbdac 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -152,13 +152,13 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, } }(); - sp<GraphicBuffer> buffer = - new GraphicBuffer(static_cast<uint32_t>(bufferWidth), - static_cast<uint32_t>(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888, - 1, - GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | - GRALLOC_USAGE_HW_TEXTURE, - "RefreshRateOverlayBuffer"); + const auto kUsageFlags = + static_cast<uint64_t>(GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | + GRALLOC_USAGE_HW_TEXTURE); + sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth), + static_cast<uint32_t>(bufferHeight), + HAL_PIXEL_FORMAT_RGBA_8888, 1u, + kUsageFlags, "RefreshRateOverlayBuffer"); const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d", diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 2487dbd793..8dd3b0f59d 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -132,7 +132,7 @@ RegionSamplingThread::~RegionSamplingThread() { void RegionSamplingThread::addListener(const Rect& samplingArea, const wp<Layer>& stopLayer, const sp<IRegionSamplingListener>& listener) { sp<IBinder> asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(this); + asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); std::lock_guard lock(mSamplingMutex); mDescriptors.emplace(wp<IBinder>(asBinder), Descriptor{samplingArea, stopLayer, listener}); } @@ -203,25 +203,14 @@ float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t st return 0.0f; } - // (b/133849373) ROT_90 screencap images produced upside down - auto area = sample_area; - if (orientation & ui::Transform::ROT_90) { - area.top = height - area.top; - area.bottom = height - area.bottom; - std::swap(area.top, area.bottom); - - area.left = width - area.left; - area.right = width - area.right; - std::swap(area.left, area.right); - } - - const uint32_t pixelCount = (area.bottom - area.top) * (area.right - area.left); + const uint32_t pixelCount = + (sample_area.bottom - sample_area.top) * (sample_area.right - sample_area.left); uint32_t accumulatedLuma = 0; // Calculates luma with approximation of Rec. 709 primaries - for (int32_t row = area.top; row < area.bottom; ++row) { + for (int32_t row = sample_area.top; row < sample_area.bottom; ++row) { const uint32_t* rowBase = data + row * stride; - for (int32_t column = area.left; column < area.right; ++column) { + for (int32_t column = sample_area.left; column < sample_area.right; ++column) { uint32_t pixel = rowBase[column]; const uint32_t r = pixel & 0xFF; const uint32_t g = (pixel >> 8) & 0xFF; @@ -344,8 +333,8 @@ void RegionSamplingThread::captureSample() { const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; sp<GraphicBuffer> graphicBuffer = - new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), - PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); + sp<GraphicBuffer>::make(sampledBounds.getWidth(), sampledBounds.getHeight(), + PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); const status_t bufferStatus = graphicBuffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d", bufferStatus); diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp index 5de796d742..5bd8a99361 100644 --- a/services/surfaceflinger/Scheduler/Android.bp +++ b/services/surfaceflinger/Scheduler/Android.bp @@ -18,6 +18,7 @@ cc_defaults { "libbase", "libcutils", "liblog", + "libui", "libutils", ], } @@ -39,6 +40,7 @@ cc_library_static { name: "libscheduler", defaults: ["libscheduler_defaults"], srcs: [ + "src/PresentLatencyTracker.cpp", "src/Timer.cpp", ], local_include_dirs: ["include"], @@ -50,6 +52,7 @@ cc_test { test_suites: ["device-tests"], defaults: ["libscheduler_defaults"], srcs: [ + "tests/PresentLatencyTrackerTest.cpp", "tests/TimerTest.cpp", ], static_libs: [ diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 639ba5a3f1..d3f53c11e4 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -157,9 +157,9 @@ DisplayEventReceiver::Event makeFrameRateOverrideFlushEvent(PhysicalDisplayId di } // namespace -EventThreadConnection::EventThreadConnection( - EventThread* eventThread, uid_t callingUid, ResyncCallback resyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration) +EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid, + ResyncCallback resyncCallback, + EventRegistrationFlags eventRegistration) : resyncCallback(std::move(resyncCallback)), mOwnerUid(callingUid), mEventRegistration(eventRegistration), @@ -173,7 +173,7 @@ EventThreadConnection::~EventThreadConnection() { void EventThreadConnection::onFirstRef() { // NOTE: mEventThread doesn't hold a strong reference on us - mEventThread->registerDisplayEventConnection(this); + mEventThread->registerDisplayEventConnection(sp<EventThreadConnection>::fromExisting(this)); } binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) { @@ -188,20 +188,22 @@ binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChann } binder::Status EventThreadConnection::setVsyncRate(int rate) { - mEventThread->setVsyncRate(static_cast<uint32_t>(rate), this); + mEventThread->setVsyncRate(static_cast<uint32_t>(rate), + sp<EventThreadConnection>::fromExisting(this)); return binder::Status::ok(); } binder::Status EventThreadConnection::requestNextVsync() { ATRACE_CALL(); - mEventThread->requestNextVsync(this); + mEventThread->requestNextVsync(sp<EventThreadConnection>::fromExisting(this)); return binder::Status::ok(); } binder::Status EventThreadConnection::getLatestVsyncEventData( ParcelableVsyncEventData* outVsyncEventData) { ATRACE_CALL(); - outVsyncEventData->vsync = mEventThread->getLatestVsyncEventData(this); + outVsyncEventData->vsync = + mEventThread->getLatestVsyncEventData(sp<EventThreadConnection>::fromExisting(this)); return binder::Status::ok(); } @@ -288,11 +290,10 @@ void EventThread::setDuration(std::chrono::nanoseconds workDuration, } sp<EventThreadConnection> EventThread::createEventConnection( - ResyncCallback resyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration) const { - return new EventThreadConnection(const_cast<EventThread*>(this), - IPCThreadState::self()->getCallingUid(), - std::move(resyncCallback), eventRegistration); + ResyncCallback resyncCallback, EventRegistrationFlags eventRegistration) const { + return sp<EventThreadConnection>::make(const_cast<EventThread*>(this), + IPCThreadState::self()->getCallingUid(), + std::move(resyncCallback), eventRegistration); } status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) { @@ -553,7 +554,7 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: { return connection->mEventRegistration.test( - ISurfaceComposer::EventRegistration::modeChanged); + gui::ISurfaceComposer::EventRegistration::modeChanged); } case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: @@ -586,7 +587,7 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, [[fallthrough]]; case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH: return connection->mEventRegistration.test( - ISurfaceComposer::EventRegistration::frameRateOverride); + gui::ISurfaceComposer::EventRegistration::frameRateOverride); default: return false; diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index adb96fd462..d85d140fc0 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -92,7 +92,7 @@ public: class EventThreadConnection : public gui::BnDisplayEventConnection { public: EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + EventRegistrationFlags eventRegistration = {}); virtual ~EventThreadConnection(); virtual status_t postEvent(const DisplayEventReceiver::Event& event); @@ -107,7 +107,7 @@ public: VSyncRequest vsyncRequest = VSyncRequest::None; const uid_t mOwnerUid; - const ISurfaceComposer::EventRegistrationFlags mEventRegistration; + const EventRegistrationFlags mEventRegistration; private: virtual void onFirstRef(); @@ -123,8 +123,7 @@ public: virtual ~EventThread(); virtual sp<EventThreadConnection> createEventConnection( - ResyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) const = 0; + ResyncCallback, EventRegistrationFlags eventRegistration = {}) const = 0; // called before the screen is turned off from main thread virtual void onScreenReleased() = 0; @@ -171,8 +170,7 @@ public: ~EventThread(); sp<EventThreadConnection> createEventConnection( - ResyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) const override; + ResyncCallback, EventRegistrationFlags eventRegistration = {}) const override; status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override; void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 5f64efa3d1..ae111c3d45 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -72,6 +72,20 @@ void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } + +LayerHistory::LayerVoteType getVoteType(LayerInfo::FrameRateCompatibility compatibility, + bool contentDetectionEnabled) { + LayerHistory::LayerVoteType voteType; + if (!contentDetectionEnabled || compatibility == LayerInfo::FrameRateCompatibility::NoVote) { + voteType = LayerHistory::LayerVoteType::NoVote; + } else if (compatibility == LayerInfo::FrameRateCompatibility::Min) { + voteType = LayerHistory::LayerVoteType::Min; + } else { + voteType = LayerHistory::LayerVoteType::Heuristic; + } + return voteType; +} + } // namespace LayerHistory::LayerHistory() @@ -81,10 +95,12 @@ LayerHistory::LayerHistory() LayerHistory::~LayerHistory() = default; -void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) { +void LayerHistory::registerLayer(Layer* layer, bool contentDetectionEnabled) { std::lock_guard lock(mLock); LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound, "%s already registered", layer->getName().c_str()); + LayerVoteType type = + getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled); auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type); // The layer can be placed on either map, it is assumed that partitionLayers() will be called @@ -132,6 +148,22 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, } } +void LayerHistory::setDefaultFrameRateCompatibility(Layer* layer, bool contentDetectionEnabled) { + std::lock_guard lock(mLock); + auto id = layer->getSequence(); + + auto [found, layerPair] = findLayer(id); + if (found == LayerStatus::NotFound) { + // Offscreen layer + ALOGV("%s: %s not registered", __func__, layer->getName().c_str()); + return; + } + + const auto& info = layerPair->second; + info->setDefaultLayerVote( + getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled)); +} + auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary { Summary summary; @@ -203,6 +235,8 @@ void LayerHistory::partitionLayers(nsecs_t now) { switch (frameRate.type) { case Layer::FrameRateCompatibility::Default: return LayerVoteType::ExplicitDefault; + case Layer::FrameRateCompatibility::Min: + return LayerVoteType::Min; case Layer::FrameRateCompatibility::ExactOrMultiple: return LayerVoteType::ExplicitExactOrMultiple; case Layer::FrameRateCompatibility::NoVote: diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 7b6096f7f3..12bec8dfc1 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -45,7 +45,7 @@ public: ~LayerHistory(); // Layers are unregistered when the weak reference expires. - void registerLayer(Layer*, LayerVoteType type); + void registerLayer(Layer*, bool contentDetectionEnabled); // Sets the display size. Client is responsible for synchronization. void setDisplayArea(uint32_t displayArea) { mDisplayArea = displayArea; } @@ -63,6 +63,10 @@ public: // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType); + // Updates the default frame rate compatibility which takes effect when the app + // does not set a preference for refresh rate. + void setDefaultFrameRateCompatibility(Layer*, bool contentDetectionEnabled); + using Summary = std::vector<RefreshRateConfigs::LayerRequirement>; // Rebuilds sets of active/inactive layers, and accumulates stats for active layers. diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 8a3b0b97e4..28cb24a64f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -74,6 +74,8 @@ public: enum class FrameRateCompatibility { Default, // Layer didn't specify any specific handling strategy + Min, // Layer needs the minimum frame rate. + Exact, // Layer needs the exact frame rate. ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index f2af85e94a..e4e65b4828 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -30,11 +30,11 @@ namespace android::impl { -void MessageQueue::Handler::dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime) { +void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) { if (!mFramePending.exchange(true)) { mVsyncId = vsyncId; mExpectedVsyncTime = expectedVsyncTime; - mQueue.mLooper->sendMessage(this, Message()); + mQueue.mLooper->sendMessage(sp<MessageHandler>::fromExisting(this), Message()); } } @@ -44,16 +44,7 @@ bool MessageQueue::Handler::isFramePending() const { void MessageQueue::Handler::handleMessage(const Message&) { mFramePending.store(false); - - const nsecs_t frameTime = systemTime(); - auto& compositor = mQueue.mCompositor; - - if (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) { - return; - } - - compositor.composite(frameTime, mVsyncId); - compositor.sample(); + mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime); } MessageQueue::MessageQueue(ICompositor& compositor) @@ -102,16 +93,17 @@ void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, ns // Trace VSYNC-sf mVsync.value = (mVsync.value + 1) % 2; + const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime); { std::lock_guard lock(mVsync.mutex); - mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime); + mVsync.lastCallbackTime = expectedVsyncTime; mVsync.scheduledFrameTime.reset(); } - const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions( - {targetWakeupTime, readyTime, vsyncTime}); + const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions( + {targetWakeupTime, readyTime, vsyncTime})}; - mHandler->dispatchFrame(vsyncId, vsyncTime); + mHandler->dispatchFrame(vsyncId, expectedVsyncTime); } void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch, @@ -133,9 +125,10 @@ void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) { std::lock_guard lock(mVsync.mutex); mVsync.workDuration = workDuration; if (mVsync.scheduledFrameTime) { - mVsync.scheduledFrameTime = mVsync.registration->schedule( - {mVsync.workDuration.get().count(), - /*readyDuration=*/0, mVsync.lastCallbackTime.count()}); + mVsync.scheduledFrameTime = + mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), + .readyDuration = 0, + .earliestVsync = mVsync.lastCallbackTime.ns()}); } } @@ -165,13 +158,26 @@ void MessageQueue::postMessage(sp<MessageHandler>&& handler) { mLooper->sendMessage(handler, Message()); } +void MessageQueue::scheduleConfigure() { + struct ConfigureHandler : MessageHandler { + explicit ConfigureHandler(ICompositor& compositor) : compositor(compositor) {} + + void handleMessage(const Message&) override { compositor.configure(); } + + ICompositor& compositor; + }; + + // TODO(b/241285876): Batch configure tasks that happen within some duration. + postMessage(sp<ConfigureHandler>::make(mCompositor)); +} + void MessageQueue::scheduleFrame() { ATRACE_CALL(); { std::lock_guard lock(mInjector.mutex); if (CC_UNLIKELY(mInjector.connection)) { - ALOGD("%s while injecting VSYNC", __FUNCTION__); + ALOGD("%s while injecting VSYNC", __func__); mInjector.connection->requestNextVsync(); return; } @@ -181,7 +187,7 @@ void MessageQueue::scheduleFrame() { mVsync.scheduledFrameTime = mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), .readyDuration = 0, - .earliestVsync = mVsync.lastCallbackTime.count()}); + .earliestVsync = mVsync.lastCallbackTime.ns()}); } void MessageQueue::injectorCallback() { @@ -190,9 +196,10 @@ void MessageQueue::injectorCallback() { while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) { for (int i = 0; i < n; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - auto& vsync = buffer[i].vsync; - mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(), - vsync.vsyncData.preferredExpectedPresentationTime()); + auto& vsync = buffer[i].vsync.vsyncData; + mHandler->dispatchFrame(VsyncId{vsync.preferredVsyncId()}, + TimePoint::fromNs( + vsync.preferredExpectedPresentationTime())); break; } } diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index 4082e26874..899233a151 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -25,8 +25,12 @@ #include <android/gui/IDisplayEventConnection.h> #include <private/gui/BitTube.h> #include <utils/Looper.h> +#include <utils/StrongPointer.h> #include <utils/Timers.h> +#include <scheduler/Time.h> +#include <scheduler/VsyncId.h> + #include "EventThread.h" #include "TracedOrdinal.h" #include "VSyncDispatch.h" @@ -34,8 +38,9 @@ namespace android { struct ICompositor { - virtual bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) = 0; - virtual void composite(nsecs_t frameTime, int64_t vsyncId) = 0; + virtual void configure() = 0; + virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0; + virtual void composite(TimePoint frameTime, VsyncId) = 0; virtual void sample() = 0; protected: @@ -47,6 +52,9 @@ class Task : public MessageHandler { template <typename G> friend auto makeTask(G&&); + template <typename... Args> + friend sp<Task<F>> sp<Task<F>>::make(Args&&... args); + explicit Task(F&& f) : mTask(std::move(f)) {} void handleMessage(const Message&) override { mTask(); } @@ -57,7 +65,7 @@ class Task : public MessageHandler { template <typename F> inline auto makeTask(F&& f) { - sp<Task<F>> task = new Task<F>(std::move(f)); + sp<Task<F>> task = sp<Task<F>>::make(std::forward<F>(f)); return std::make_pair(task, task->mTask.get_future()); } @@ -71,6 +79,7 @@ public: virtual void setInjector(sp<EventThreadConnection>) = 0; virtual void waitMessage() = 0; virtual void postMessage(sp<MessageHandler>&&) = 0; + virtual void scheduleConfigure() = 0; virtual void scheduleFrame() = 0; using Clock = std::chrono::steady_clock; @@ -84,8 +93,9 @@ protected: class Handler : public MessageHandler { MessageQueue& mQueue; std::atomic_bool mFramePending = false; - std::atomic<int64_t> mVsyncId = 0; - std::atomic<nsecs_t> mExpectedVsyncTime = 0; + + std::atomic<VsyncId> mVsyncId; + std::atomic<TimePoint> mExpectedVsyncTime; public: explicit Handler(MessageQueue& queue) : mQueue(queue) {} @@ -93,7 +103,7 @@ protected: bool isFramePending() const; - virtual void dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime); + virtual void dispatchFrame(VsyncId, TimePoint expectedVsyncTime); }; friend class Handler; @@ -104,6 +114,8 @@ protected: void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime); private: + virtual void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) = 0; + ICompositor& mCompositor; const sp<Looper> mLooper; const sp<Handler> mHandler; @@ -115,7 +127,7 @@ private: mutable std::mutex mutex; TracedOrdinal<std::chrono::nanoseconds> workDuration GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)}; - std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0}; + TimePoint lastCallbackTime GUARDED_BY(mutex); std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex); TracedOrdinal<int> value = {"VSYNC-sf", 0}; }; @@ -142,6 +154,7 @@ public: void waitMessage() override; void postMessage(sp<MessageHandler>&&) override; + void scheduleConfigure() override; void scheduleFrame() override; std::optional<Clock::time_point> getScheduledFrameTime() const override; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index a48c921378..3cb052c4e3 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -27,6 +27,7 @@ #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <ftl/enum.h> +#include <ftl/fake_guard.h> #include <utils/Trace.h> #include "../SurfaceFlingerProperties.h" @@ -47,24 +48,6 @@ struct RefreshRateScore { } fixedRateBelowThresholdLayersScore; }; -template <typename Iterator> -const DisplayModePtr& getMaxScoreRefreshRate(Iterator begin, Iterator end) { - const auto it = - std::max_element(begin, end, [](RefreshRateScore max, RefreshRateScore current) { - const auto& [modeIt, overallScore, _] = current; - - std::string name = to_string(modeIt->second->getFps()); - ALOGV("%s scores %.2f", name.c_str(), overallScore); - - ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100))); - - constexpr float kEpsilon = 0.0001f; - return overallScore > max.overallScore * (1 + kEpsilon); - }); - - return it->modeIt->second; -} - constexpr RefreshRateConfigs::GlobalSignals kNoSignals; std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) { @@ -136,6 +119,34 @@ bool canModesSupportFrameRateOverride(const std::vector<DisplayModeIterator>& so } // namespace +struct RefreshRateConfigs::RefreshRateScoreComparator { + bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const { + const auto& [modeIt, overallScore, _] = lhs; + + std::string name = to_string(modeIt->second->getFps()); + ALOGV("%s sorting scores %.2f", name.c_str(), overallScore); + + ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100))); + + constexpr float kEpsilon = 0.0001f; + if (std::abs(overallScore - rhs.overallScore) > kEpsilon) { + return overallScore > rhs.overallScore; + } + + // If overallScore tie we will pick the higher refresh rate if + // high refresh rate is the priority else the lower refresh rate. + if (refreshRateOrder == RefreshRateOrder::Descending) { + using fps_approx_ops::operator>; + return modeIt->second->getFps() > rhs.modeIt->second->getFps(); + } else { + using fps_approx_ops::operator<; + return modeIt->second->getFps() < rhs.modeIt->second->getFps(); + } + } + + const RefreshRateOrder refreshRateOrder; +}; + std::string RefreshRateConfigs::Policy::toString() const { return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s" ", primaryRange=%s, appRequestRange=%s}", @@ -217,6 +228,13 @@ float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerR return 0; } +float RefreshRateConfigs::calculateRefreshRateScoreForFps(Fps refreshRate) const { + const float ratio = + refreshRate.getValue() / mAppRequestRefreshRates.back()->second->getFps().getValue(); + // Use ratio^2 to get a lower score the more we get further from peak + return ratio * ratio; +} + float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate, bool isSeamlessSwitch) const { // Slightly prefer seamless switches. @@ -225,10 +243,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { - const auto& maxRefreshRate = mAppRequestRefreshRates.back()->second; - const auto ratio = refreshRate.getValue() / maxRefreshRate->getFps().getValue(); - // use ratio^2 to get a lower score the more we get further from peak - return ratio * ratio; + return calculateRefreshRateScoreForFps(refreshRate); } if (layer.vote == LayerVoteType::ExplicitExact) { @@ -257,35 +272,43 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye kNonExactMatchingPenalty; } -auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers, - GlobalSignals signals) const - -> std::pair<DisplayModePtr, GlobalSignals> { +auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers, + GlobalSignals signals) const + -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { std::lock_guard lock(mLock); - if (mGetBestRefreshRateCache && - mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) { - return mGetBestRefreshRateCache->result; + if (mGetRankedRefreshRatesCache && + mGetRankedRefreshRatesCache->arguments == std::make_pair(layers, signals)) { + return mGetRankedRefreshRatesCache->result; } - const auto result = getBestRefreshRateLocked(layers, signals); - mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result}; + const auto result = getRankedRefreshRatesLocked(layers, signals); + mGetRankedRefreshRatesCache = GetRankedRefreshRatesCache{{layers, signals}, result}; return result; } -auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers, - GlobalSignals signals) const - -> std::pair<DisplayModePtr, GlobalSignals> { +auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers, + GlobalSignals signals) const + -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { using namespace fps_approx_ops; ATRACE_CALL(); ALOGV("%s: %zu layers", __func__, layers.size()); + const auto& activeMode = *getActiveModeItLocked()->second; + + // Keep the display at max refresh rate for the duration of powering on the display. + if (signals.powerOnImminent) { + ALOGV("Power On Imminent"); + return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending), + GlobalSignals{.powerOnImminent = true}}; + } + int noVoteLayers = 0; int minVoteLayers = 0; int maxVoteLayers = 0; int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; int explicitExact = 0; - float maxExplicitWeight = 0; int seamedFocusedLayers = 0; for (const auto& layer : layers) { @@ -301,15 +324,12 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire break; case LayerVoteType::ExplicitDefault: explicitDefaultVoteLayers++; - maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::ExplicitExactOrMultiple: explicitExactOrMultipleVoteLayers++; - maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::ExplicitExact: explicitExact++; - maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::Heuristic: break; @@ -325,6 +345,7 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire const Policy* policy = getCurrentPolicyLocked(); const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); + // If the default mode group is different from the group of current mode, // this means a layer requesting a seamed mode switch just disappeared and // we should switch back to the default group. @@ -332,14 +353,14 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire // of the current mode, in order to prevent unnecessary seamed mode switches // (e.g. when pausing a video playback). const auto anchorGroup = - seamedFocusedLayers > 0 ? mActiveModeIt->second->getGroup() : defaultMode->getGroup(); + seamedFocusedLayers > 0 ? activeMode.getGroup() : defaultMode->getGroup(); // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. if (signals.touch && !hasExplicitVoteLayers) { - const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); - ALOGV("TouchBoost - choose %s", to_string(max->getFps()).c_str()); - return {max, GlobalSignals{.touch = true}}; + ALOGV("Touch Boost"); + return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), + GlobalSignals{.touch = true}}; } // If the primary range consists of a single refresh rate then we can only @@ -349,22 +370,22 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire isApproxEqual(policy->primaryRange.min, policy->primaryRange.max); if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { - const DisplayModePtr& min = getMinRefreshRateByPolicyLocked(); - ALOGV("Idle - choose %s", to_string(min->getFps()).c_str()); - return {min, GlobalSignals{.idle = true}}; + ALOGV("Idle"); + return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending), + GlobalSignals{.idle = true}}; } if (layers.empty() || noVoteLayers == layers.size()) { - const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); - ALOGV("no layers with votes - choose %s", to_string(max->getFps()).c_str()); - return {max, kNoSignals}; + ALOGV("No layers with votes"); + return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), + kNoSignals}; } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { - const DisplayModePtr& min = getMinRefreshRateByPolicyLocked(); - ALOGV("all layers Min - choose %s", to_string(min->getFps()).c_str()); - return {min, kNoSignals}; + ALOGV("All layers Min"); + return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending), + kNoSignals}; } // Find the best refresh rate based on score @@ -387,12 +408,12 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) { const auto& [id, mode] = *modeIt; - const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup(); + const bool isSeamlessSwitch = mode->getGroup() == activeMode.getGroup(); if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) { ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s", formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(), - to_string(*mActiveModeIt->second).c_str()); + to_string(activeMode).c_str()); continue; } @@ -401,7 +422,7 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed." " Current mode = %s", formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(), - to_string(*mActiveModeIt->second).c_str()); + to_string(activeMode).c_str()); continue; } @@ -413,7 +434,7 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire const bool isInPolicyForDefault = mode->getGroup() == anchorGroup; if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) { ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(), - to_string(*mode).c_str(), to_string(*mActiveModeIt->second).c_str()); + to_string(*mode).c_str(), to_string(activeMode).c_str()); continue; } @@ -511,22 +532,29 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire } // Now that we scored all the refresh rates we need to pick the one that got the highest - // overallScore. In case of a tie we will pick the higher refresh rate if any of the layers - // wanted Max, or the lower otherwise. - const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0 - ? getMaxScoreRefreshRate(scores.rbegin(), scores.rend()) - : getMaxScoreRefreshRate(scores.begin(), scores.end()); + // overallScore. Sort the scores based on their overallScore in descending order of priority. + const RefreshRateOrder refreshRateOrder = + maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending; + std::sort(scores.begin(), scores.end(), + RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder}); + std::vector<RefreshRateRanking> rankedRefreshRates; + rankedRefreshRates.reserve(scores.size()); + + std::transform(scores.begin(), scores.end(), back_inserter(rankedRefreshRates), + [](const RefreshRateScore& score) { + return RefreshRateRanking{score.modeIt->second, score.overallScore}; + }); if (primaryRangeIsSingleRate) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { return score.overallScore == 0; })) { - const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); - ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str()); - return {max, kNoSignals}; + ALOGV("Layers not scored"); + return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), + kNoSignals}; } else { - return {bestRefreshRate, kNoSignals}; + return {rankedRefreshRates, kNoSignals}; } } @@ -534,8 +562,6 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit // vote we should not change it if we get a touch event. Only apply touch boost if it will // actually increase the refresh rate over the normal selection. - const DisplayModePtr& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); - const bool touchBoostForExplicitExact = [&] { if (mSupportsFrameRateOverrideByContent) { // Enable touch boost if there are other layers besides exact @@ -546,15 +572,18 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire } }(); + const auto& touchRefreshRates = + getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && - bestRefreshRate->getFps() < touchRefreshRate->getFps()) { - ALOGV("TouchBoost - choose %s", to_string(touchRefreshRate->getFps()).c_str()); - return {touchRefreshRate, GlobalSignals{.touch = true}}; + scores.front().modeIt->second->getFps() < + touchRefreshRates.front().displayModePtr->getFps()) { + ALOGV("Touch Boost"); + return {touchRefreshRates, GlobalSignals{.touch = true}}; } - return {bestRefreshRate, kNoSignals}; + return {rankedRefreshRates, kNoSignals}; } std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> @@ -659,11 +688,13 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr continue; } - // Now that we scored all the refresh rates we need to pick the one that got the highest - // score. + // Now that we scored all the refresh rates we need to pick the lowest refresh rate + // that got the highest score. const DisplayModePtr& bestRefreshRate = - getMaxScoreRefreshRate(scores.begin(), scores.end()); - + std::min_element(scores.begin(), scores.end(), + RefreshRateScoreComparator{.refreshRateOrder = + RefreshRateOrder::Ascending}) + ->modeIt->second; frameRateOverrides.emplace(uid, bestRefreshRate->getFps()); } @@ -676,7 +707,7 @@ std::optional<Fps> RefreshRateConfigs::onKernelTimerChanged( const DisplayModePtr& current = desiredActiveModeId ? mDisplayModes.get(*desiredActiveModeId)->get() - : mActiveModeIt->second; + : getActiveModeItLocked()->second; const DisplayModePtr& min = mMinRefreshRateModeIt->second; if (current == min) { @@ -688,26 +719,22 @@ std::optional<Fps> RefreshRateConfigs::onKernelTimerChanged( } const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const { + const auto& activeMode = *getActiveModeItLocked()->second; + for (const DisplayModeIterator modeIt : mPrimaryRefreshRates) { const auto& mode = modeIt->second; - if (mActiveModeIt->second->getGroup() == mode->getGroup()) { + if (activeMode.getGroup() == mode->getGroup()) { return mode; } } - ALOGE("Can't find min refresh rate by policy with the same mode group" - " as the current mode %s", - to_string(*mActiveModeIt->second).c_str()); + ALOGE("Can't find min refresh rate by policy with the same mode group as the current mode %s", + to_string(activeMode).c_str()); // Default to the lowest refresh rate. return mPrimaryRefreshRates.front()->second; } -DisplayModePtr RefreshRateConfigs::getMaxRefreshRateByPolicy() const { - std::lock_guard lock(mLock); - return getMaxRefreshRateByPolicyLocked(); -} - const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) { const auto& mode = (*it)->second; @@ -716,25 +743,63 @@ const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int an } } - ALOGE("Can't find max refresh rate by policy with the same mode group" - " as the current mode %s", - to_string(*mActiveModeIt->second).c_str()); + ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup); // Default to the highest refresh rate. return mPrimaryRefreshRates.back()->second; } -DisplayModePtr RefreshRateConfigs::getActiveMode() const { +std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked( + std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const { + std::vector<RefreshRateRanking> rankings; + const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) { + const auto& mode = it->second; + const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending); + const float score = calculateRefreshRateScoreForFps(mode->getFps()); + if (!anchorGroupOpt || mode->getGroup() == anchorGroupOpt) { + rankings.push_back(RefreshRateRanking{mode, inverseScore ? 1.0f / score : score}); + } + }; + + if (refreshRateOrder == RefreshRateOrder::Ascending) { + std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), makeRanking); + } else { + std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), makeRanking); + } + + if (!rankings.empty() || !anchorGroupOpt) { + return rankings; + } + + ALOGW("Can't find %s refresh rate by policy with the same mode group" + " as the mode group %d", + refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value()); + + return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder); +} + +DisplayModePtr RefreshRateConfigs::getActiveModePtr() const { std::lock_guard lock(mLock); - return mActiveModeIt->second; + return getActiveModeItLocked()->second; +} + +const DisplayMode& RefreshRateConfigs::getActiveMode() const { + // Reads from kMainThreadContext do not require mLock. + ftl::FakeGuard guard(mLock); + return *mActiveModeIt->second; +} + +DisplayModeIterator RefreshRateConfigs::getActiveModeItLocked() const { + // Reads under mLock do not require kMainThreadContext. + return FTL_FAKE_GUARD(kMainThreadContext, mActiveModeIt); } void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) { std::lock_guard lock(mLock); - // Invalidate the cached invocation to getBestRefreshRate. This forces - // the refresh rate to be recomputed on the next call to getBestRefreshRate. - mGetBestRefreshRateCache.reset(); + // Invalidate the cached invocation to getRankedRefreshRates. This forces + // the refresh rate to be recomputed on the next call to getRankedRefreshRates. + mGetRankedRefreshRatesCache.reset(); mActiveModeIt = mDisplayModes.find(modeId); LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); @@ -744,7 +809,7 @@ RefreshRateConfigs::RefreshRateConfigs(DisplayModes modes, DisplayModeId activeM Config config) : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) { initializeIdleTimer(); - updateDisplayModes(std::move(modes), activeModeId); + FTL_FAKE_GUARD(kMainThreadContext, updateDisplayModes(std::move(modes), activeModeId)); } void RefreshRateConfigs::initializeIdleTimer() { @@ -769,9 +834,9 @@ void RefreshRateConfigs::initializeIdleTimer() { void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) { std::lock_guard lock(mLock); - // Invalidate the cached invocation to getBestRefreshRate. This forces - // the refresh rate to be recomputed on the next call to getBestRefreshRate. - mGetBestRefreshRateCache.reset(); + // Invalidate the cached invocation to getRankedRefreshRates. This forces + // the refresh rate to be recomputed on the next call to getRankedRefreshRates. + mGetRankedRefreshRatesCache.reset(); mDisplayModes = std::move(modes); mActiveModeIt = mDisplayModes.find(activeModeId); @@ -815,7 +880,7 @@ status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str()); return BAD_VALUE; } - mGetBestRefreshRateCache.reset(); + mGetRankedRefreshRatesCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mDisplayManagerPolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { @@ -830,7 +895,7 @@ status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& poli if (policy && !isPolicyValidLocked(*policy)) { return BAD_VALUE; } - mGetBestRefreshRateCache.reset(); + mGetRankedRefreshRatesCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mOverridePolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { @@ -930,7 +995,8 @@ RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction return KernelIdleTimerAction::TurnOff; } - const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked(); + const DisplayModePtr& maxByPolicy = + getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); if (minByPolicy == maxByPolicy) { // Turn on the timer when the min of the primary range is below the device min. if (const Policy* currentPolicy = getCurrentPolicyLocked(); @@ -976,7 +1042,7 @@ void RefreshRateConfigs::dump(std::string& result) const { std::lock_guard lock(mLock); - const auto activeModeId = mActiveModeIt->first; + const auto activeModeId = getActiveModeItLocked()->first; result += " activeModeId="s; result += std::to_string(activeModeId.value()); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index a79002e959..0642fcbd14 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -31,6 +31,7 @@ #include "DisplayHardware/HWComposer.h" #include "Scheduler/OneShotTimer.h" #include "Scheduler/StrongTyping.h" +#include "ThreadContext.h" namespace android::scheduler { @@ -43,6 +44,15 @@ inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs)); } +struct RefreshRateRanking { + DisplayModePtr displayModePtr; + float score = 0.0f; + + bool operator==(const RefreshRateRanking& ranking) const { + return displayModePtr == ranking.displayModePtr && score == ranking.score; + } +}; + using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; /** @@ -184,15 +194,19 @@ public: bool touch = false; // True if the system hasn't seen any buffers posted to layers recently. bool idle = false; + // Whether the display is about to be powered on, or has been in PowerMode::ON + // within the timeout of DisplayPowerTimer. + bool powerOnImminent = false; bool operator==(GlobalSignals other) const { - return touch == other.touch && idle == other.idle; + return touch == other.touch && idle == other.idle && + powerOnImminent == other.powerOnImminent; } }; - // Returns the refresh rate that best fits the given layers, and whether the refresh rate was - // chosen based on touch boost and/or idle timer. - std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRate( + // Returns the list in the descending order of refresh rates desired + // based on their overall score, and the GlobalSignals that were considered. + std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRates( const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { @@ -203,12 +217,11 @@ public: std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const EXCLUDES(mLock); - // Returns the highest refresh rate according to the current policy. May change at runtime. Only - // uses the primary range, not the app request range. - DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock); + void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext); - void setActiveModeId(DisplayModeId) EXCLUDES(mLock); - DisplayModePtr getActiveMode() const EXCLUDES(mLock); + // See mActiveModeIt for thread safety. + DisplayModePtr getActiveModePtr() const EXCLUDES(mLock); + const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext); // Returns a known frame rate that is the closest to frameRate Fps findClosestKnownFrameRate(Fps frameRate) const; @@ -332,7 +345,10 @@ private: void constructAvailableRefreshRates() REQUIRES(mLock); - std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRateLocked( + // See mActiveModeIt for thread safety. + DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); + + std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRatesLocked( const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); // Returns number of display frames and remainder when dividing the layer refresh period by @@ -346,13 +362,22 @@ private: // Returns the highest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); - const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) { - return getMaxRefreshRateByPolicyLocked(mActiveModeIt->second->getGroup()); - } + + struct RefreshRateScoreComparator; + + enum class RefreshRateOrder { Ascending, Descending }; + + // Returns the rankings in RefreshRateOrder. May change at runtime. + // Only uses the primary range, not the app request range. + std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked(std::optional<int> anchorGroupOpt, + RefreshRateOrder) const + REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); + // Returns the refresh rate score as a ratio to max refresh rate, which has a score of 1. + float calculateRefreshRateScoreForFps(Fps refreshRate) const REQUIRES(mLock); // calculates a score for a layer. Used to determine the display refresh rate // and the frame rate override for certains applications. float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, @@ -361,7 +386,8 @@ private: float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const REQUIRES(mLock); - void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock); + void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock) + REQUIRES(kMainThreadContext); void initializeIdleTimer(); @@ -377,7 +403,10 @@ private: // is also dependent, so must be reset as well. DisplayModes mDisplayModes GUARDED_BY(mLock); - DisplayModeIterator mActiveModeIt GUARDED_BY(mLock); + // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext + // need not be under mLock. + DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext); + DisplayModeIterator mMinRefreshRateModeIt GUARDED_BY(mLock); DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock); @@ -397,11 +426,11 @@ private: const Config mConfig; bool mSupportsFrameRateOverrideByContent; - struct GetBestRefreshRateCache { + struct GetRankedRefreshRatesCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; - std::pair<DisplayModePtr, GlobalSignals> result; + std::pair<std::vector<RefreshRateRanking>, GlobalSignals> result; }; - mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock); + mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache GUARDED_BY(mLock); // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. std::mutex mIdleTimerCallbacksMutex; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 727cb0817e..6d68bac8e2 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -28,7 +28,6 @@ #include <ftl/fake_guard.h> #include <gui/WindowInfo.h> #include <system/window.h> -#include <ui/DisplayStatInfo.h> #include <utils/Timers.h> #include <utils/Trace.h> @@ -132,6 +131,18 @@ void Scheduler::run() { } } +void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, + TimePoint expectedVsyncTime) { + const TimePoint frameTime = SchedulerClock::now(); + + if (!compositor.commit(frameTime, vsyncId, expectedVsyncTime)) { + return; + } + + compositor.composite(frameTime, vsyncId); + compositor.sample(); +} + void Scheduler::createVsyncSchedule(FeatureFlags features) { mVsyncSchedule.emplace(features); } @@ -152,28 +163,27 @@ std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent); } -bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { +bool Scheduler::isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const { const auto frameRate = getFrameRateOverride(uid); if (!frameRate.has_value()) { return true; } - return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp, *frameRate); + return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp.ns(), *frameRate); } impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { std::scoped_lock lock(mRefreshRateConfigsLock); return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) { - return !isVsyncValid(expectedVsyncTimestamp, uid); + return !isVsyncValid(TimePoint::fromNs(expectedVsyncTimestamp), uid); }; } impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const { return [this](uid_t uid) { - const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps(); - const auto currentPeriod = - mVsyncSchedule->getTracker().currentPeriod() ?: refreshRate.getPeriodNsecs(); + const Fps refreshRate = holdRefreshRateConfigs()->getActiveModePtr()->getFps(); + const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs(); const auto frameRate = getFrameRateOverride(uid); if (!frameRate.has_value()) { @@ -214,12 +224,12 @@ ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventT } sp<EventThreadConnection> Scheduler::createConnectionInternal( - EventThread* eventThread, ISurfaceComposer::EventRegistrationFlags eventRegistration) { + EventThread* eventThread, EventRegistrationFlags eventRegistration) { return eventThread->createEventConnection([&] { resync(); }, eventRegistration); } sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection( - ConnectionHandle handle, ISurfaceComposer::EventRegistrationFlags eventRegistration) { + ConnectionHandle handle, EventRegistrationFlags eventRegistration) { std::lock_guard<std::mutex> lock(mConnectionsLock); RETURN_IF_INVALID_HANDLE(handle, nullptr); return createConnectionInternal(mConnections[handle].thread.get(), eventRegistration); @@ -310,7 +320,7 @@ void Scheduler::dispatchCachedReportedMode() { // mode change is in progress. In that case we shouldn't dispatch an event // as it will be dispatched when the current mode changes. if (std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->getActiveMode() != mPolicy.mode) { + mRefreshRateConfigs->getActiveModePtr() != mPolicy.mode) { return; } @@ -361,12 +371,6 @@ void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds wo thread->setDuration(workDuration, readyDuration); } -DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) { - const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom(now); - const auto vsyncPeriod = mVsyncSchedule->getTracker().currentPeriod(); - return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod}; -} - ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { if (mInjectVSyncs == enable) { return {}; @@ -449,7 +453,7 @@ void Scheduler::resync() { if (now - last > kIgnoreDelay) { const auto refreshRate = [&] { std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getActiveMode()->getFps(); + return mRefreshRateConfigs->getActiveModePtr()->getFps(); }(); resyncToHardwareVsync(false, refreshRate); } @@ -497,24 +501,10 @@ void Scheduler::addPresentFence(std::shared_ptr<FenceTime> fence) { } void Scheduler::registerLayer(Layer* layer) { - using WindowType = gui::WindowInfo::Type; - - scheduler::LayerHistory::LayerVoteType voteType; - - if (!mFeatures.test(Feature::kContentDetection) || - layer->getWindowType() == WindowType::STATUS_BAR) { - voteType = scheduler::LayerHistory::LayerVoteType::NoVote; - } else if (layer->getWindowType() == WindowType::WALLPAPER) { - // Running Wallpaper at Min is considered as part of content detection. - voteType = scheduler::LayerHistory::LayerVoteType::Min; - } else { - voteType = scheduler::LayerHistory::LayerVoteType::Heuristic; - } - // If the content detection feature is off, we still keep the layer history, // since we use it for other features (like Frame Rate API), so layers // still need to be registered. - mLayerHistory.registerLayer(layer, voteType); + mLayerHistory.registerLayer(layer, mFeatures.test(Feature::kContentDetection)); } void Scheduler::deregisterLayer(Layer* layer) { @@ -535,6 +525,11 @@ void Scheduler::setModeChangePending(bool pending) { mLayerHistory.setModeChangePending(pending); } +void Scheduler::setDefaultFrameRateCompatibility(Layer* layer) { + mLayerHistory.setDefaultFrameRateCompatibility(layer, + mFeatures.test(Feature::kContentDetection)); +} + void Scheduler::chooseRefreshRateForContent() { const auto configs = holdRefreshRateConfigs(); if (!configs->canSwitch()) return; @@ -582,7 +577,7 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { // magic number const Fps refreshRate = [&] { std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getActiveMode()->getFps(); + return mRefreshRateConfigs->getActiveModePtr()->getFps(); }(); constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz; @@ -679,7 +674,9 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals if (currentState == newState) return {}; currentState = std::forward<T>(newState); - std::tie(newMode, consideredSignals) = chooseDisplayMode(); + const auto [rankings, signals] = getRankedDisplayModes(); + newMode = rankings.front().displayModePtr; + consideredSignals = signals; frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); if (mPolicy.mode == newMode) { @@ -704,31 +701,28 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals return consideredSignals; } -auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> { +auto Scheduler::getRankedDisplayModes() + -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { ATRACE_CALL(); const auto configs = holdRefreshRateConfigs(); - // If Display Power is not in normal operation we want to be in performance mode. When coming - // back to normal mode, a grace period is given with DisplayPowerTimer. - if (mDisplayPowerTimer && - (mPolicy.displayPowerMode != hal::PowerMode::ON || - mPolicy.displayPowerTimer == TimerState::Reset)) { - constexpr GlobalSignals kNoSignals; - return {configs->getMaxRefreshRateByPolicy(), kNoSignals}; - } + const bool powerOnImminent = mDisplayPowerTimer && + (mPolicy.displayPowerMode != hal::PowerMode::ON || + mPolicy.displayPowerTimer == TimerState::Reset); const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active, - .idle = mPolicy.idleTimer == TimerState::Expired}; + .idle = mPolicy.idleTimer == TimerState::Expired, + .powerOnImminent = powerOnImminent}; - return configs->getBestRefreshRate(mPolicy.contentRequirements, signals); + return configs->getRankedRefreshRates(mPolicy.contentRequirements, signals); } DisplayModePtr Scheduler::getPreferredDisplayMode() { std::lock_guard<std::mutex> lock(mPolicyLock); // Make sure the stored mode is up to date. if (mPolicy.mode) { - mPolicy.mode = chooseDisplayMode().first; + mPolicy.mode = getRankedDisplayModes().first.front().displayModePtr; } return mPolicy.mode; } @@ -776,11 +770,4 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid mFrameRateOverrideMappings.setPreferredRefreshRateForUid(frameRateOverride); } -std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom( - nsecs_t expectedPresentTime) const { - const auto presentTime = std::chrono::nanoseconds(expectedPresentTime); - const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule->getTracker().currentPeriod()); - return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod); -} - } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index a8043bf94c..f567205631 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -33,6 +33,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include <scheduler/Features.h> +#include <scheduler/Time.h> #include "EventThread.h" #include "FrameRateOverrideMappings.h" @@ -94,8 +95,8 @@ protected: ~ISchedulerCallback() = default; }; -class Scheduler : impl::MessageQueue { - using Impl = impl::MessageQueue; +class Scheduler : android::impl::MessageQueue { + using Impl = android::impl::MessageQueue; public: Scheduler(ICompositor&, ISchedulerCallback&, FeatureFlags); @@ -115,6 +116,7 @@ public: using Impl::getScheduledFrameTime; using Impl::setDuration; + using Impl::scheduleConfigure; using Impl::scheduleFrame; // Schedule an asynchronous or synchronous task on the main thread. @@ -128,10 +130,10 @@ public: ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, - impl::EventThread::InterceptVSyncsCallback); + android::impl::EventThread::InterceptVSyncsCallback); sp<IDisplayEventConnection> createDisplayEventConnection( - ConnectionHandle, ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + ConnectionHandle, EventRegistrationFlags eventRegistration = {}); sp<EventThreadConnection> getEventConnection(ConnectionHandle); @@ -148,8 +150,6 @@ public: void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration); - DisplayStatInfo getDisplayStatInfo(nsecs_t now); - // Returns injector handle if injection has toggled, or an invalid handle otherwise. ConnectionHandle enableVSyncInjection(bool enable); // Returns false if injection is disabled. @@ -176,6 +176,7 @@ public: void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) EXCLUDES(mRefreshRateConfigsLock); void setModeChangePending(bool pending); + void setDefaultFrameRateCompatibility(Layer*); void deregisterLayer(Layer*); // Detects content using layer history, and selects a matching refresh rate. @@ -188,13 +189,11 @@ public: void setDisplayPowerMode(hal::PowerMode powerMode); - VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); } + VsyncSchedule& getVsyncSchedule() { return *mVsyncSchedule; } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid - bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const; - - std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const; + bool isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const; void dump(std::string&) const; void dump(ConnectionHandle, std::string&) const; @@ -230,7 +229,7 @@ public: nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getActiveMode()->getFps().getPeriodNsecs(); + return mRefreshRateConfigs->getActiveModePtr()->getFps().getPeriodNsecs(); } // Returns the framerate of the layer with the given sequence ID @@ -245,10 +244,13 @@ private: enum class TimerState { Reset, Expired }; enum class TouchState { Inactive, Active }; + // impl::MessageQueue overrides: + void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override; + // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr<EventThread>); sp<EventThreadConnection> createConnectionInternal( - EventThread*, ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + EventThread*, EventRegistrationFlags eventRegistration = {}); // Update feature state machine to given state when corresponding timer resets or expires. void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateConfigsLock); @@ -267,16 +269,18 @@ private: template <typename S, typename T> GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock); - // Returns the display mode that fulfills the policy, and the signals that were considered. - std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock); + // Returns the list of display modes in descending order of their priority that fulfills the + // policy, and the signals that were considered. + std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedDisplayModes() + REQUIRES(mPolicyLock); bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); - impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const + android::impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const EXCLUDES(mRefreshRateConfigsLock); - impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; + android::impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; std::shared_ptr<RefreshRateConfigs> holdRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index 27f43115c1..cc9f7cfaaa 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -100,14 +100,8 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTim return getExpectedCallbackTime(nextVsyncTime, timing); } - bool const alreadyDispatchedForVsync = mLastDispatchTime && - ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime && - (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime); - if (alreadyDispatchedForVsync) { - nextVsyncTime = - tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance); - nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration; - } + nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime); + nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration; auto const nextReadyTime = nextVsyncTime - timing.readyDuration; mScheduleTiming = timing; @@ -123,6 +117,25 @@ bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const { return mWorkloadUpdateInfo.has_value(); } +nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker, + nsecs_t nextVsyncTime) const { + bool const alreadyDispatchedForVsync = mLastDispatchTime && + ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime && + (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime); + const nsecs_t currentPeriod = tracker.currentPeriod(); + bool const nextVsyncTooClose = mLastDispatchTime && + (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod; + if (alreadyDispatchedForVsync) { + return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance); + } + + if (nextVsyncTooClose) { + return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod); + } + + return nextVsyncTime; +} + void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { if (!mArmedInfo && !mWorkloadUpdateInfo) { return; @@ -136,7 +149,9 @@ void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration; const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync); - const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(earliestVsync); + const auto nextVsyncTime = + adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/ + tracker.nextAnticipatedVSyncTimeFrom(earliestVsync)); const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration; const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration; diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index 4923031098..4f2f87a7d2 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -84,6 +84,8 @@ public: void dump(std::string& result) const; private: + nsecs_t adjustVsyncIfNeeded(VSyncTracker& tracker, nsecs_t nextVsyncTime) const; + const std::string mName; const VSyncDispatch::Callback mCallback; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 77782e9c72..898e86578a 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -167,7 +167,9 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { vsyncTS[i] = timestamp; meanTS += timestamp; - const auto ordinal = (vsyncTS[i] + currentPeriod / 2) / currentPeriod * kScalingFactor; + const auto ordinal = currentPeriod == 0 + ? 0 + : (vsyncTS[i] + currentPeriod / 2) / currentPeriod * kScalingFactor; ordinals[i] = ordinal; meanOrdinal += ordinal; } diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp index be57b2acd7..138d8d65f7 100644 --- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp @@ -53,14 +53,14 @@ VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(Transactio case Schedule::EarlyStart: if (token) { mEarlyWakeupRequests.emplace(token); - token->linkToDeath(this); + token->linkToDeath(sp<DeathRecipient>::fromExisting(this)); } else { ALOGW("%s: EarlyStart requested without a valid token", __func__); } break; case Schedule::EarlyEnd: { if (token && mEarlyWakeupRequests.erase(token) > 0) { - token->unlinkToDeath(this); + token->unlinkToDeath(sp<DeathRecipient>::fromExisting(this)); } else { ALOGW("%s: Unexpected EarlyEnd", __func__); } diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp index 3a918a1660..95bc31f239 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp @@ -68,6 +68,14 @@ VsyncSchedule::VsyncSchedule(TrackerPtr tracker, DispatchPtr dispatch, Controlle VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default; VsyncSchedule::~VsyncSchedule() = default; +Period VsyncSchedule::period() const { + return Period::fromNs(mTracker->currentPeriod()); +} + +TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const { + return TimePoint::fromNs(mTracker->nextAnticipatedVSyncTimeFrom(timePoint.ns())); +} + void VsyncSchedule::dump(std::string& out) const { out.append("VsyncController:\n"); mController->dump(out); diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h index 0d9b114875..8c17409b02 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.h +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -20,6 +20,7 @@ #include <string> #include <scheduler/Features.h> +#include <scheduler/Time.h> namespace android::scheduler { @@ -38,6 +39,9 @@ public: VsyncSchedule(VsyncSchedule&&); ~VsyncSchedule(); + Period period() const; + TimePoint vsyncDeadlineAfter(TimePoint) const; + // TODO(b/185535769): Hide behind API. const VsyncTracker& getTracker() const { return *mTracker; } VsyncTracker& getTracker() { return *mTracker; } diff --git a/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h b/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h new file mode 100644 index 0000000000..23ae83fc4b --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#pragma once + +#include <memory> +#include <queue> +#include <utility> + +#include <scheduler/Time.h> + +namespace android { + +class FenceTime; + +namespace scheduler { + +// Computes composite-to-present latency by tracking recently composited frames pending to present. +class PresentLatencyTracker { +public: + // For tests. + static constexpr size_t kMaxPendingFrames = 4; + + // Returns the present latency of the latest frame. + Duration trackPendingFrame(TimePoint compositeTime, + std::shared_ptr<FenceTime> presentFenceTime); + +private: + struct PendingFrame { + PendingFrame(TimePoint compositeTime, std::shared_ptr<FenceTime> presentFenceTime) + : compositeTime(compositeTime), presentFenceTime(std::move(presentFenceTime)) {} + + const TimePoint compositeTime; + const std::shared_ptr<FenceTime> presentFenceTime; + }; + + std::queue<PendingFrame> mPendingFrames; +}; + +} // namespace scheduler +} // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Time.h b/services/surfaceflinger/Scheduler/include/scheduler/Time.h new file mode 100644 index 0000000000..2ca55d41ee --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/Time.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#pragma once + +#include <chrono> + +#include <utils/Timers.h> + +namespace android { +namespace scheduler { + +// TODO(b/185535769): Pull Clock.h to libscheduler to reuse this. +using SchedulerClock = std::chrono::high_resolution_clock; +static_assert(SchedulerClock::is_steady); + +} // namespace scheduler + +struct Duration; + +struct TimePoint : scheduler::SchedulerClock::time_point { + constexpr TimePoint() = default; + explicit constexpr TimePoint(const Duration&); + + // Implicit conversion from std::chrono counterpart. + constexpr TimePoint(scheduler::SchedulerClock::time_point p) + : scheduler::SchedulerClock::time_point(p) {} + + static constexpr TimePoint fromNs(nsecs_t); + + static TimePoint now() { return scheduler::SchedulerClock::now(); }; + + nsecs_t ns() const; +}; + +struct Duration : TimePoint::duration { + // Implicit conversion from std::chrono counterpart. + template <typename R, typename P> + constexpr Duration(std::chrono::duration<R, P> d) : TimePoint::duration(d) {} + + static constexpr Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; } + + nsecs_t ns() const { return std::chrono::nanoseconds(*this).count(); } +}; + +using Period = Duration; + +constexpr TimePoint::TimePoint(const Duration& d) : scheduler::SchedulerClock::time_point(d) {} + +constexpr TimePoint TimePoint::fromNs(nsecs_t ns) { + return TimePoint(Duration::fromNs(ns)); +} + +inline nsecs_t TimePoint::ns() const { + return Duration(time_since_epoch()).ns(); +} + +// Shorthand to convert the tick count of a Duration to Period and Rep. For example: +// +// const auto i = ticks<std::ratio<1>>(d); // Integer seconds. +// const auto f = ticks<std::milli, float>(d); // Floating-point milliseconds. +// +template <typename Period, typename Rep = Duration::rep> +constexpr Rep ticks(Duration d) { + using D = std::chrono::duration<Rep, Period>; + return std::chrono::duration_cast<D>(d).count(); +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h b/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h new file mode 100644 index 0000000000..c64a3cdc6f --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#pragma once + +#include <cstdint> + +namespace android { + +// TODO(b/185536303): Import StrongTyping.h into FTL so it can be used here. + +// Sequential frame identifier, also known as FrameTimeline token. +struct VsyncId { + int64_t value = -1; +}; + +inline bool operator==(VsyncId lhs, VsyncId rhs) { + return lhs.value == rhs.value; +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp b/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp new file mode 100644 index 0000000000..8f3e0818f8 --- /dev/null +++ b/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp @@ -0,0 +1,56 @@ +/* + * 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 <scheduler/PresentLatencyTracker.h> + +#include <cutils/compiler.h> +#include <log/log.h> +#include <ui/FenceTime.h> + +namespace android::scheduler { + +Duration PresentLatencyTracker::trackPendingFrame(TimePoint compositeTime, + std::shared_ptr<FenceTime> presentFenceTime) { + Duration presentLatency = Duration::zero(); + while (!mPendingFrames.empty()) { + const auto& pendingFrame = mPendingFrames.front(); + const auto presentTime = + TimePoint::fromNs(pendingFrame.presentFenceTime->getCachedSignalTime()); + + if (presentTime == TimePoint::fromNs(Fence::SIGNAL_TIME_PENDING)) { + break; + } + + if (presentTime == TimePoint::fromNs(Fence::SIGNAL_TIME_INVALID)) { + ALOGE("%s: Invalid present fence", __func__); + } else { + presentLatency = presentTime - pendingFrame.compositeTime; + } + + mPendingFrames.pop(); + } + + mPendingFrames.emplace(compositeTime, std::move(presentFenceTime)); + + if (CC_UNLIKELY(mPendingFrames.size() > kMaxPendingFrames)) { + ALOGE("%s: Too many pending frames", __func__); + mPendingFrames.pop(); + } + + return presentLatency; +} + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp new file mode 100644 index 0000000000..8952ca99ab --- /dev/null +++ b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp @@ -0,0 +1,81 @@ +/* + * 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 <gtest/gtest.h> + +#include <algorithm> +#include <array> + +#include <scheduler/PresentLatencyTracker.h> +#include <ui/FenceTime.h> + +namespace android::scheduler { +namespace { + +using FencePair = std::pair<sp<Fence>, std::shared_ptr<FenceTime>>; + +FencePair makePendingFence(FenceToFenceTimeMap& fenceMap) { + const auto fence = sp<Fence>::make(); + return {fence, fenceMap.createFenceTimeForTest(fence)}; +} + +} // namespace + +TEST(PresentLatencyTrackerTest, skipsInvalidFences) { + PresentLatencyTracker tracker; + + const TimePoint kCompositeTime = TimePoint::fromNs(999); + EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero()); + EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero()); + EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero()); + + FenceToFenceTimeMap fenceMap; + const auto [fence, fenceTime] = makePendingFence(fenceMap); + EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero()); + + fenceTime->signalForTest(9999); + + EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), + Duration::fromNs(9000)); +} + +TEST(PresentLatencyTrackerTest, tracksPendingFrames) { + PresentLatencyTracker tracker; + + FenceToFenceTimeMap fenceMap; + std::array<FencePair, PresentLatencyTracker::kMaxPendingFrames> fences; + std::generate(fences.begin(), fences.end(), [&fenceMap] { return makePendingFence(fenceMap); }); + + // The present latency is 0 if all fences are pending. + const TimePoint kCompositeTime = TimePoint::fromNs(1234); + for (const auto& [fence, fenceTime] : fences) { + EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero()); + } + + // If multiple frames have been presented... + constexpr size_t kPresentCount = fences.size() / 2; + for (size_t i = 0; i < kPresentCount; i++) { + fences[i].second->signalForTest(kCompositeTime.ns() + static_cast<nsecs_t>(i)); + } + + const auto fence = makePendingFence(fenceMap); + + // ...then the present latency is measured using the latest frame. + constexpr Duration kPresentLatency = Duration::fromNs(static_cast<nsecs_t>(kPresentCount) - 1); + EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fence.second), kPresentLatency); +} + +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f1479912d8..7d3fc98578 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -30,6 +30,7 @@ #include <android-base/strings.h> #include <android/configuration.h> #include <android/gui/IDisplayEventConnection.h> +#include <android/gui/StaticDisplayInfo.h> #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/types.h> @@ -52,9 +53,11 @@ #include <configstore/Utils.h> #include <cutils/compiler.h> #include <cutils/properties.h> +#include <ftl/algorithm.h> #include <ftl/fake_guard.h> #include <ftl/future.h> -#include <ftl/small_map.h> +#include <ftl/unit.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> #include <gui/IProducerListener.h> @@ -103,12 +106,9 @@ #include <ui/DisplayIdentification.h> #include "BackgroundExecutor.h" -#include "BufferLayer.h" -#include "BufferQueueLayer.h" -#include "BufferStateLayer.h" #include "Client.h" #include "Colorizer.h" -#include "ContainerLayer.h" +#include "Display/DisplayMap.h" #include "DisplayDevice.h" #include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/FramebufferSurface.h" @@ -117,7 +117,6 @@ #include "DisplayHardware/PowerAdvisor.h" #include "DisplayHardware/VirtualDisplaySurface.h" #include "DisplayRenderArea.h" -#include "EffectLayer.h" #include "Effects/Daltonizer.h" #include "FlagManager.h" #include "FpsReporter.h" @@ -128,7 +127,6 @@ #include "LayerProtoHelper.h" #include "LayerRenderArea.h" #include "LayerVector.h" -#include "MonitoredProducer.h" #include "MutexUtils.h" #include "NativeWindowSurface.h" #include "RefreshRateOverlay.h" @@ -154,8 +152,13 @@ #define NO_THREAD_SAFETY_ANALYSIS \ _Pragma("GCC error \"Prefer <ftl/fake_guard.h> or MutexUtils.h helpers.\"") +// To enable layer borders in the system, change the below flag to true. +#undef DOES_CONTAIN_BORDER +#define DOES_CONTAIN_BORDER false + namespace android { +using namespace std::chrono_literals; using namespace std::string_literals; using namespace hardware::configstore; @@ -169,10 +172,15 @@ using CompositionStrategyPredictionState = android::compositionengine::impl:: OutputCompositionState::CompositionStrategyPredictionState; using base::StringAppendF; +using display::PhysicalDisplay; +using display::PhysicalDisplays; using gui::DisplayInfo; +using gui::GameMode; using gui::IDisplayEventConnection; using gui::IWindowInfosListener; +using gui::LayerMetadata; using gui::WindowInfo; +using gui::aidl_utils::binderStatusFromStatusT; using ui::ColorMode; using ui::Dataspace; using ui::DisplayPrimaries; @@ -273,6 +281,8 @@ const String16 sInternalSystemWindow("android.permission.INTERNAL_SYSTEM_WINDOW" const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled"; +static const int MAX_TRACING_MEMORY = 1024 * 1024 * 1024; // 1GB + // --------------------------------------------------------------------------- int64_t SurfaceFlinger::dispSyncPresentTimeOffset; bool SurfaceFlinger::useHwcForRgbToYuv; @@ -327,11 +337,11 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)), mCompositionEngine(mFactory.createCompositionEngine()), mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), - mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()), + mTunnelModeEnabledReporter(sp<TunnelModeEnabledReporter>::make()), mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)), - mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) { + mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make()) { ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); } @@ -402,7 +412,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.sf.blurs_are_expensive", value, "0"); mBlursAreExpensive = atoi(value); - const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS; + const size_t defaultListSize = MAX_LAYERS; auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize)); mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize; mGraphicBufferProducerListSizeLogThreshold = @@ -452,14 +462,14 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { - if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) { - return LatchUnsignaledConfig::Always; - } - if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) { return LatchUnsignaledConfig::AutoSingleLayer; } + if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) { + return LatchUnsignaledConfig::Always; + } + return LatchUnsignaledConfig::Disabled; } @@ -470,7 +480,8 @@ void SurfaceFlinger::binderDied(const wp<IBinder>&) { mBootFinished = false; // Sever the link to inputflinger since it's gone as well. - static_cast<void>(mScheduler->schedule([=] { mInputFlinger = nullptr; })); + static_cast<void>(mScheduler->schedule( + [this] { mInputFlinger.clear(); })); // restore initial conditions (default device unblank, etc) initializeDisplays(); @@ -483,11 +494,6 @@ void SurfaceFlinger::run() { mScheduler->run(); } -sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { - const sp<Client> client = new Client(this); - return client->initCheck() == NO_ERROR ? client : nullptr; -} - sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secure) { // onTransact already checks for some permissions, but adding an additional check here. // This is to ensure that only system and graphics can request to create a secure @@ -503,7 +509,7 @@ sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secur virtual ~DisplayToken() { // no more references, this display must be terminated Mutex::Autolock _l(flinger->mStateLock); - flinger->mCurrentState.displays.removeItem(this); + flinger->mCurrentState.displays.removeItem(wp<IBinder>::fromExisting(this)); flinger->setTransactionFlags(eDisplayTransactionNeeded); } public: @@ -512,7 +518,7 @@ sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secur } }; - sp<BBinder> token = new DisplayToken(this); + sp<BBinder> token = sp<DisplayToken>::make(sp<SurfaceFlinger>::fromExisting(this)); Mutex::Autolock _l(mStateLock); // Display ID is assigned when virtual display is allocated by HWC. @@ -590,12 +596,12 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { std::vector<PhysicalDisplayId> displayIds; - displayIds.reserve(mPhysicalDisplayTokens.size()); + displayIds.reserve(mPhysicalDisplays.size()); const auto defaultDisplayId = getDefaultDisplayDeviceLocked()->getPhysicalId(); displayIds.push_back(defaultDisplayId); - for (const auto& [id, token] : mPhysicalDisplayTokens) { + for (const auto& [id, display] : mPhysicalDisplays) { if (id != defaultDisplayId) { displayIds.push_back(id); } @@ -604,10 +610,10 @@ std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() con return displayIds; } -status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const { - Mutex::Autolock lock(mStateLock); - *id = getPrimaryDisplayIdLocked(); - return NO_ERROR; +std::optional<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdLocked( + const sp<display::DisplayToken>& displayToken) const { + return ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_key<PhysicalDisplays>); } sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const { @@ -660,7 +666,7 @@ void SurfaceFlinger::bootFinished() { const String16 name("window"); mWindowManager = defaultServiceManager()->getService(name); if (mWindowManager != 0) { - mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); + mWindowManager->linkToDeath(sp<IBinder::DeathRecipient>::fromExisting(this)); } // stop boot animation @@ -674,7 +680,7 @@ void SurfaceFlinger::bootFinished() { sp<IBinder> input(defaultServiceManager()->getService(String16("inputflinger"))); - static_cast<void>(mScheduler->schedule([=] { + static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(kMainThreadContext) { if (input == nullptr) { ALOGE("Failed to link to input service"); } else { @@ -702,8 +708,9 @@ void SurfaceFlinger::bootFinished() { mBootStage = BootStage::FINISHED; - if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) { - FTL_FAKE_GUARD(mStateLock, enableRefreshRateOverlay(true)); + if (base::GetBoolProperty("sf.debug.show_refresh_rate_overlay"s, false)) { + ftl::FakeGuard guard(mStateLock); + enableRefreshRateOverlay(true); } })); } @@ -765,10 +772,10 @@ chooseRenderEngineTypeViaSysProp() { // Do not call property_set on main thread which will be blocked by init // Use StartPropertySetThread instead. -void SurfaceFlinger::init() { +void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); // Get a RenderEngine for the given display / config (can't fail) // TODO(b/77156734): We need to stop casting and use HAL types when possible. @@ -807,13 +814,36 @@ void SurfaceFlinger::init() { enableHalVirtualDisplays(true); } - // Process any initial hotplug and resulting display changes. - processDisplayHotplugEventsLocked(); - const auto display = getDefaultDisplayDeviceLocked(); - LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback."); - const auto displayId = display->getPhysicalId(); - LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId), - "Primary display is disconnected."); + // Process hotplug for displays connected at boot. + LOG_ALWAYS_FATAL_IF(!configureLocked(), + "Initial display configuration failed: HWC did not hotplug"); + + // Commit primary display. + sp<const DisplayDevice> display; + if (const auto indexOpt = mCurrentState.getDisplayIndex(getPrimaryDisplayIdLocked())) { + const auto& displays = mCurrentState.displays; + + const auto& token = displays.keyAt(*indexOpt); + const auto& state = displays.valueAt(*indexOpt); + + processDisplayAdded(token, state); + mDrawingState.displays.add(token, state); + + display = getDefaultDisplayDeviceLocked(); + } + + LOG_ALWAYS_FATAL_IF(!display, "Failed to configure the primary display"); + LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getPhysicalId()), + "Primary display is disconnected"); + + // TODO(b/241285876): The Scheduler needlessly depends on creating the CompositionEngine part of + // the DisplayDevice, hence the above commit of the primary display. Remove that special case by + // initializing the Scheduler after configureLocked, once decoupled from DisplayDevice. + initScheduler(display); + dispatchDisplayHotplugEvent(display->getPhysicalId(), true); + + // Commit secondary display(s). + processDisplayChangesLocked(); // initialize our drawing state mDrawingState = mCurrentState; @@ -881,17 +911,6 @@ void SurfaceFlinger::startBootAnim() { // ---------------------------------------------------------------------------- -bool SurfaceFlinger::authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const { - Mutex::Autolock _l(mStateLock); - return authenticateSurfaceTextureLocked(bufferProducer); -} - -bool SurfaceFlinger::authenticateSurfaceTextureLocked( - const sp<IGraphicBufferProducer>& /* bufferProducer */) const { - return false; -} - status_t SurfaceFlinger::getSupportedFrameTimestamps( std::vector<FrameEvent>* outSupported) const { *outSupported = { @@ -943,16 +962,19 @@ status_t SurfaceFlinger::getStaticDisplayInfo(const sp<IBinder>& displayToken, Mutex::Autolock lock(mStateLock); - const auto display = getDisplayDeviceLocked(displayToken); - if (!display) { + const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>) + .and_then(getDisplayDeviceAndSnapshot()); + + if (!displayOpt) { return NAME_NOT_FOUND; } - if (const auto connectionType = display->getConnectionType()) - info->connectionType = *connectionType; - else { - return INVALID_OPERATION; - } + const auto& [display, snapshotRef] = *displayOpt; + const auto& snapshot = snapshotRef.get(); + + info->connectionType = snapshot.connectionType(); + info->deviceProductInfo = snapshot.deviceProductInfo(); if (mEmulatedDisplayDensity) { info->density = mEmulatedDisplayDensity; @@ -964,7 +986,6 @@ status_t SurfaceFlinger::getStaticDisplayInfo(const sp<IBinder>& displayToken, info->density /= ACONFIGURATION_DENSITY_MEDIUM; info->secure = display->isSecure(); - info->deviceProductInfo = display->getDeviceProductInfo(); info->installOrientation = display->getPhysicalOrientation(); return NO_ERROR; @@ -978,23 +999,22 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, Mutex::Autolock lock(mStateLock); - const auto display = getDisplayDeviceLocked(displayToken); - if (!display) { + const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>) + .and_then(getDisplayDeviceAndSnapshot()); + if (!displayOpt) { return NAME_NOT_FOUND; } - const auto displayId = PhysicalDisplayId::tryCast(display->getId()); - if (!displayId) { - return INVALID_OPERATION; - } + const auto& [display, snapshotRef] = *displayOpt; + const auto& snapshot = snapshotRef.get(); - info->activeDisplayModeId = display->getActiveMode()->getId().value(); + const auto& displayModes = snapshot.displayModes(); - const auto& supportedModes = display->getSupportedModes(); info->supportedDisplayModes.clear(); - info->supportedDisplayModes.reserve(supportedModes.size()); + info->supportedDisplayModes.reserve(displayModes.size()); - for (const auto& [id, mode] : supportedModes) { + for (const auto& [id, mode] : displayModes) { ui::DisplayMode outMode; outMode.id = static_cast<int32_t>(id.value()); @@ -1038,21 +1058,24 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, info->supportedDisplayModes.push_back(outMode); } + const PhysicalDisplayId displayId = snapshot.displayId(); + + info->activeDisplayModeId = display->refreshRateConfigs().getActiveModePtr()->getId().value(); info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; - info->supportedColorModes = getDisplayColorModes(*display); + info->supportedColorModes = getDisplayColorModes(displayId); info->hdrCapabilities = display->getHdrCapabilities(); info->autoLowLatencyModeSupported = - getHwComposer().hasDisplayCapability(*displayId, + getHwComposer().hasDisplayCapability(displayId, DisplayCapability::AUTO_LOW_LATENCY_MODE); info->gameContentTypeSupported = - getHwComposer().supportsContentType(*displayId, hal::ContentType::GAME); + getHwComposer().supportsContentType(displayId, hal::ContentType::GAME); info->preferredBootDisplayMode = static_cast<ui::DisplayModeId>(-1); if (getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG)) { - if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(*displayId)) { - if (const auto modeId = display->translateModeId(*hwcId)) { + if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(displayId)) { + if (const auto modeId = snapshot.translateModeId(*hwcId)) { info->preferredBootDisplayMode = modeId->value(); } } @@ -1061,12 +1084,14 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, return NO_ERROR; } -status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* stats) { - if (!stats) { +status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* outStats) { + if (!outStats) { return BAD_VALUE; } - *stats = mScheduler->getDisplayStatInfo(systemTime()); + const auto& schedule = mScheduler->getVsyncSchedule(); + outStats->vsyncTime = schedule.vsyncDeadlineAfter(TimePoint::now()).ns(); + outStats->vsyncPeriod = schedule.period().ns(); return NO_ERROR; } @@ -1098,39 +1123,44 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { } } -status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int modeId) { +status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToken>& displayToken, + DisplayModeId modeId) { ATRACE_CALL(); if (!displayToken) { return BAD_VALUE; } + const char* const whence = __func__; auto future = mScheduler->schedule([=]() -> status_t { - const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken)); - if (!display) { - ALOGE("Attempt to set allowed display modes for invalid display token %p", - displayToken.get()); + const auto displayOpt = + FTL_FAKE_GUARD(mStateLock, + ftl::find_if(mPhysicalDisplays, + PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>) + .and_then(getDisplayDeviceAndSnapshot())); + if (!displayOpt) { + ALOGE("%s: Invalid physical display token %p", whence, displayToken.get()); return NAME_NOT_FOUND; } - if (display->isVirtual()) { - ALOGW("Attempt to set allowed display modes for virtual display"); - return INVALID_OPERATION; - } + const auto& [display, snapshotRef] = *displayOpt; + const auto& snapshot = snapshotRef.get(); - const auto mode = display->getMode(DisplayModeId{modeId}); - if (!mode) { - ALOGW("Attempt to switch to an unsupported mode %d.", modeId); + const auto fpsOpt = snapshot.displayModes().get(modeId).transform( + [](const DisplayModePtr& mode) { return mode->getFps(); }); + + if (!fpsOpt) { + ALOGE("%s: Invalid mode %d for display %s", whence, modeId.value(), + to_string(snapshot.displayId()).c_str()); return BAD_VALUE; } - const auto fps = mode->getFps(); + const Fps fps = *fpsOpt; // Keep the old switching type. - const auto allowGroupSwitching = + const bool allowGroupSwitching = display->refreshRateConfigs().getCurrentPolicy().allowGroupSwitching; - const scheduler::RefreshRateConfigs::Policy policy{mode->getId(), - allowGroupSwitching, - {fps, fps}}; + const scheduler::RefreshRateConfigs::Policy policy{modeId, allowGroupSwitching, {fps, fps}}; constexpr bool kOverridePolicy = false; return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy); @@ -1147,16 +1177,14 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { return; } - const auto upcomingModeInfo = - FTL_FAKE_GUARD(kMainThreadContext, display->getUpcomingActiveMode()); - + const auto upcomingModeInfo = display->getUpcomingActiveMode(); if (!upcomingModeInfo.mode) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. return; } - if (display->getActiveMode()->getResolution() != upcomingModeInfo.mode->getResolution()) { + if (display->getActiveMode().getResolution() != upcomingModeInfo.mode->getResolution()) { auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). @@ -1168,9 +1196,12 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { return; } - // We just created this display so we can call even if we are not on the main thread. - ftl::FakeGuard guard(kMainThreadContext); - display->setActiveMode(upcomingModeInfo.mode->getId()); + mPhysicalDisplays.get(display->getPhysicalId()) + .transform(&PhysicalDisplay::snapshotRef) + .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) { + FTL_FAKE_GUARD(kMainThreadContext, + display->setActiveMode(upcomingModeInfo.mode->getId(), snapshot)); + })); const Fps refreshRate = upcomingModeInfo.mode->getFps(); mRefreshRateStats->setRefreshRate(refreshRate); @@ -1200,12 +1231,16 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { std::optional<PhysicalDisplayId> displayToUpdateImmediately; - for (const auto& iter : mDisplays) { - const auto& display = iter.second; - if (!display || !display->isInternal()) { + for (const auto& [id, physical] : mPhysicalDisplays) { + const auto& snapshot = physical.snapshot(); + + if (snapshot.connectionType() != ui::DisplayConnectionType::Internal) { continue; } + const auto display = getDisplayDeviceLocked(id); + if (!display) continue; + // Store the local variable to release the lock. const auto desiredActiveMode = display->getDesiredActiveMode(); if (!desiredActiveMode) { @@ -1219,20 +1254,23 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { continue; } - const auto desiredMode = display->getMode(desiredActiveMode->mode->getId()); - if (!desiredMode) { + const auto desiredModeId = desiredActiveMode->mode->getId(); + const auto refreshRateOpt = + snapshot.displayModes() + .get(desiredModeId) + .transform([](const DisplayModePtr& mode) { return mode->getFps(); }); + + if (!refreshRateOpt) { ALOGW("Desired display mode is no longer supported. Mode ID = %d", - desiredActiveMode->mode->getId().value()); + desiredModeId.value()); clearDesiredActiveModeState(display); continue; } - const auto refreshRate = desiredMode->getFps(); - ALOGV("%s changing active mode to %d(%s) for display %s", __func__, - desiredMode->getId().value(), to_string(refreshRate).c_str(), - to_string(display->getId()).c_str()); + ALOGV("%s changing active mode to %d(%s) for display %s", __func__, desiredModeId.value(), + to_string(*refreshRateOpt).c_str(), to_string(display->getId()).c_str()); - if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { + if (display->getActiveMode().getId() == desiredModeId) { // we are already in the requested mode, there is nothing left to do desiredActiveModeChangeDone(display); continue; @@ -1241,8 +1279,7 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { // Desired active mode was set, it is different than the mode currently in use, however // allowed modes might have changed by the time we process the refresh. // Make sure the desired mode is still allowed - const auto displayModeAllowed = - display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId()); + const auto displayModeAllowed = display->refreshRateConfigs().isModeAllowed(desiredModeId); if (!displayModeAllowed) { clearDesiredActiveModeState(display); continue; @@ -1254,9 +1291,8 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; - const auto status = FTL_FAKE_GUARD(kMainThreadContext, - display->initiateModeChange(*desiredActiveMode, - constraints, &outTimeline)); + const auto status = + display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline); if (status != NO_ERROR) { // initiateModeChange may fail if a hotplug event is just about @@ -1283,7 +1319,7 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately); const auto desiredActiveMode = display->getDesiredActiveMode(); if (desiredActiveMode && - display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { + display->getActiveMode().getId() == desiredActiveMode->mode->getId()) { desiredActiveModeChangeDone(display); } } @@ -1304,15 +1340,18 @@ void SurfaceFlinger::disableExpensiveRendering() { future.wait(); } -std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) { - auto modes = getHwComposer().getColorModes(display.getPhysicalId()); +std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) { + auto modes = getHwComposer().getColorModes(displayId); + + const bool isInternalDisplay = mPhysicalDisplays.get(displayId) + .transform(&PhysicalDisplay::isInternal) + .value_or(false); // If the display is internal and the configuration claims it's not wide color capable, // filter out all wide color modes. The typical reason why this happens is that the // hardware is not good enough to support GPU composition of wide color, and thus the // OEMs choose to disable this capability. - if (display.getConnectionType() == ui::DisplayConnectionType::Internal && - !hasWideColorDisplay) { + if (isInternalDisplay && !hasWideColorDisplay) { const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode); modes.erase(newEnd, modes.end()); } @@ -1328,13 +1367,13 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayTok Mutex::Autolock lock(mStateLock); - const auto display = getDisplayDeviceLocked(displayToken); + const auto display = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>); if (!display) { return NAME_NOT_FOUND; } - const auto connectionType = display->getConnectionType(); - if (connectionType != ui::DisplayConnectionType::Internal) { + if (!display.transform(&PhysicalDisplay::isInternal).value()) { return INVALID_OPERATION; } @@ -1362,7 +1401,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, Col return INVALID_OPERATION; } - const auto modes = getDisplayColorModes(*display); + const auto modes = getDisplayColorModes(display->getPhysicalId()); const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end(); if (mode < ColorMode::NATIVE || !exists) { @@ -1390,30 +1429,31 @@ status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const { return NO_ERROR; } -status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken, - ui::DisplayModeId modeId) { +status_t SurfaceFlinger::setBootDisplayMode(const sp<display::DisplayToken>& displayToken, + DisplayModeId modeId) { const char* const whence = __func__; auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { - const auto display = getDisplayDeviceLocked(displayToken); - if (!display) { - ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + const auto snapshotOpt = + ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>) + .transform(&PhysicalDisplay::snapshotRef); + + if (!snapshotOpt) { + ALOGE("%s: Invalid physical display token %p", whence, displayToken.get()); return NAME_NOT_FOUND; } - if (display->isVirtual()) { - ALOGE("%s: Invalid operation on virtual display", whence); - return INVALID_OPERATION; - } + const auto& snapshot = snapshotOpt->get(); + const auto hwcIdOpt = snapshot.displayModes().get(modeId).transform( + [](const DisplayModePtr& mode) { return mode->getHwcId(); }); - const auto displayId = display->getPhysicalId(); - const auto mode = display->getMode(DisplayModeId{modeId}); - if (!mode) { - ALOGE("%s: Invalid mode %d for display %s", whence, modeId, - to_string(displayId).c_str()); + if (!hwcIdOpt) { + ALOGE("%s: Invalid mode %d for display %s", whence, modeId.value(), + to_string(snapshot.displayId()).c_str()); return BAD_VALUE; } - return getHwComposer().setBootDisplayMode(displayId, mode->getHwcId()); + return getHwComposer().setBootDisplayMode(snapshot.displayId(), *hwcIdOpt); }); return future.get(); } @@ -1454,18 +1494,6 @@ void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on })); } -status_t SurfaceFlinger::clearAnimationFrameStats() { - Mutex::Autolock _l(mStateLock); - mAnimFrameTracker.clearStats(); - return NO_ERROR; -} - -status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { - Mutex::Autolock _l(mStateLock); - mAnimFrameTracker.getStats(outStats); - return NO_ERROR; -} - status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken, const std::vector<ui::Hdr>& hdrTypes) { Mutex::Autolock lock(mStateLock); @@ -1575,15 +1603,13 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { status_t SurfaceFlinger::injectVSync(nsecs_t when) { Mutex::Autolock lock(mStateLock); - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(when); - const auto expectedPresent = calculateExpectedPresentTime(stats); - return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent, - /*deadlineTimestamp=*/expectedPresent) - ? NO_ERROR - : BAD_VALUE; + const nsecs_t expectedPresentTime = calculateExpectedPresentTime(TimePoint::fromNs(when)).ns(); + const nsecs_t deadlineTimestamp = expectedPresentTime; + return mScheduler->injectVSync(when, expectedPresentTime, deadlineTimestamp) ? NO_ERROR + : BAD_VALUE; } -status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) { +status_t SurfaceFlinger::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) { outLayers->clear(); auto future = mScheduler->schedule([=] { const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); @@ -1815,10 +1841,11 @@ status_t SurfaceFlinger::getDisplayDecorationSupport( // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource, - ISurfaceComposer::EventRegistrationFlags eventRegistration) { + gui::ISurfaceComposer::VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) { const auto& handle = - vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; + vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger + ? mSfConnectionHandle + : mAppConnectionHandle; return mScheduler->createDisplayEventConnection(handle, eventRegistration); } @@ -1866,17 +1893,12 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t ATRACE_FORMAT("onComposerHalVsync%s", tracePeriod.c_str()); Mutex::Autolock lock(mStateLock); - const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId); - if (displayId) { - const auto token = getPhysicalDisplayTokenLocked(*displayId); - const auto display = getDisplayDeviceLocked(token); - display->onVsync(timestamp); - } if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) { return; } + const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId); const bool isActiveDisplay = displayId && getPhysicalDisplayTokenLocked(*displayId) == mActiveDisplayToken; if (!isActiveDisplay) { @@ -1891,30 +1913,16 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t } } -void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { - std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); - *compositorTiming = getBE().mCompositorTiming; -} - void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { - const bool connected = connection == hal::Connection::CONNECTED; - ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId); - - // Only lock if we're not on the main thread. This function is normally - // called on a hwbinder thread, but for the primary display it's called on - // the main thread with the state lock already held, so don't attempt to - // acquire it here. - ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - - mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection}); - - if (std::this_thread::get_id() == mMainThreadId) { - // Process all pending hot plug events immediately if we are on the main thread. - processDisplayHotplugEventsLocked(); + { + std::lock_guard<std::mutex> lock(mHotplugMutex); + mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection}); } - setTransactionFlags(eDisplayTransactionNeeded); + if (mScheduler) { + mScheduler->scheduleConfigure(); + } } void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged( @@ -1956,26 +1964,15 @@ void SurfaceFlinger::setVsyncEnabled(bool enabled) { })); } -SurfaceFlinger::FenceWithFenceTime SurfaceFlinger::previousFrameFence() { - const auto now = systemTime(); - const auto vsyncPeriod = mScheduler->getDisplayStatInfo(now).vsyncPeriod; - const bool expectedPresentTimeIsTheNextVsync = mExpectedPresentTime - now <= vsyncPeriod; - - size_t shift = 0; - if (!expectedPresentTimeIsTheNextVsync) { - shift = static_cast<size_t>((mExpectedPresentTime - now) / vsyncPeriod); - if (shift >= mPreviousPresentFences.size()) { - shift = mPreviousPresentFences.size() - 1; - } - } - ATRACE_FORMAT("previousFrameFence shift=%zu", shift); - return mPreviousPresentFences[shift]; +auto SurfaceFlinger::getPreviousPresentFence(TimePoint frameTime, Period vsyncPeriod) + -> const FenceTimePtr& { + const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod; + const size_t i = static_cast<size_t>(isTwoVsyncsAhead); + return mPreviousPresentFences[i].fenceTime; } -bool SurfaceFlinger::previousFramePending(int graceTimeMs) { +bool SurfaceFlinger::isFencePending(const FenceTimePtr& fence, int graceTimeMs) { ATRACE_CALL(); - const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime; - if (fence == FenceTime::NO_FENCE) { return false; } @@ -1986,44 +1983,45 @@ bool SurfaceFlinger::previousFramePending(int graceTimeMs) { return status == -ETIME; } -nsecs_t SurfaceFlinger::previousFramePresentTime() { - const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime; +TimePoint SurfaceFlinger::calculateExpectedPresentTime(TimePoint frameTime) const { + const auto& schedule = mScheduler->getVsyncSchedule(); - if (fence == FenceTime::NO_FENCE) { - return Fence::SIGNAL_TIME_INVALID; + const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(frameTime); + if (mVsyncModulator->getVsyncConfig().sfOffset > 0) { + return vsyncDeadline; } - return fence->getSignalTime(); + // Inflate the expected present time if we're targeting the next vsync. + return vsyncDeadline + schedule.period(); } -nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) const { - // Inflate the expected present time if we're targetting the next vsync. - return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? stats.vsyncTime - : stats.vsyncTime + stats.vsyncPeriod; +void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) { + Mutex::Autolock lock(mStateLock); + if (configureLocked()) { + setTransactionFlags(eDisplayTransactionNeeded); + } } -bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) +bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) FTL_FAKE_GUARD(kMainThreadContext) { - // calculate the expected present time once and use the cached - // value throughout this frame to make sure all layers are - // seeing this same value. - if (expectedVsyncTime >= frameTime) { - mExpectedPresentTime = expectedVsyncTime; - } else { - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameTime); - mExpectedPresentTime = calculateExpectedPresentTime(stats); - } - - const nsecs_t lastScheduledPresentTime = mScheduledPresentTime; + // The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the + // future relative to frameTime, but may not be for delayed frames. Adjust mExpectedPresentTime + // accordingly, but not mScheduledPresentTime. + const TimePoint lastScheduledPresentTime = mScheduledPresentTime; mScheduledPresentTime = expectedVsyncTime; - const auto vsyncIn = [&] { - if (!ATRACE_ENABLED()) return 0.f; - return (mExpectedPresentTime - systemTime()) / 1e6f; - }(); - ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn, + // Calculate the expected present time once and use the cached value throughout this frame to + // make sure all layers are seeing this same value. + mExpectedPresentTime = expectedVsyncTime >= frameTime ? expectedVsyncTime + : calculateExpectedPresentTime(frameTime); + + ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId.value, + ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()), mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)"); + const Period vsyncPeriod = mScheduler->getVsyncSchedule().period(); + const FenceTimePtr& previousPresentFence = getPreviousPresentFence(frameTime, vsyncPeriod); + // When Backpressure propagation is enabled we want to give a small grace period // for the present fence to fire instead of just giving up on this frame to handle cases // where present fence is just about to get signaled. @@ -2032,7 +2030,8 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Pending frames may trigger backpressure propagation. const TracedOrdinal<bool> framePending = {"PrevFramePending", - previousFramePending(graceTimeForPresentFenceMs)}; + isFencePending(previousPresentFence, + graceTimeForPresentFenceMs)}; // Frame missed counts for metrics tracking. // A frame is missed if the prior frame is still pending. If no longer pending, @@ -2042,13 +2041,12 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Add some slop to correct for drift. This should generally be // smaller than a typical frame duration, but should not be so small // that it reports reasonable drift as a missed frame. - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime()); - const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2; - const nsecs_t previousPresentTime = previousFramePresentTime(); + const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2; + const nsecs_t previousPresentTime = previousPresentFence->getSignalTime(); const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed", framePending || (previousPresentTime >= 0 && - (lastScheduledPresentTime < + (lastScheduledPresentTime.ns() < previousPresentTime - frameMissedSlop))}; const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed", mHadDeviceComposition && frameMissed}; @@ -2068,6 +2066,11 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected mGpuFrameMissedCount++; } + if (mTracingEnabledChanged) { + mLayerTracingEnabled = mLayerTracing.isEnabled(); + mTracingEnabledChanged = false; + } + // If we are in the middle of a mode change and the fence hasn't // fired yet just wait for the next commit. if (mSetActiveModePending) { @@ -2100,14 +2103,15 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected activeDisplay->getPowerMode() == hal::PowerMode::ON; if (mPowerHintSessionEnabled) { const auto& display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get(); - // get stable vsync period from display mode - const nsecs_t vsyncPeriod = display->getActiveMode()->getVsyncPeriod(); + const Period vsyncPeriod = Period::fromNs(display->getActiveMode().getVsyncPeriod()); mPowerAdvisor->setCommitStart(frameTime); mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime); - const nsecs_t idealSfWorkDuration = - mVsyncModulator->getVsyncConfig().sfWorkDuration.count(); - // Frame delay is how long we should have minus how long we actually have - mPowerAdvisor->setFrameDelay(idealSfWorkDuration - (mExpectedPresentTime - frameTime)); + + // Frame delay is how long we should have minus how long we actually have. + const Duration idealSfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration; + const Duration frameDelay = idealSfWorkDuration - (mExpectedPresentTime - frameTime); + + mPowerAdvisor->setFrameDelay(frameDelay); mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration); mPowerAdvisor->setTargetWorkDuration(vsyncPeriod); @@ -2118,11 +2122,6 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected } } - if (mTracingEnabledChanged) { - mLayerTracingEnabled = mLayerTracing.isEnabled(); - mTracingEnabledChanged = false; - } - if (mRefreshRateOverlaySpinner) { Mutex::Autolock lock(mStateLock); if (const auto display = getDefaultDisplayDeviceLocked()) { @@ -2133,11 +2132,13 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Composite if transactions were committed, or if requested by HWC. bool mustComposite = mMustComposite.exchange(false); { - mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod)); + mFrameTimeline->setSfWakeUp(vsyncId.value, frameTime.ns(), + Fps::fromPeriodNsecs(vsyncPeriod.ns())); bool needsTraversal = false; if (clearTransactionFlags(eTransactionFlushNeeded)) { - needsTraversal |= commitCreatedLayers(); + needsTraversal |= commitMirrorDisplays(vsyncId); + needsTraversal |= commitCreatedLayers(vsyncId); needsTraversal |= flushTransactionQueues(vsyncId); } @@ -2172,7 +2173,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer> // and may eventually call to ~Layer() if it holds the last reference { - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); mScheduler->chooseRefreshRateForContent(); setActiveModeInHwcIfNeeded(); } @@ -2182,17 +2183,18 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and tracing should only be enabled for debugging. - mLayerTracing.notify(mVisibleRegionsDirty, frameTime); + mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value); } + mLastCommittedVsyncId = vsyncId; persistDisplayBrightness(mustComposite); return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } -void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) +void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId) FTL_FAKE_GUARD(kMainThreadContext) { - ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId); + ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId.value); compositionengine::CompositionRefreshArgs refreshArgs; const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays); @@ -2203,10 +2205,29 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) displayIds.push_back(display->getId()); } mPowerAdvisor->setDisplays(displayIds); - mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) { - if (auto layerFE = layer->getCompositionEngineLayerFE()) - refreshArgs.layers.push_back(layerFE); - }); + + const bool updateTaskMetadata = mCompositionEngine->getFeatureFlags().test( + compositionengine::Feature::kSnapshotLayerMetadata); + if (updateTaskMetadata && (mVisibleRegionsDirty || mLayerMetadataSnapshotNeeded)) { + updateLayerMetadataSnapshot(); + mLayerMetadataSnapshotNeeded = false; + } + + if (DOES_CONTAIN_BORDER) { + refreshArgs.borderInfoList.clear(); + mDrawingState.traverse([&refreshArgs](Layer* layer) { + if (layer->isBorderEnabled()) { + compositionengine::BorderRenderInfo info; + info.width = layer->getBorderWidth(); + info.color = layer->getBorderColor(); + layer->traverse(LayerVector::StateSet::Drawing, [&info](Layer* ilayer) { + info.layerIds.push_back(ilayer->getSequence()); + }); + refreshArgs.borderInfoList.emplace_back(std::move(info)); + } + }); + } + refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); for (auto layer : mLayersWithQueuedFrames) { if (auto layerFE = layer->getCompositionEngineLayerFE()) @@ -2221,6 +2242,12 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty; + mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) { + layer->updateSnapshot(refreshArgs.updatingGeometryThisFrame); + if (auto layerFE = layer->getCompositionEngineLayerFE()) { + refreshArgs.layers.push_back(layerFE); + } + }); refreshArgs.blursAreExpensive = mBlursAreExpensive; refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags(); @@ -2236,13 +2263,13 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay); } - const auto expectedPresentTime = mExpectedPresentTime.load(); - const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(expectedPresentTime); + const auto prevVsyncTime = mExpectedPresentTime - mScheduler->getVsyncSchedule().period(); const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; + refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration; refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime; refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); - refreshArgs.expectedPresentTime = expectedPresentTime; + refreshArgs.expectedPresentTime = mExpectedPresentTime.ns(); // Store the present time just before calling to the composition engine so we could notify // the scheduler. @@ -2250,12 +2277,13 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) mCompositionEngine->present(refreshArgs); - mTimeStats->recordFrameDuration(frameTime, systemTime()); + mTimeStats->recordFrameDuration(frameTime.ns(), systemTime()); // Send a power hint hint after presentation is finished if (mPowerHintSessionEnabled) { - mPowerAdvisor->setSfPresentTiming(mPreviousPresentFences[0].fenceTime->getSignalTime(), - systemTime()); + mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(mPreviousPresentFences[0] + .fenceTime->getSignalTime()), + TimePoint::now()); if (mPowerHintSessionMode.late) { mPowerAdvisor->sendActualWorkDuration(); } @@ -2265,7 +2293,6 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) scheduleComposite(FrameHint::kNone); } - postFrame(); postComposition(); const bool prevFrameHadClientComposition = mHadClientComposition; @@ -2295,7 +2322,7 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) mLayersWithQueuedFrames.clear(); if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and should only be used for debugging. - mLayerTracing.notify(mVisibleRegionsDirty, frameTime); + mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value); } mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp @@ -2306,7 +2333,7 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) } if (mPowerHintSessionEnabled) { - mPowerAdvisor->setCompositeEnd(systemTime()); + mPowerAdvisor->setCompositeEnd(TimePoint::now()); } } @@ -2325,66 +2352,6 @@ void SurfaceFlinger::updateLayerGeometry() { mLayersPendingRefresh.clear(); } -void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, - std::shared_ptr<FenceTime>& presentFenceTime) { - // Update queue of past composite+present times and determine the - // most recently known composite to present latency. - getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime}); - nsecs_t compositeToPresentLatency = -1; - while (!getBE().mCompositePresentTimes.empty()) { - SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front(); - // Cached values should have been updated before calling this method, - // which helps avoid duplicate syscalls. - nsecs_t displayTime = cpt.display->getCachedSignalTime(); - if (displayTime == Fence::SIGNAL_TIME_PENDING) { - break; - } - compositeToPresentLatency = displayTime - cpt.composite; - getBE().mCompositePresentTimes.pop(); - } - - // Don't let mCompositePresentTimes grow unbounded, just in case. - while (getBE().mCompositePresentTimes.size() > 16) { - getBE().mCompositePresentTimes.pop(); - } - - setCompositorTimingSnapped(stats, compositeToPresentLatency); -} - -void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, - nsecs_t compositeToPresentLatency) { - // Avoid division by 0 by defaulting to 60Hz - const auto vsyncPeriod = stats.vsyncPeriod ?: (60_Hz).getPeriodNsecs(); - - // Integer division and modulo round toward 0 not -inf, so we need to - // treat negative and positive offsets differently. - nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0) - ? (vsyncPeriod - - (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % vsyncPeriod)) - : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % vsyncPeriod); - - // Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval. - if (idealLatency <= 0) { - idealLatency = vsyncPeriod; - } - - // Snap the latency to a value that removes scheduling jitter from the - // composition and present times, which often have >1ms of jitter. - // Reducing jitter is important if an app attempts to extrapolate - // something (such as user input) to an accurate diasplay time. - // Snapping also allows an app to precisely calculate - // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval). - const nsecs_t bias = vsyncPeriod / 2; - const int64_t extraVsyncs = ((compositeToPresentLatency - idealLatency + bias) / vsyncPeriod); - const nsecs_t snappedCompositeToPresentLatency = - (extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncPeriod) : idealLatency; - - std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); - getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency; - getBE().mCompositorTiming.interval = vsyncPeriod; - getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency; -} - bool SurfaceFlinger::isHdrLayer(Layer* layer) const { // Treat all layers as non-HDR if: // 1. They do not have a valid HDR dataspace. Currently we treat those as PQ or HLG. and @@ -2441,7 +2408,7 @@ ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, void SurfaceFlinger::postComposition() { ATRACE_CALL(); - ALOGV("postComposition"); + ALOGV(__func__); const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get(); @@ -2455,40 +2422,41 @@ void SurfaceFlinger::postComposition() { glCompositionDoneFenceTime = FenceTime::NO_FENCE; } - for (size_t i = mPreviousPresentFences.size()-1; i >= 1; i--) { - mPreviousPresentFences[i] = mPreviousPresentFences[i-1]; - } + mPreviousPresentFences[1] = mPreviousPresentFences[0]; - mPreviousPresentFences[0].fence = + auto presentFence = display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE; - mPreviousPresentFences[0].fenceTime = - std::make_shared<FenceTime>(mPreviousPresentFences[0].fence); - nsecs_t now = systemTime(); + auto presentFenceTime = std::make_shared<FenceTime>(presentFence); + mPreviousPresentFences[0] = {presentFence, presentFenceTime}; + + const TimePoint presentTime = TimePoint::now(); // Set presentation information before calling Layer::releasePendingBuffer, such that jank // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. - mFrameTimeline->setSfPresent(/* sfPresentTime */ now, mPreviousPresentFences[0].fenceTime, - glCompositionDoneFenceTime); - - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now); + mFrameTimeline->setSfPresent(presentTime.ns(), presentFenceTime, glCompositionDoneFenceTime); // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, - // but that should be okay since updateCompositorTiming has snapping logic. - updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(), - mPreviousPresentFences[0].fenceTime); - CompositorTiming compositorTiming; - { - std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); - compositorTiming = getBE().mCompositorTiming; - } + // but that should be okay since CompositorTiming has snapping logic. + const TimePoint compositeTime = + TimePoint::fromNs(mCompositionEngine->getLastFrameRefreshTimestamp()); + const Duration presentLatency = + mPresentLatencyTracker.trackPendingFrame(compositeTime, presentFenceTime); + + const auto& schedule = mScheduler->getVsyncSchedule(); + const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(presentTime); + const Period vsyncPeriod = schedule.period(); + const nsecs_t vsyncPhase = mVsyncConfiguration->getCurrentConfigs().late.sfOffset; + + const CompositorTiming compositorTiming(vsyncDeadline.ns(), vsyncPeriod.ns(), vsyncPhase, + presentLatency.ns()); for (const auto& layer: mLayersWithQueuedFrames) { - layer->onPostComposition(display, glCompositionDoneFenceTime, - mPreviousPresentFences[0].fenceTime, compositorTiming); - layer->releasePendingBuffer(/*dequeueReadyTime*/ now); + layer->onPostComposition(display, glCompositionDoneFenceTime, presentFenceTime, + compositorTiming); + layer->releasePendingBuffer(presentTime.ns()); } std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>> @@ -2545,13 +2513,22 @@ void SurfaceFlinger::postComposition() { mSomeDataspaceChanged = false; mVisibleRegionsWereDirtyThisFrame = false; - mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence); + mTransactionCallbackInvoker.addPresentFence(std::move(presentFence)); mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); mTransactionCallbackInvoker.clearCompletedTransactions(); - if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON && - mPreviousPresentFences[0].fenceTime->isValid()) { - mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime); + mTimeStats->incrementTotalFrames(); + mTimeStats->setPresentFenceGlobal(presentFenceTime); + + const bool isInternalDisplay = display && + FTL_FAKE_GUARD(mStateLock, mPhysicalDisplays) + .get(display->getPhysicalId()) + .transform(&PhysicalDisplay::isInternal) + .value_or(false); + + if (isInternalDisplay && display && display->getPowerMode() == hal::PowerMode::ON && + presentFenceTime->isValid()) { + mScheduler->addPresentFence(std::move(presentFenceTime)); } const bool isDisplayConnected = @@ -2563,24 +2540,6 @@ void SurfaceFlinger::postComposition() { } } - if (mAnimCompositionPending) { - mAnimCompositionPending = false; - - if (mPreviousPresentFences[0].fenceTime->isValid()) { - mAnimFrameTracker.setActualPresentFence(mPreviousPresentFences[0].fenceTime); - } else if (isDisplayConnected) { - // The HWC doesn't support present fences, so use the refresh - // timestamp instead. - const nsecs_t presentTime = display->getRefreshTimestamp(); - mAnimFrameTracker.setActualPresentTime(presentTime); - } - mAnimFrameTracker.advanceFrame(); - } - - mTimeStats->incrementTotalFrames(); - - mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime); - const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle); const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle); mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections); @@ -2590,21 +2549,6 @@ void SurfaceFlinger::postComposition() { return; } - nsecs_t currentTime = systemTime(); - if (mHasPoweredOff) { - mHasPoweredOff = false; - } else { - nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime; - size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod); - if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) { - getBE().mFrameBuckets[numPeriods] += elapsedTime; - } else { - getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime; - } - getBE().mTotalTime += elapsedTime; - } - getBE().mLastSwapTime = currentTime; - // Cleanup any outstanding resources due to rendering a prior frame. getRenderEngine().cleanupPostRender(); @@ -2631,6 +2575,8 @@ void SurfaceFlinger::postComposition() { // getTotalSize returns the total number of buffers that were allocated by SurfaceFlinger ATRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize()); } + + logFrameStats(presentTime); } FloatRect SurfaceFlinger::getMaxDisplayBounds() { @@ -2663,16 +2609,6 @@ void SurfaceFlinger::computeLayerBounds() { } } -void SurfaceFlinger::postFrame() { - const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); - if (display && getHwComposer().isConnected(display->getPhysicalId())) { - uint32_t flipCount = display->getPageFlipCount(); - if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { - logFrameStats(); - } - } -} - void SurfaceFlinger::commitTransactions() { ATRACE_CALL(); @@ -2705,10 +2641,9 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( do { hwcModes = getHwComposer().getModes(displayId); activeModeHwcId = getHwComposer().getActiveMode(displayId); - LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active mode"); const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) { - return mode.hwcId == *activeModeHwcId; + return mode.hwcId == activeModeHwcId; }; if (std::any_of(hwcModes.begin(), hwcModes.end(), isActiveMode)) { @@ -2716,16 +2651,21 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( } } while (++attempt < kMaxAttempts); - LOG_ALWAYS_FATAL_IF(attempt == kMaxAttempts, - "After %d attempts HWC still returns an active mode which is not" - " supported. Active mode ID = %" PRIu64 ". Supported modes = %s", - kMaxAttempts, *activeModeHwcId, base::Join(hwcModes, ", ").c_str()); - - DisplayModes oldModes; - if (const auto token = getPhysicalDisplayTokenLocked(displayId)) { - oldModes = getDisplayDeviceLocked(token)->getSupportedModes(); + if (attempt == kMaxAttempts) { + const std::string activeMode = + activeModeHwcId ? std::to_string(*activeModeHwcId) : "unknown"s; + ALOGE("HWC failed to report an active mode that is supported: activeModeHwcId=%s, " + "hwcModes={%s}", + activeMode.c_str(), base::Join(hwcModes, ", ").c_str()); + return {}; } + const DisplayModes oldModes = mPhysicalDisplays.get(displayId) + .transform([](const PhysicalDisplay& display) { + return display.snapshot().displayModes(); + }) + .value_or(DisplayModes{}); + ui::DisplayModeId nextModeId = 1 + std::accumulate(oldModes.begin(), oldModes.end(), static_cast<ui::DisplayModeId>(-1), [](ui::DisplayModeId max, const auto& pair) { @@ -2763,70 +2703,96 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( return {modes, activeMode}; } -void SurfaceFlinger::processDisplayHotplugEventsLocked() { - for (const auto& event : mPendingHotplugEvents) { - std::optional<DisplayIdentificationInfo> info = - getHwComposer().onHotplug(event.hwcDisplayId, event.connection); +bool SurfaceFlinger::configureLocked() { + std::vector<HotplugEvent> events; + { + std::lock_guard<std::mutex> lock(mHotplugMutex); + events = std::move(mPendingHotplugEvents); + } - if (!info) { - continue; + for (const auto [hwcDisplayId, connection] : events) { + if (auto info = getHwComposer().onHotplug(hwcDisplayId, connection)) { + const auto displayId = info->id; + const bool connected = connection == hal::Connection::CONNECTED; + + if (const char* const log = + processHotplug(displayId, hwcDisplayId, connected, std::move(*info))) { + ALOGI("%s display %s (HAL ID %" PRIu64 ")", log, to_string(displayId).c_str(), + hwcDisplayId); + } } + } - const auto displayId = info->id; - const auto token = mPhysicalDisplayTokens.get(displayId); + return !events.empty(); +} - if (event.connection == hal::Connection::CONNECTED) { - auto [supportedModes, activeMode] = loadDisplayModes(displayId); +const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId, + hal::HWDisplayId hwcDisplayId, bool connected, + DisplayIdentificationInfo&& info) { + const auto displayOpt = mPhysicalDisplays.get(displayId); + if (!connected) { + LOG_ALWAYS_FATAL_IF(!displayOpt); + const auto& display = displayOpt->get(); - if (!token) { - ALOGV("Creating display %s", to_string(displayId).c_str()); + if (const ssize_t index = mCurrentState.displays.indexOfKey(display.token()); index >= 0) { + const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); + mInterceptor->saveDisplayDeletion(state.sequenceId); + mCurrentState.displays.removeItemsAt(index); + } - DisplayDeviceState state; - state.physical = {.id = displayId, - .type = getHwComposer().getDisplayConnectionType(displayId), - .hwcDisplayId = event.hwcDisplayId, - .deviceProductInfo = std::move(info->deviceProductInfo), - .supportedModes = std::move(supportedModes), - .activeMode = std::move(activeMode)}; - state.isSecure = true; // All physical displays are currently considered secure. - state.displayName = std::move(info->name); + mPhysicalDisplays.erase(displayId); + return "Disconnecting"; + } - sp<IBinder> token = new BBinder(); - mCurrentState.displays.add(token, state); - mPhysicalDisplayTokens.try_emplace(displayId, std::move(token)); - mInterceptor->saveDisplayCreation(state); - } else { - ALOGV("Recreating display %s", to_string(displayId).c_str()); - - auto& state = mCurrentState.displays.editValueFor(token->get()); - state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. - state.physical->supportedModes = std::move(supportedModes); - state.physical->activeMode = std::move(activeMode); - if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) { - state.physical->deviceProductInfo = std::move(info->deviceProductInfo); - } - } - } else { - ALOGV("Removing display %s", to_string(displayId).c_str()); + auto [displayModes, activeMode] = loadDisplayModes(displayId); + if (!activeMode) { + // TODO(b/241286153): Report hotplug failure to the framework. + ALOGE("Failed to hotplug display %s", to_string(displayId).c_str()); + getHwComposer().disconnectDisplay(displayId); + return nullptr; + } - if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) { - const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); - mInterceptor->saveDisplayDeletion(state.sequenceId); - mCurrentState.displays.removeItemsAt(index); - } + if (displayOpt) { + const auto& display = displayOpt->get(); + const auto& snapshot = display.snapshot(); - mPhysicalDisplayTokens.erase(displayId); + std::optional<DeviceProductInfo> deviceProductInfo; + if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) { + deviceProductInfo = std::move(info.deviceProductInfo); + } else { + deviceProductInfo = snapshot.deviceProductInfo(); } - processDisplayChangesLocked(); + const auto it = + mPhysicalDisplays.try_replace(displayId, display.token(), displayId, + snapshot.connectionType(), std::move(displayModes), + std::move(deviceProductInfo)); + + auto& state = mCurrentState.displays.editValueFor(it->second.token()); + state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. + state.physical->activeMode = std::move(activeMode); + return "Reconnecting"; } - mPendingHotplugEvents.clear(); + const sp<IBinder> token = sp<BBinder>::make(); + + mPhysicalDisplays.try_emplace(displayId, token, displayId, + getHwComposer().getDisplayConnectionType(displayId), + std::move(displayModes), std::move(info.deviceProductInfo)); + + DisplayDeviceState state; + state.physical = {.id = displayId, + .hwcDisplayId = hwcDisplayId, + .activeMode = std::move(activeMode)}; + state.isSecure = true; // All physical displays are currently considered secure. + state.displayName = std::move(info.name); + + mCurrentState.displays.add(token, state); + mInterceptor->saveDisplayCreation(state); + return "Connecting"; } void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) { - ALOGI("Dispatching display hotplug event displayId=%s, connected=%d", - to_string(displayId).c_str(), connected); mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected); mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected); } @@ -2837,7 +2803,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer) { - DisplayDeviceCreationArgs creationArgs(this, getHwComposer(), displayToken, compositionDisplay); + DisplayDeviceCreationArgs creationArgs(sp<SurfaceFlinger>::fromExisting(this), getHwComposer(), + displayToken, compositionDisplay); creationArgs.sequenceId = state.sequenceId; creationArgs.isSecure = state.isSecure; creationArgs.displaySurface = displaySurface; @@ -2845,8 +2812,6 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( creationArgs.supportedPerFrameMetadata = 0; if (const auto& physical = state.physical) { - creationArgs.connectionType = physical->type; - creationArgs.supportedModes = physical->supportedModes; creationArgs.activeModeId = physical->activeMode->getId(); const auto [kernelIdleTimerController, idleTimerTimeoutMs] = getKernelIdleTimerProperties(compositionDisplay->getId()); @@ -2857,9 +2822,17 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0), .idleTimerTimeout = idleTimerTimeoutMs, .kernelIdleTimerController = kernelIdleTimerController}; + creationArgs.refreshRateConfigs = - std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes, - creationArgs.activeModeId, config); + mPhysicalDisplays.get(physical->id) + .transform(&PhysicalDisplay::snapshotRef) + .transform([&](const display::DisplaySnapshot& snapshot) { + return std::make_shared< + scheduler::RefreshRateConfigs>(snapshot.displayModes(), + creationArgs.activeModeId, + config); + }) + .value_or(nullptr); } if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) { @@ -2917,13 +2890,17 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); - if (!state.isVirtual()) { - FTL_FAKE_GUARD(kMainThreadContext, - display->setActiveMode(state.physical->activeMode->getId())); - display->setDeviceProductInfo(state.physical->deviceProductInfo); + + if (const auto& physical = state.physical) { + mPhysicalDisplays.get(physical->id) + .transform(&PhysicalDisplay::snapshotRef) + .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) { + FTL_FAKE_GUARD(kMainThreadContext, + display->setActiveMode(physical->activeMode->getId(), snapshot)); + })); } - display->setLayerStack(state.layerStack); + display->setLayerFilter(makeLayerFilterForDisplay(display->getId(), state.layerStack)); display->setProjection(state.orientation, state.layerStackSpaceRect, state.orientedDisplaySpaceRect); display->setDisplayName(state.displayName); @@ -2999,10 +2976,13 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, LOG_FATAL_IF(!displaySurface); auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), state, displaySurface, producer); - if (display->isPrimary()) { - initScheduler(display); - } - if (!state.isVirtual()) { + + if (mScheduler && !display->isVirtual()) { + // Display modes are reloaded on hotplug reconnect. + if (display->isPrimary()) { + mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs()); + } + dispatchDisplayHotplugEvent(display->getPhysicalId(), true); } @@ -3079,7 +3059,8 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (const auto display = getDisplayDeviceLocked(displayToken)) { if (currentState.layerStack != drawingState.layerStack) { - display->setLayerStack(currentState.layerStack); + display->setLayerFilter( + makeLayerFilterForDisplay(display->getId(), currentState.layerStack)); } if (currentState.flags != drawingState.flags) { display->setFlags(currentState.flags); @@ -3103,9 +3084,10 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, } } } + void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) { mVsyncConfiguration->reset(); - const Fps refreshRate = activeDisplay->refreshRateConfigs().getActiveMode()->getFps(); + const Fps refreshRate = activeDisplay->getActiveMode().getFps(); updatePhaseConfiguration(refreshRate); mRefreshRateStats->setRefreshRate(refreshRate); } @@ -3118,6 +3100,7 @@ void SurfaceFlinger::processDisplayChangesLocked() { const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; + mUpdateInputInfo = true; // find the displays that were removed // (ie: in drawing state but not in current state) @@ -3155,13 +3138,13 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; if (displayTransactionNeeded) { processDisplayChangesLocked(); - processDisplayHotplugEventsLocked(); } mForceTransactionDisplayChange = displayTransactionNeeded; if (mSomeChildrenChanged) { mVisibleRegionsDirty = true; mSomeChildrenChanged = false; + mUpdateInputInfo = true; } // Update transform hint. @@ -3203,7 +3186,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { } } - if (!hintDisplay) { + if (!hintDisplay && mDisplays.size() > 0) { // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to // redraw after transform hint changes. See bug 8508397. @@ -3213,7 +3196,11 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { hintDisplay = getDefaultDisplayDeviceLocked(); } - layer->updateTransformHint(hintDisplay->getTransformHint()); + if (hintDisplay) { + layer->updateTransformHint(hintDisplay->getTransformHint()); + } else { + ALOGW("Ignoring transform hint update for %s", layer->getDebugName()); + } }); } @@ -3221,6 +3208,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { mLayersAdded = false; // Layers have been added. mVisibleRegionsDirty = true; + mUpdateInputInfo = true; } // some layers might have been removed, so @@ -3228,19 +3216,19 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; + mUpdateInputInfo = true; mDrawingState.traverseInZOrder([&](Layer* layer) { - if (mLayersPendingRemoval.indexOf(layer) >= 0) { + if (mLayersPendingRemoval.indexOf(sp<Layer>::fromExisting(layer)) >= 0) { // this layer is not visible anymore Region visibleReg; visibleReg.set(layer->getScreenBounds()); - invalidateLayerStack(layer, visibleReg); + invalidateLayerStack(sp<Layer>::fromExisting(layer), visibleReg); } }); } doCommitTransactions(); signalSynchronousTransactions(CountDownLatch::eSyncTransaction); - mAnimTransactionPending = false; } void SurfaceFlinger::updateInputFlinger() { @@ -3252,14 +3240,14 @@ void SurfaceFlinger::updateInputFlinger() { std::vector<WindowInfo> windowInfos; std::vector<DisplayInfo> displayInfos; bool updateWindowInfo = false; - if (mVisibleRegionsDirty || mInputInfoChanged) { - mInputInfoChanged = false; + if (mUpdateInputInfo) { + mUpdateInputInfo = false; updateWindowInfo = true; buildWindowInfos(windowInfos, displayInfos); - } - if (!updateWindowInfo && mInputWindowCommands.empty()) { + } else if (mInputWindowCommands.empty()) { return; } + BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo, windowInfos = std::move(windowInfos), displayInfos = std::move(displayInfos), @@ -3268,12 +3256,17 @@ void SurfaceFlinger::updateInputFlinger() { inputFlinger = mInputFlinger, this]() { ATRACE_NAME("BackgroundExecutor::updateInputFlinger"); if (updateWindowInfo) { - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, - inputWindowCommands.syncInputWindows); - } else if (inputWindowCommands.syncInputWindows) { - // If the caller requested to sync input windows, but there are no - // changes to input windows, notify immediately. - windowInfosReported(); + mWindowInfosListenerInvoker + ->windowInfosChanged(windowInfos, displayInfos, + inputWindowCommands.windowInfosReportedListeners); + } else { + // If there are listeners but no changes to input windows, call the listeners + // immediately. + for (const auto& listener : inputWindowCommands.windowInfosReportedListeners) { + if (IInterface::asBinder(listener)->isBinderAlive()) { + listener->onWindowInfosReported(); + } + } } for (const auto& focusRequest : inputWindowCommands.focusRequests) { inputFlinger->setFocusedWindow(focusRequest); @@ -3314,7 +3307,7 @@ void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos, std::vector<DisplayInfo>& outDisplayInfos) { - ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos; + display::DisplayMap<ui::LayerStack, DisplayDevice::InputInfo> displayInputInfos; for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { const auto layerStack = display->getLayerStack(); @@ -3344,10 +3337,11 @@ void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos, mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - const auto opt = displayInputInfos.get(layer->getLayerStack(), - [](const auto& info) -> Layer::InputDisplayArgs { - return {&info.transform, info.isSecure}; - }); + const auto opt = displayInputInfos.get(layer->getLayerStack()) + .transform([](const DisplayDevice::InputInfo& info) { + return Layer::InputDisplayArgs{&info.transform, info.isSecure}; + }); + outWindowInfos.push_back(layer->fillInputInfo(opt.value_or(Layer::InputDisplayArgs{}))); }); @@ -3400,20 +3394,16 @@ void SurfaceFlinger::triggerOnFrameRateOverridesChanged() { mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId); } -void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { - if (mScheduler) { - // If the scheduler is already initialized, this means that we received - // a hotplug(connected) on the primary display. In that case we should - // update the scheduler with the most recent display information. - ALOGW("Scheduler already initialized, updating instead"); - mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs()); - return; - } - const auto currRefreshRate = display->getActiveMode()->getFps(); - mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate, - hal::PowerMode::OFF); +void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { + LOG_ALWAYS_FATAL_IF(mScheduler); - mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); + const auto activeModePtr = display->refreshRateConfigs().getActiveModePtr(); + const Fps activeRefreshRate = activeModePtr->getFps(); + mRefreshRateStats = + std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, activeRefreshRate, + hal::PowerMode::OFF); + + mVsyncConfiguration = getFactory().createVsyncConfiguration(activeRefreshRate); mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs()); using Feature = scheduler::Feature; @@ -3446,7 +3436,7 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { mScheduler->startTimers(); const auto configs = mVsyncConfiguration->getCurrentConfigs(); - const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs(); + const nsecs_t vsyncPeriod = activeRefreshRate.getPeriodNsecs(); mAppConnectionHandle = mScheduler->createConnection("app", mFrameTimeline->getTokenManager(), /*workDuration=*/configs.late.appWorkDuration, @@ -3460,12 +3450,13 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { mInterceptor->saveVSyncEvent(timestamp); }); - mScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(), - configs.late.sfWorkDuration); + mScheduler->initVsync(mScheduler->getVsyncSchedule().getDispatch(), + *mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration); mRegionSamplingThread = - new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables()); - mFpsReporter = new FpsReporter(*mFrameTimeline, *this); + sp<RegionSamplingThread>::make(*this, + RegionSamplingThread::EnvironmentTimingTunables()); + mFpsReporter = sp<FpsReporter>::make(*mFrameTimeline, *this); // Dispatch a mode change request for the primary display on scheduler // initialization, so that the EventThreads always contain a reference to a // prior configuration. @@ -3473,7 +3464,7 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { // This is a bit hacky, but this avoids a back-pointer into the main SF // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode()); + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr); } void SurfaceFlinger::updatePhaseConfiguration(const Fps& refreshRate) { @@ -3523,10 +3514,6 @@ void SurfaceFlinger::doCommitTransactions() { mLayersPendingRemoval.clear(); } - // If this transaction is part of a window animation then the next frame - // we composite should be considered an animation as well. - mAnimCompositionPending = mAnimTransactionPending; - mDrawingState = mCurrentState; // clear the "changed" flags in current state mCurrentState.colorMatrixChanged = false; @@ -3572,8 +3559,6 @@ bool SurfaceFlinger::latchBuffers() { bool frameQueued = false; bool newDataLatched = false; - const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); - // Store the set of layers that need updates. This set must not change as // buffers are being latched, as this could result in a deadlock. // Example: Two producers share the same command stream and: @@ -3593,12 +3578,7 @@ bool SurfaceFlinger::latchBuffers() { if (layer->hasReadyFrame()) { frameQueued = true; - if (layer->shouldPresentNow(expectedPresentTime)) { - mLayersWithQueuedFrames.emplace(layer); - } else { - ATRACE_NAME("!layer->shouldPresentNow()"); - layer->useEmptyDamage(); - } + mLayersWithQueuedFrames.emplace(sp<Layer>::fromExisting(layer)); } else { layer->useEmptyDamage(); } @@ -3619,7 +3599,7 @@ bool SurfaceFlinger::latchBuffers() { Mutex::Autolock lock(mStateLock); for (const auto& layer : mLayersWithQueuedFrames) { - if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) { + if (layer->latchBuffer(visibleRegions, latchTime)) { mLayersPendingRefresh.push_back(layer); newDataLatched = true; } @@ -3653,9 +3633,9 @@ bool SurfaceFlinger::latchBuffers() { status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<Layer>& layer, const wp<Layer>& parent, bool addToRoot, uint32_t* outTransformHint) { - if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { + if (mNumLayers >= MAX_LAYERS) { ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), - ISurfaceComposer::MAX_LAYERS); + MAX_LAYERS); static_cast<void>(mScheduler->schedule([=] { ALOGE("Dumping random sampling of on-screen layers: "); mDrawingState.traverse([&](Layer *layer) { @@ -3676,15 +3656,16 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBind return NO_MEMORY; } + layer->updateTransformHint(mActiveDisplayTransformHint); + if (outTransformHint) { + *outTransformHint = mActiveDisplayTransformHint; + } + { std::scoped_lock<std::mutex> lock(mCreatedLayersLock); mCreatedLayers.emplace_back(layer, parent, addToRoot); } - layer->updateTransformHint(mActiveDisplayTransformHint); - if (outTransformHint) { - *outTransformHint = mActiveDisplayTransformHint; - } // attach this layer to the client if (client != nullptr) { client->attachLayer(handle, layer); @@ -3711,52 +3692,33 @@ void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule sche } } -bool SurfaceFlinger::stopTransactionProcessing( - const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& - applyTokensWithUnsignaledTransactions) const { - if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) { - // if we are in LatchUnsignaledConfig::AutoSingleLayer - // then we should have only one applyToken for processing. - // so we can stop further transactions on this applyToken. - return !applyTokensWithUnsignaledTransactions.empty(); - } - - return false; -} - -int SurfaceFlinger::flushUnsignaledPendingTransactionQueues( - std::vector<TransactionState>& transactions, - std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, - std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions) { - return flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, - applyTokensWithUnsignaledTransactions, - /*tryApplyUnsignaled*/ true); -} - int SurfaceFlinger::flushPendingTransactionQueues( std::vector<TransactionState>& transactions, std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, - std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions, bool tryApplyUnsignaled) { + std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; int transactionsPendingBarrier = 0; auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; while (!transactionQueue.empty()) { - if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) { + // if we are in LatchUnsignaledConfig::AutoSingleLayer + // then we should have only one applyToken for processing. + // so we can stop further transactions on this applyToken. + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer && + !applyTokensWithUnsignaledTransactions.empty()) { ATRACE_NAME("stopTransactionProcessing"); break; } auto& transaction = transactionQueue.front(); const auto ready = - transactionIsReadyToBeApplied(transaction, - transaction.frameTimelineInfo, - transaction.isAutoTimestamp, - transaction.desiredPresentTime, - transaction.originUid, transaction.states, - bufferLayersReadyToPresent, transactions.size(), - tryApplyUnsignaled); + transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo, + transaction.isAutoTimestamp, + TimePoint::fromNs(transaction.desiredPresentTime), + transaction.originUid, transaction.states, + bufferLayersReadyToPresent, transactions.size(), + tryApplyUnsignaled); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); if (ready == TransactionReadiness::NotReady) { setTransactionFlags(eTransactionFlushNeeded); @@ -3785,11 +3747,12 @@ int SurfaceFlinger::flushPendingTransactionQueues( transactions.emplace_back(std::move(transaction)); transactionQueue.pop(); + mPendingTransactionCount--; + ATRACE_INT("TransactionQueue", mPendingTransactionCount.load()); } if (transactionQueue.empty()) { it = mPendingTransactionQueues.erase(it); - mTransactionQueueCV.broadcast(); } else { it = std::next(it, 1); } @@ -3797,73 +3760,23 @@ int SurfaceFlinger::flushPendingTransactionQueues( return transactionsPendingBarrier; } -bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { +bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) { // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer // states) around outside the scope of the lock std::vector<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>> bufferLayersReadyToPresent; - std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; { Mutex::Autolock _l(mStateLock); { - Mutex::Autolock _l(mQueueLock); - - int lastTransactionsPendingBarrier = 0; - int transactionsPendingBarrier = 0; - // First collect transactions from the pending transaction queues. - // We are not allowing unsignaled buffers here as we want to - // collect all the transactions from applyTokens that are ready first. - transactionsPendingBarrier = - flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, - applyTokensWithUnsignaledTransactions, /*tryApplyUnsignaled*/ false); - - // Second, collect transactions from the transaction queue. - // Here as well we are not allowing unsignaled buffers for the same - // reason as above. - while (!mTransactionQueue.empty()) { - auto& transaction = mTransactionQueue.front(); - const bool pendingTransactions = - mPendingTransactionQueues.find(transaction.applyToken) != - mPendingTransactionQueues.end(); - const auto ready = [&]() REQUIRES(mStateLock) { - if (pendingTransactions) { - ATRACE_NAME("pendingTransactions"); - return TransactionReadiness::NotReady; - } - - return transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo, - transaction.isAutoTimestamp, - transaction.desiredPresentTime, - transaction.originUid, transaction.states, - bufferLayersReadyToPresent, - transactions.size(), - /*tryApplyUnsignaled*/ false); - }(); - ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); - if (ready != TransactionReadiness::Ready) { - if (ready == TransactionReadiness::NotReadyBarrier) { - transactionsPendingBarrier++; - } - mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); - } else { - transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { - const bool frameNumberChanged = state.bufferData->flags.test( - BufferData::BufferDataChange::frameNumberChanged); - if (frameNumberChanged) { - bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber; - } else { - // Barrier function only used for BBQ which always includes a frame number. - // This value only used for barrier logic. - bufferLayersReadyToPresent[state.surface] = - std::numeric_limits<uint64_t>::max(); - } - }); - transactions.emplace_back(std::move(transaction)); + while (!mLocklessTransactionQueue.isEmpty()) { + auto maybeTransaction = mLocklessTransactionQueue.pop(); + if (!maybeTransaction.has_value()) { + break; } - mTransactionQueue.pop_front(); - ATRACE_INT("TransactionQueue", mTransactionQueue.size()); + auto transaction = maybeTransaction.value(); + mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } // Transactions with a buffer pending on a barrier may be on a different applyToken @@ -3876,20 +3789,21 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // loop through flushPendingTransactionQueues until we perform an iteration // where the number of transactionsPendingBarrier doesn't change. This way // we can continue to resolve dependency chains of barriers as far as possible. - while (lastTransactionsPendingBarrier != transactionsPendingBarrier) { + int lastTransactionsPendingBarrier = 0; + int transactionsPendingBarrier = 0; + do { lastTransactionsPendingBarrier = transactionsPendingBarrier; transactionsPendingBarrier = - flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, - applyTokensWithUnsignaledTransactions, - /*tryApplyUnsignaled*/ false); - } + flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, + /*tryApplyUnsignaled*/ false); + } while (lastTransactionsPendingBarrier != transactionsPendingBarrier); // We collected all transactions that could apply without latching unsignaled buffers. // If we are allowing latch unsignaled of some form, now it's the time to go over the // transactions that were not applied and try to apply them unsignaled. if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { - flushUnsignaledPendingTransactionQueues(transactions, bufferLayersReadyToPresent, - applyTokensWithUnsignaledTransactions); + flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, + /*tryApplyUnsignaled*/ true); } return applyTransactions(transactions, vsyncId); @@ -3898,7 +3812,7 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { } bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions, - int64_t vsyncId) { + VsyncId vsyncId) { bool needsTraversal = false; // Now apply all transactions. for (auto& transaction : transactions) { @@ -3918,37 +3832,37 @@ bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactio } if (mTransactionTracing) { - mTransactionTracing->addCommittedTransactions(transactions, vsyncId); + mTransactionTracing->addCommittedTransactions(transactions, vsyncId.value); } return needsTraversal; } bool SurfaceFlinger::transactionFlushNeeded() { - Mutex::Autolock _l(mQueueLock); - return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty(); + return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty(); } -bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const { - // The amount of time SF can delay a frame if it is considered early based - // on the VsyncModulator::VsyncConfig::appWorkDuration - constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; - - const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod; - const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2; - - const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId); - if (!prediction.has_value()) { +bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId) const { + const auto prediction = + mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId.value); + if (!prediction) { return false; } - if (std::abs(prediction->presentTime - expectedPresentTime) >= - kEarlyLatchMaxThreshold.count()) { + const auto predictedPresentTime = TimePoint::fromNs(prediction->presentTime); + + // The duration for which SF can delay a frame if it is considered early based on the + // VsyncModulator::VsyncConfig::appWorkDuration. + if (constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; + std::chrono::abs(predictedPresentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold) { return false; } - return prediction->presentTime >= expectedPresentTime && - prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold; + const Duration earlyLatchVsyncThreshold = mScheduler->getVsyncSchedule().period() / 2; + + return predictedPresentTime >= expectedPresentTime && + predictedPresentTime - expectedPresentTime >= earlyLatchVsyncThreshold; } + bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state, size_t numStates, size_t totalTXapplied) const { if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { @@ -3995,30 +3909,29 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_s return true; } -auto SurfaceFlinger::transactionIsReadyToBeApplied(TransactionState& transaction, - const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, - uid_t originUid, const Vector<ComposerState>& states, - const std::unordered_map< - sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, +auto SurfaceFlinger::transactionIsReadyToBeApplied( + TransactionState& transaction, const FrameTimelineInfo& info, bool isAutoTimestamp, + TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, + const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& + bufferLayersReadyToPresent, size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness { ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); - const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. - if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime && - desiredPresentTime < expectedPresentTime + s2ns(1)) { + if (!isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime && + desiredPresentTime < mExpectedPresentTime + 1s) { ATRACE_NAME("not current"); return TransactionReadiness::NotReady; } - if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) { + if (!mScheduler->isVsyncValid(mExpectedPresentTime, originUid)) { ATRACE_NAME("!isVsyncValid"); return TransactionReadiness::NotReady; } // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected // present time of this transaction. - if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) { + if (isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{info.vsyncId})) { ATRACE_NAME("frameIsEarly"); return TransactionReadiness::NotReady; } @@ -4064,7 +3977,7 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied(TransactionState& transaction if (fenceUnsignaled && !allowLatchUnsignaled) { if (!transaction.sentFenceTimeoutWarning && - queueProcessTime - transaction.queueTime > std::chrono::nanoseconds(4s).count()) { + queueProcessTime - transaction.postTime > std::chrono::nanoseconds(4s).count()) { transaction.sentFenceTimeoutWarning = true; auto listener = s.bufferData->releaseBufferListener; if (listener) { @@ -4091,20 +4004,15 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied(TransactionState& transaction } void SurfaceFlinger::queueTransaction(TransactionState& state) { - state.queueTime = systemTime(); - - Mutex::Autolock lock(mQueueLock); - // Generate a CountDownLatch pending state if this is a synchronous transaction. - if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) { - state.transactionCommittedSignal = std::make_shared<CountDownLatch>( - (state.inputWindowCommands.syncInputWindows - ? (CountDownLatch::eSyncInputWindows | CountDownLatch::eSyncTransaction) - : CountDownLatch::eSyncTransaction)); + if (state.flags & eSynchronous) { + state.transactionCommittedSignal = + std::make_shared<CountDownLatch>(CountDownLatch::eSyncTransaction); } - mTransactionQueue.emplace_back(state); - ATRACE_INT("TransactionQueue", mTransactionQueue.size()); + mLocklessTransactionQueue.push(state); + mPendingTransactionCount++; + ATRACE_INT("TransactionQueue", mPendingTransactionCount.load()); const auto schedule = [](uint32_t flags) { if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd; @@ -4273,10 +4181,6 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin if (transactionFlags) { setTransactionFlags(transactionFlags); } - - if (flags & eAnimation) { - mAnimTransactionPending = true; - } } return needsTraversal; @@ -4385,7 +4289,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (layer == nullptr) { for (auto& [listener, callbackIds] : s.listeners) { mTransactionCallbackInvoker.registerUnpresentedCallbackHandle( - new CallbackHandle(listener, callbackIds, s.surface)); + sp<CallbackHandle>::make(listener, callbackIds, s.surface)); } return 0; } @@ -4439,11 +4343,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } } } - if (what & layer_state_t::eSizeChanged) { - if (layer->setSize(s.w, s.h)) { - flags |= eTraversalNeeded; - } - } if (what & layer_state_t::eAlphaChanged) { if (layer->setAlpha(s.alpha)) flags |= eTraversalNeeded; @@ -4482,6 +4381,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eBlurRegionsChanged) { if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eRenderBorderChanged) { + if (layer->enableBorder(s.borderEnabled, s.borderWidth, s.borderColor)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eLayerStackChanged) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); // We only allow setting layer stacks for top level layers, @@ -4533,16 +4437,20 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } std::optional<nsecs_t> dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { - dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME); + dequeueBufferTimestamp = s.metadata.getInt64(gui::METADATA_DEQUEUE_TIME); - if (const int32_t gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); gameMode != -1) { + if (const int32_t gameMode = s.metadata.getInt32(gui::METADATA_GAME_MODE, -1); + gameMode != -1) { // The transaction will be received on the Task layer and needs to be applied to all // child layers. Child layers that are added at a later point will obtain the game mode // info through addChild(). layer->setGameModeForTree(static_cast<GameMode>(gameMode)); } - if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded; + if (layer->setMetadata(s.metadata)) { + flags |= eTraversalNeeded; + mLayerMetadataSnapshotNeeded = true; + } } if (what & layer_state_t::eColorSpaceAgnosticChanged) { if (layer->setColorSpaceAgnostic(s.colorSpaceAgnostic)) { @@ -4552,6 +4460,14 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eShadowRadiusChanged) { if (layer->setShadowRadius(s.shadowRadius)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eDefaultFrameRateCompatibilityChanged) { + const auto compatibility = + Layer::FrameRate::convertCompatibility(s.defaultFrameRateCompatibility); + + if (layer->setDefaultFrameRateCompatibility(compatibility)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eFrameRateSelectionPriority) { if (layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) { flags |= eTraversalNeeded; @@ -4602,7 +4518,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eDropInputModeChanged) { if (layer->setDropInputMode(s.dropInputMode)) { flags |= eTraversalNeeded; - mInputInfoChanged = true; + mUpdateInputInfo = true; } } // This has to happen after we reparent children because when we reparent to null we remove @@ -4625,7 +4541,8 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime std::vector<sp<CallbackHandle>> callbackHandles; if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { for (auto& [listener, callbackIds] : filteredListeners) { - callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); + callbackHandles.emplace_back( + sp<CallbackHandle>::make(listener, callbackIds, s.surface)); } } @@ -4666,7 +4583,9 @@ status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args, if (!mirrorFrom) { return NAME_NOT_FOUND; } - status_t result = createContainerLayer(args, outHandle, &mirrorLayer); + LayerCreationArgs mirrorArgs = args; + mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill; + status_t result = createEffectLayer(mirrorArgs, outHandle, &mirrorLayer); if (result != NO_ERROR) { return result; } @@ -4683,6 +4602,55 @@ status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args, false /* addToRoot */, nullptr /* outTransformHint */); } +status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args, + sp<IBinder>* outHandle, int32_t* outLayerId) { + IPCThreadState* ipc = IPCThreadState::self(); + const int uid = ipc->getCallingUid(); + if (uid != AID_ROOT && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != AID_SHELL) { + ALOGE("Permission denied when trying to mirror display"); + return PERMISSION_DENIED; + } + + ui::LayerStack layerStack; + sp<Layer> rootMirrorLayer; + status_t result = 0; + + { + Mutex::Autolock lock(mStateLock); + + const auto display = getDisplayDeviceLocked(displayId); + if (!display) { + return NAME_NOT_FOUND; + } + + layerStack = display->getLayerStack(); + LayerCreationArgs mirrorArgs = args; + mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill; + result = createEffectLayer(mirrorArgs, outHandle, &rootMirrorLayer); + *outLayerId = rootMirrorLayer->sequence; + result |= addClientLayer(args.client, *outHandle, rootMirrorLayer /* layer */, + nullptr /* parent */, true /* addToRoot */, + nullptr /* outTransformHint */); + } + + if (result != NO_ERROR) { + return result; + } + + if (mTransactionTracing) { + mTransactionTracing->onLayerAdded((*outHandle)->localBinder(), *outLayerId, args.name, + args.flags, -1 /* parentId */); + } + + { + std::scoped_lock<std::mutex> lock(mMirrorDisplayLock); + mMirrorDisplays.emplace_back(layerStack, *outHandle, args.client); + } + + setTransactionFlags(eTransactionFlushNeeded); + return NO_ERROR; +} + status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle, const sp<IBinder>& parentHandle, int32_t* outLayerId, const sp<Layer>& parentLayer, uint32_t* outTransformHint) { @@ -4696,7 +4664,11 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHa switch (args.flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: - case ISurfaceComposerClient::eFXSurfaceBufferState: { + case ISurfaceComposerClient::eFXSurfaceContainer: + case ISurfaceComposerClient::eFXSurfaceBufferState: + args.flags |= ISurfaceComposerClient::eNoColorFill; + FMT_FALLTHROUGH; + case ISurfaceComposerClient::eFXSurfaceEffect: { result = createBufferStateLayer(args, outHandle, &layer); std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter(); if (pendingBufferCounter) { @@ -4705,12 +4677,6 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHa pendingBufferCounter); } } break; - case ISurfaceComposerClient::eFXSurfaceEffect: - result = createEffectLayer(args, outHandle, &layer); - break; - case ISurfaceComposerClient::eFXSurfaceContainer: - result = createContainerLayer(args, outHandle, &layer); - break; default: result = BAD_VALUE; break; @@ -4751,42 +4717,6 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHa return result; } -status_t SurfaceFlinger::createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, - sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, - sp<Layer>* outLayer) { - // initialize the surfaces - switch (format) { - case PIXEL_FORMAT_TRANSPARENT: - case PIXEL_FORMAT_TRANSLUCENT: - format = PIXEL_FORMAT_RGBA_8888; - break; - case PIXEL_FORMAT_OPAQUE: - format = PIXEL_FORMAT_RGBX_8888; - break; - } - - sp<BufferQueueLayer> layer; - args.textureName = getNewTexture(); - { - // Grab the SF state lock during this since it's the only safe way to access - // RenderEngine when creating a BufferLayerConsumer - // TODO: Check if this lock is still needed here - Mutex::Autolock lock(mStateLock); - layer = getFactory().createBufferQueueLayer(args); - } - - status_t err = layer->setDefaultBufferProperties(0, 0, format); - if (err == NO_ERROR) { - *handle = layer->getHandle(); - *gbp = layer->getProducer(); - *outLayer = layer; - } - - ALOGE_IF(err, "createBufferQueueLayer() failed (%s)", strerror(-err)); - return err; -} - status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle, sp<Layer>* outLayer) { args.textureName = getNewTexture(); @@ -4802,13 +4732,6 @@ status_t SurfaceFlinger::createEffectLayer(const LayerCreationArgs& args, sp<IBi return NO_ERROR; } -status_t SurfaceFlinger::createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* handle, - sp<Layer>* outLayer) { - *outLayer = getFactory().createContainerLayer(args); - *handle = (*outLayer)->getHandle(); - return NO_ERROR; -} - void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) { mLayersPendingRemoval.add(layer); mLayersRemoved = true; @@ -4825,8 +4748,6 @@ void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer) { } } -// --------------------------------------------------------------------------- - void SurfaceFlinger::onInitializeDisplays() { const auto display = getDefaultDisplayDeviceLocked(); if (!display) return; @@ -4858,19 +4779,15 @@ void SurfaceFlinger::onInitializeDisplays() { {}, mPid, getuid(), transactionId); setPowerModeInternal(display, hal::PowerMode::ON); - const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod(); - mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod); + mActiveDisplayTransformHint = display->getTransformHint(); - // Use phase of 0 since phase is not known. - // Use latency of 0, which will snap to the ideal latency. - DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod}; - setCompositorTimingSnapped(stats, 0); } void SurfaceFlinger::initializeDisplays() { // Async since we may be called from the main thread. - static_cast<void>( - mScheduler->schedule([this]() FTL_FAKE_GUARD(mStateLock) { onInitializeDisplays(); })); + static_cast<void>(mScheduler->schedule( + [this]() FTL_FAKE_GUARD(mStateLock) + FTL_FAKE_GUARD(kMainThreadContext) { onInitializeDisplays(); })); } void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) { @@ -4887,8 +4804,12 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: return; } + const bool isInternalDisplay = mPhysicalDisplays.get(displayId) + .transform(&PhysicalDisplay::isInternal) + .value_or(false); + const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken); - if (activeDisplay != display && display->isInternal() && activeDisplay && + if (isInternalDisplay && activeDisplay != display && activeDisplay && activeDisplay->isPoweredOn()) { ALOGW("Trying to change power mode on non active display while the active display is ON"); } @@ -4898,10 +4819,10 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: if (mInterceptor->isEnabled()) { mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode)); } - const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); + const auto refreshRate = display->refreshRateConfigs().getActiveMode().getFps(); if (*currentMode == hal::PowerMode::OFF) { // Turn on the display - if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) { + if (isInternalDisplay && (!activeDisplay || !activeDisplay->isPoweredOn())) { onActiveDisplayChangedLocked(display); } // Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315. @@ -4920,7 +4841,6 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } mVisibleRegionsDirty = true; - mHasPoweredOff = true; scheduleComposite(FrameHint::kActive); } else if (mode == hal::PowerMode::OFF) { // Turn off the display @@ -4945,6 +4865,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: // Update display while dozing getHwComposer().setPowerMode(displayId, mode); if (isDisplayActiveLocked(display) && *currentMode == hal::PowerMode::DOZE_SUSPEND) { + ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON."); + mVisibleRegionsDirty = true; + scheduleRepaint(); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, refreshRate); } @@ -4970,7 +4893,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) { - auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD( + kMainThreadContext) { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set power mode %d for invalid display token %p", mode, @@ -5007,11 +4931,11 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)}, {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)}, {"--planner"s, argsDumper(&SurfaceFlinger::dumpPlannerInfo)}, - {"--static-screen"s, dumper(&SurfaceFlinger::dumpStaticScreenStats)}, {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)}, {"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)}, {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)}, {"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)}, + {"--hwclayers"s, dumper(&SurfaceFlinger::dumpHwcLayersMinidumpLocked)}, }; const auto flag = args.empty() ? ""s : std::string(String8(args[0])); @@ -5091,17 +5015,14 @@ void SurfaceFlinger::listLayersLocked(std::string& result) const { void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const { StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriodFromHWC()); + if (args.size() < 2) return; - if (args.size() > 1) { - const auto name = String8(args[1]); - mCurrentState.traverseInZOrder([&](Layer* layer) { - if (layer->getName() == name.string()) { - layer->dumpFrameStats(result); - } - }); - } else { - mAnimFrameTracker.dumpStats(result); - } + const auto name = String8(args[1]); + mCurrentState.traverseInZOrder([&](Layer* layer) { + if (layer->getName() == name.string()) { + layer->dumpFrameStats(result); + } + }); } void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) { @@ -5113,8 +5034,6 @@ void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) { layer->clearFrameStats(); } }); - - mAnimFrameTracker.clearStats(); } void SurfaceFlinger::dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const { @@ -5125,12 +5044,13 @@ void SurfaceFlinger::dumpFrameTimeline(const DumpArgs& args, std::string& result mFrameTimeline->parseArgs(args, result); } -void SurfaceFlinger::logFrameStats() { - mDrawingState.traverse([&](Layer* layer) { - layer->logFrameStats(); - }); +void SurfaceFlinger::logFrameStats(TimePoint now) { + static TimePoint sTimestamp = now; + if (now - sTimestamp < 30min) return; + sTimestamp = now; - mAnimFrameTracker.logAndResetStats("<win-anim>"); + ATRACE_CALL(); + mDrawingState.traverse([&](Layer* layer) { layer->logFrameStats(); }); } void SurfaceFlinger::appendSfConfigString(std::string& result) const { @@ -5173,21 +5093,6 @@ void SurfaceFlinger::dumpPlannerInfo(const DumpArgs& args, std::string& result) } } -void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const { - result.append("Static screen stats:\n"); - for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) { - float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9; - float percent = 100.0f * - static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime; - StringAppendF(&result, " < %zd frames: %.3f s (%.1f%%)\n", b + 1, bucketTimeSec, percent); - } - float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9; - float percent = 100.0f * - static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime; - StringAppendF(&result, " %zd+ frames: %.3f s (%.1f%%)\n", SurfaceFlingerBE::NUM_BUCKETS - 1, - bucketTimeSec, percent); -} - void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const { for (const auto& [token, display] : mDisplays) { display->getCompositionDisplay()->dump(result); @@ -5196,10 +5101,20 @@ void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const { } void SurfaceFlinger::dumpDisplays(std::string& result) const { - for (const auto& [token, display] : mDisplays) { - display->dump(result); + for (const auto& [id, display] : mPhysicalDisplays) { + if (const auto device = getDisplayDeviceLocked(id)) { + device->dump(result); + } + display.snapshot().dump(result); result += '\n'; } + + for (const auto& [token, display] : mDisplays) { + if (display->isVirtual()) { + display->dump(result); + result += '\n'; + } + } } void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { @@ -5346,6 +5261,23 @@ void SurfaceFlinger::dumpOffscreenLayers(std::string& result) { result.append(future.get()); } +void SurfaceFlinger::dumpHwcLayersMinidumpLocked(std::string& result) const { + for (const auto& [token, display] : mDisplays) { + const auto displayId = HalDisplayId::tryCast(display->getId()); + if (!displayId) { + continue; + } + + StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(), + (isDisplayActiveLocked(display) ? "active" : "inactive")); + Layer::miniDumpHeader(result); + + const DisplayDevice& ref = *display; + mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); }); + result.append("\n"); + } +} + void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& compositionLayers, std::string& result) const { const bool colorize = !args.empty() && args[0] == String16("--color"); @@ -5384,9 +5316,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp dumpVSync(result); result.append("\n"); - dumpStaticScreenStats(result); - result.append("\n"); - StringAppendF(&result, "Total missed frame count: %u\n", mFrameMissedCount.load()); StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load()); StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load()); @@ -5436,10 +5365,10 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp if (const auto display = getDefaultDisplayDeviceLocked()) { std::string fps, xDpi, yDpi; - if (const auto activeMode = display->getActiveMode()) { - fps = to_string(activeMode->getFps()); + if (const auto activeModePtr = display->refreshRateConfigs().getActiveModePtr()) { + fps = to_string(activeModePtr->getFps()); - const auto dpi = activeMode->getDpi(); + const auto dpi = activeModePtr->getDpi(); xDpi = base::StringPrintf("%.2f", dpi.x); yDpi = base::StringPrintf("%.2f", dpi.y); } else { @@ -5470,23 +5399,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp } result.push_back('\n'); - /* - * HWC layer minidump - */ - for (const auto& [token, display] : mDisplays) { - const auto displayId = HalDisplayId::tryCast(display->getId()); - if (!displayId) { - continue; - } - - StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(), - (isDisplayActiveLocked(display) ? "active" : "inactive")); - Layer::miniDumpHeader(result); - - const DisplayDevice& ref = *display; - mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); }); - result.append("\n"); - } + dumpHwcLayersMinidumpLocked(result); { DumpArgs plannerArgs; @@ -5549,29 +5462,11 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { #pragma clang diagnostic push #pragma clang diagnostic error "-Wswitch-enum" switch (static_cast<ISurfaceComposerTag>(code)) { - case ENABLE_VSYNC_INJECTIONS: - case INJECT_VSYNC: - if (!hasMockHwc()) return PERMISSION_DENIED; - [[fallthrough]]; // These methods should at minimum make sure that the client requested // access to SF. - case BOOT_FINISHED: - case CLEAR_ANIMATION_FRAME_STATS: - case GET_ANIMATION_FRAME_STATS: - case OVERRIDE_HDR_TYPES: case GET_HDR_CAPABILITIES: - case SET_DESIRED_DISPLAY_MODE_SPECS: - case GET_DESIRED_DISPLAY_MODE_SPECS: - case SET_ACTIVE_COLOR_MODE: - case SET_BOOT_DISPLAY_MODE: case GET_AUTO_LOW_LATENCY_MODE_SUPPORT: case GET_GAME_CONTENT_TYPE_SUPPORT: - case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: - case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: - case GET_DISPLAYED_CONTENT_SAMPLE: - case ADD_TUNNEL_MODE_ENABLED_LISTENER: - case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: - case SET_GLOBAL_SHADOW_SETTINGS: case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { // OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary // permission dynamically. Don't use the permission cache for this check. @@ -5584,100 +5479,38 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return OK; } - case GET_LAYER_DEBUG_INFO: { - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { - ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - return OK; - } - // Used by apps to hook Choreographer to SurfaceFlinger. - case CREATE_DISPLAY_EVENT_CONNECTION: // The following calls are currently used by clients that do not // request necessary permissions. However, they do not expose any secret // information, so it is OK to pass them. - case AUTHENTICATE_SURFACE: case GET_ACTIVE_COLOR_MODE: case GET_ACTIVE_DISPLAY_MODE: case GET_DISPLAY_COLOR_MODES: - case GET_DISPLAY_NATIVE_PRIMARIES: - case GET_STATIC_DISPLAY_INFO: - case GET_DYNAMIC_DISPLAY_INFO: case GET_DISPLAY_MODES: - case GET_SUPPORTED_FRAME_TIMESTAMPS: // Calling setTransactionState is safe, because you need to have been // granted a reference to Client* and Handle* to do anything with it. - case SET_TRANSACTION_STATE: - case CREATE_CONNECTION: - case GET_COLOR_MANAGEMENT: - case GET_COMPOSITION_PREFERENCE: - case GET_PROTECTED_CONTENT_SUPPORT: - // setFrameRate() is deliberately available for apps to call without any - // special permissions. - case SET_FRAME_RATE: - case GET_DISPLAY_DECORATION_SUPPORT: - case SET_FRAME_TIMELINE_INFO: - case GET_GPU_CONTEXT_PRIORITY: - case GET_MAX_ACQUIRED_BUFFER_COUNT: { + case SET_TRANSACTION_STATE: { // This is not sensitive information, so should not require permission control. return OK; } - case ADD_FPS_LISTENER: - case REMOVE_FPS_LISTENER: - case ADD_REGION_SAMPLING_LISTENER: - case REMOVE_REGION_SAMPLING_LISTENER: { - // codes that require permission check - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && - !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { - ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - return OK; - } - case ADD_TRANSACTION_TRACE_LISTENER: { - IPCThreadState* ipc = IPCThreadState::self(); - const int uid = ipc->getCallingUid(); - if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { - return OK; - } - return PERMISSION_DENIED; - } - case SET_OVERRIDE_FRAME_RATE: { - const int uid = IPCThreadState::self()->getCallingUid(); - if (uid == AID_ROOT || uid == AID_SYSTEM) { - return OK; - } - return PERMISSION_DENIED; - } - case ON_PULL_ATOM: { - const int uid = IPCThreadState::self()->getCallingUid(); - if (uid == AID_SYSTEM) { - return OK; - } - return PERMISSION_DENIED; - } - case ADD_WINDOW_INFOS_LISTENER: - case REMOVE_WINDOW_INFOS_LISTENER: { - const int uid = IPCThreadState::self()->getCallingUid(); - if (uid == AID_SYSTEM || uid == AID_GRAPHICS) { - return OK; - } - return PERMISSION_DENIED; - } + case BOOT_FINISHED: + // Used by apps to hook Choreographer to SurfaceFlinger. + case CREATE_DISPLAY_EVENT_CONNECTION: + case CREATE_CONNECTION: case CREATE_DISPLAY: case DESTROY_DISPLAY: case GET_PRIMARY_PHYSICAL_DISPLAY_ID: case GET_PHYSICAL_DISPLAY_IDS: case GET_PHYSICAL_DISPLAY_TOKEN: + case AUTHENTICATE_SURFACE: case SET_POWER_MODE: + case GET_SUPPORTED_FRAME_TIMESTAMPS: case GET_DISPLAY_STATE: case GET_DISPLAY_STATS: + case GET_STATIC_DISPLAY_INFO: + case GET_DYNAMIC_DISPLAY_INFO: + case GET_DISPLAY_NATIVE_PRIMARIES: + case SET_ACTIVE_COLOR_MODE: + case SET_BOOT_DISPLAY_MODE: case CLEAR_BOOT_DISPLAY_MODE: case GET_BOOT_DISPLAY_MODE_SUPPORT: case SET_AUTO_LOW_LATENCY_MODE: @@ -5685,12 +5518,43 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case CAPTURE_LAYERS: case CAPTURE_DISPLAY: case CAPTURE_DISPLAY_BY_ID: + case CLEAR_ANIMATION_FRAME_STATS: + case GET_ANIMATION_FRAME_STATS: + case OVERRIDE_HDR_TYPES: + case ON_PULL_ATOM: + case ENABLE_VSYNC_INJECTIONS: + case INJECT_VSYNC: + case GET_LAYER_DEBUG_INFO: + case GET_COLOR_MANAGEMENT: + case GET_COMPOSITION_PREFERENCE: + case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: + case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: + case GET_DISPLAYED_CONTENT_SAMPLE: + case GET_PROTECTED_CONTENT_SUPPORT: case IS_WIDE_COLOR_DISPLAY: + case ADD_REGION_SAMPLING_LISTENER: + case REMOVE_REGION_SAMPLING_LISTENER: + case ADD_FPS_LISTENER: + case REMOVE_FPS_LISTENER: + case ADD_TUNNEL_MODE_ENABLED_LISTENER: + case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: + case ADD_WINDOW_INFOS_LISTENER: + case REMOVE_WINDOW_INFOS_LISTENER: + case SET_DESIRED_DISPLAY_MODE_SPECS: + case GET_DESIRED_DISPLAY_MODE_SPECS: case GET_DISPLAY_BRIGHTNESS_SUPPORT: case SET_DISPLAY_BRIGHTNESS: case ADD_HDR_LAYER_INFO_LISTENER: case REMOVE_HDR_LAYER_INFO_LISTENER: case NOTIFY_POWER_BOOST: + case SET_GLOBAL_SHADOW_SETTINGS: + case GET_DISPLAY_DECORATION_SUPPORT: + case SET_FRAME_RATE: + case SET_OVERRIDE_FRAME_RATE: + case SET_FRAME_TIMELINE_INFO: + case ADD_TRANSACTION_TRACE_LISTENER: + case GET_GPU_CONTEXT_PRIORITY: + case GET_MAX_ACQUIRED_BUFFER_COUNT: LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code); return PERMISSION_DENIED; } @@ -5772,15 +5636,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r reply->writeInt32(0); reply->writeInt32(mDebugDisableHWC); return NO_ERROR; - case 1013: { - const auto display = getDefaultDisplayDevice(); - if (!display) { - return NAME_NOT_FOUND; - } - - reply->writeInt32(display->getPageFlipCount()); - return NO_ERROR; - } + case 1013: // Unused. + return NAME_NOT_FOUND; case 1014: { Mutex::Autolock _l(mStateLock); // daltonize @@ -5902,7 +5759,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r (fixedStartingTime) ? fixedStartingTime : systemTime(); mScheduler ->schedule([&]() FTL_FAKE_GUARD(mStateLock) { - mLayerTracing.notify("start", startingTime); + mLayerTracing.notify(true /* visibleRegionDirty */, + startingTime, mLastCommittedVsyncId.value); }) .wait(); } @@ -6010,19 +5868,17 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1034: { - auto future = mScheduler->schedule([&] { - switch (n = data.readInt32()) { - case 0: - case 1: - FTL_FAKE_GUARD(mStateLock, - enableRefreshRateOverlay(static_cast<bool>(n))); - break; - default: { - reply->writeBool( - FTL_FAKE_GUARD(mStateLock, isRefreshRateOverlayEnabled())); - } - } - }); + auto future = mScheduler->schedule( + [&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) { + switch (n = data.readInt32()) { + case 0: + case 1: + enableRefreshRateOverlay(static_cast<bool>(n)); + break; + default: + reply->writeBool(isRefreshRateOverlayEnabled()); + } + }); future.wait(); return NO_ERROR; @@ -6045,7 +5901,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r }(); mDebugDisplayModeSetByBackdoor = false; - const status_t result = setActiveModeFromBackdoor(display, modeId); + const status_t result = setActiveModeFromBackdoor(display, DisplayModeId{modeId}); mDebugDisplayModeSetByBackdoor = result == NO_ERROR; return result; } @@ -6598,7 +6454,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return; } - sp<Layer> p = layer; + auto p = sp<Layer>::fromExisting(layer); while (p != nullptr) { if (excludeLayers.count(p) != 0) { return; @@ -6692,7 +6548,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon( std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get(); if (!renderArea) { ALOGW("Skipping screen capture because of invalid render area."); - captureResults.result = NO_MEMORY; + captureResults.fenceResult = base::unexpected(NO_MEMORY); captureListener->onScreenCaptureCompleted(captureResults); return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } @@ -6705,24 +6561,19 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon( }); if (captureListener) { - // TODO: The future returned by std::async blocks the main thread. Return a chain of - // futures to the Binder thread instead. - std::async([=]() mutable { - ATRACE_NAME("captureListener is nonnull!"); - auto fenceResult = renderFuture.get(); - // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult. - captureResults.result = fenceStatus(fenceResult); - captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE); - captureListener->onScreenCaptureCompleted(captureResults); - }); + // Defer blocking on renderFuture back to the Binder thread. + return ftl::Future(std::move(renderFuture)) + .then([captureListener, captureResults = std::move(captureResults)]( + FenceResult fenceResult) mutable -> FenceResult { + captureResults.fenceResult = std::move(fenceResult); + captureListener->onScreenCaptureCompleted(captureResults); + return base::unexpected(NO_ERROR); + }) + .share(); } return renderFuture; }); - if (captureListener) { - return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); - } - // Flatten nested futures. auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) { return future; @@ -6817,6 +6668,11 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( std::vector<Layer*> renderedLayers; bool disableBlurs = false; traverseLayers([&](Layer* layer) { + // Layer::prepareClientComposition uses the layer's snapshot to populate the resulting + // LayerSettings. Calling Layer::updateSnapshot ensures that LayerSettings are + // generated with the layer's current buffer and geometry. + layer->updateSnapshot(true /* updateGeometry */); + disableBlurs |= layer->getDrawingState().sidebandStream != nullptr; Region clip(renderArea.getBounds()); @@ -6837,27 +6693,25 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( isHdrLayer(layer) ? displayBrightnessNits : sdrWhitePointNits, }; - std::vector<compositionengine::LayerFE::LayerSettings> results = - layer->prepareClientCompositionList(targetSettings); - if (results.size() > 0) { - for (auto& settings : results) { - settings.geometry.positionTransform = - transform.asMatrix4() * settings.geometry.positionTransform; - // There's no need to process blurs when we're executing region sampling, - // we're just trying to understand what we're drawing, and doing so without - // blurs is already a pretty good approximation. - if (regionSampling) { - settings.backgroundBlurRadius = 0; - } - captureResults.capturedHdrLayers |= isHdrLayer(layer); - } + std::optional<compositionengine::LayerFE::LayerSettings> settings = + layer->prepareClientComposition(targetSettings); + if (!settings) { + return; + } - clientCompositionLayers.insert(clientCompositionLayers.end(), - std::make_move_iterator(results.begin()), - std::make_move_iterator(results.end())); - renderedLayers.push_back(layer); + settings->geometry.positionTransform = + transform.asMatrix4() * settings->geometry.positionTransform; + // There's no need to process blurs when we're executing region sampling, + // we're just trying to understand what we're drawing, and doing so without + // blurs is already a pretty good approximation. + if (regionSampling) { + settings->backgroundBlurRadius = 0; + settings->blurRegions.clear(); } + captureResults.capturedHdrLayers |= isHdrLayer(layer); + clientCompositionLayers.push_back(std::move(*settings)); + renderedLayers.push_back(layer); }); std::vector<renderengine::LayerSettings> clientRenderEngineLayers; @@ -6873,13 +6727,11 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( getRenderEngine().useProtectedContext(useProtected); constexpr bool kUseFramebufferCache = false; - auto chain = - ftl::Future(getRenderEngine().drawLayers(clientCompositionDisplay, - clientRenderEngineLayers, buffer, - kUseFramebufferCache, std::move(bufferFence))) - .then(&toFenceResult); + const auto future = getRenderEngine() + .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, + buffer, kUseFramebufferCache, std::move(bufferFence)) + .share(); - const auto future = chain.share(); for (auto* layer : renderedLayers) { layer->onLayerDisplayed(future); } @@ -6890,11 +6742,6 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( return future; } -void SurfaceFlinger::windowInfosReported() { - Mutex::Autolock _l(mStateLock); - signalSynchronousTransactions(CountDownLatch::eSyncInputWindows); -} - // --------------------------------------------------------------------------- void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const { @@ -6933,6 +6780,20 @@ void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const } } +std::optional<DisplayModePtr> SurfaceFlinger::getPreferredDisplayMode( + PhysicalDisplayId displayId, DisplayModeId defaultModeId) const { + if (const auto schedulerMode = mScheduler->getPreferredDisplayMode(); + schedulerMode && schedulerMode->getPhysicalDisplayId() == displayId) { + return schedulerMode; + } + + return mPhysicalDisplays.get(displayId) + .transform(&PhysicalDisplay::snapshotRef) + .and_then([&](const display::DisplaySnapshot& snapshot) { + return snapshot.displayModes().get(defaultModeId); + }); +} + status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( const sp<DisplayDevice>& display, const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) { @@ -6951,42 +6812,40 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( return NO_ERROR; } - scheduler::RefreshRateConfigs::Policy currentPolicy = + const scheduler::RefreshRateConfigs::Policy currentPolicy = display->refreshRateConfigs().getCurrentPolicy(); ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str()); // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might // be depending in this callback. - const auto activeMode = display->getActiveMode(); + const auto activeModePtr = display->refreshRateConfigs().getActiveModePtr(); if (isDisplayActiveLocked(display)) { - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode); + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr); toggleKernelIdleTimer(); } else { - mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode); + mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr); } - const DisplayModePtr preferredDisplayMode = [&] { - const auto schedulerMode = mScheduler->getPreferredDisplayMode(); - if (schedulerMode && schedulerMode->getPhysicalDisplayId() == display->getPhysicalId()) { - return schedulerMode; - } + auto preferredModeOpt = + getPreferredDisplayMode(display->getPhysicalId(), currentPolicy.defaultMode); + if (!preferredModeOpt) { + ALOGE("%s: Preferred mode is unknown", __func__); + return NAME_NOT_FOUND; + } - return display->getMode(currentPolicy.defaultMode); - }(); + auto preferredMode = std::move(*preferredModeOpt); + const auto preferredModeId = preferredMode->getId(); - ALOGV("trying to switch to Scheduler preferred mode %d (%s)", - preferredDisplayMode->getId().value(), to_string(preferredDisplayMode->getFps()).c_str()); + ALOGV("Switching to Scheduler preferred mode %d (%s)", preferredModeId.value(), + to_string(preferredMode->getFps()).c_str()); - if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) { - ALOGV("switching to Scheduler preferred display mode %d", - preferredDisplayMode->getId().value()); - setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed}); - } else { - LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", - preferredDisplayMode->getId().value()); + if (!display->refreshRateConfigs().isModeAllowed(preferredModeId)) { + ALOGE("%s: Preferred mode %d is disallowed", __func__, preferredModeId.value()); + return INVALID_OPERATION; } + setDesiredActiveMode({std::move(preferredMode), DisplayModeEvent::Changed}); return NO_ERROR; } @@ -7127,45 +6986,12 @@ const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayer // on the work to remove the table in that bug rather than adding more to // it. static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{ - {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID}, - {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR}, + {"org.chromium.arc.V1_0.TaskId", gui::METADATA_TASK_ID}, + {"org.chromium.arc.V1_0.CursorInfo", gui::METADATA_MOUSE_CURSOR}, }; return genericLayerMetadataKeyMap; } -status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility, int8_t changeFrameRateStrategy) { - if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, - "SurfaceFlinger::setFrameRate")) { - return BAD_VALUE; - } - - static_cast<void>(mScheduler->schedule([=] { - Mutex::Autolock lock(mStateLock); - if (authenticateSurfaceTextureLocked(surface)) { - sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer(); - if (layer == nullptr) { - ALOGE("Attempt to set frame rate on a layer that no longer exists"); - return BAD_VALUE; - } - const auto strategy = - Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy); - if (layer->setFrameRate( - Layer::FrameRate(Fps::fromValue(frameRate), - Layer::FrameRate::convertCompatibility(compatibility), - strategy))) { - setTransactionFlags(eTraversalNeeded); - } - } else { - ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer"); - return BAD_VALUE; - } - return NO_ERROR; - })); - - return NO_ERROR; -} - status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { PhysicalDisplayId displayId = [&]() { Mutex::Autolock lock(mStateLock); @@ -7177,28 +7003,12 @@ status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { return NO_ERROR; } -status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, - const FrameTimelineInfo& frameTimelineInfo) { - Mutex::Autolock lock(mStateLock); - if (!authenticateSurfaceTextureLocked(surface)) { - ALOGE("Attempt to set frame timeline info on an unrecognized IGraphicBufferProducer"); - return BAD_VALUE; - } - - sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer(); - if (layer == nullptr) { - ALOGE("Attempt to set frame timeline info on a layer that no longer exists"); - return BAD_VALUE; - } - - layer->setFrameTimelineInfoForBuffer(frameTimelineInfo); - return NO_ERROR; -} - void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { - for (const auto& [ignored, display] : mDisplays) { - if (display->isInternal()) { - display->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner); + for (const auto& [id, display] : mPhysicalDisplays) { + if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) { + if (const auto device = getDisplayDeviceLocked(id)) { + device->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner); + } } } } @@ -7214,7 +7024,7 @@ status_t SurfaceFlinger::addTransactionTraceListener( return NO_ERROR; } -int SurfaceFlinger::getGPUContextPriority() { +int SurfaceFlinger::getGpuContextPriority() { return getRenderEngine().getContextPriority(); } @@ -7247,7 +7057,7 @@ uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t ui refreshRate = *frameRateOverride; } else if (!getHwComposer().isHeadless()) { if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) { - refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); + refreshRate = display->refreshRateConfigs().getActiveModePtr()->getFps(); } } @@ -7260,7 +7070,7 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) con return calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } -void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) { +void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, VsyncId vsyncId) { sp<Layer> layer = state.layer.promote(); if (!layer) { ALOGD("Layer was destroyed soon after creation %p", state.layer.unsafe_get()); @@ -7290,7 +7100,9 @@ void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) { } layer->updateTransformHint(mActiveDisplayTransformHint); - + if (mTransactionTracing) { + mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId.value); + } mInterceptor->saveSurfaceCreation(layer); } @@ -7302,7 +7114,7 @@ void SurfaceFlinger::sample() { mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime()); } -void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) { +void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<const DisplayDevice>& activeDisplay) { mScheduler->onActiveDisplayAreaChanged(activeDisplay->getWidth() * activeDisplay->getHeight()); getRenderEngine().onActiveDisplaySizeChanged(activeDisplay->getSize()); } @@ -7374,7 +7186,46 @@ std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextur return buffer; } -bool SurfaceFlinger::commitCreatedLayers() { +bool SurfaceFlinger::commitMirrorDisplays(VsyncId vsyncId) { + std::vector<MirrorDisplayState> mirrorDisplays; + { + std::scoped_lock<std::mutex> lock(mMirrorDisplayLock); + mirrorDisplays = std::move(mMirrorDisplays); + mMirrorDisplays.clear(); + if (mirrorDisplays.size() == 0) { + return false; + } + } + + sp<IBinder> unused; + for (const auto& mirrorDisplay : mirrorDisplays) { + // Set mirror layer's default layer stack to -1 so it doesn't end up rendered on a display + // accidentally. + sp<Layer> rootMirrorLayer = Layer::fromHandle(mirrorDisplay.rootHandle).promote(); + rootMirrorLayer->setLayerStack(ui::LayerStack::fromValue(-1)); + for (const auto& layer : mDrawingState.layersSortedByZ) { + if (layer->getLayerStack() != mirrorDisplay.layerStack || + layer->isInternalDisplayOverlay()) { + continue; + } + + LayerCreationArgs mirrorArgs(this, mirrorDisplay.client, "MirrorLayerParent", + ISurfaceComposerClient::eNoColorFill, + gui::LayerMetadata()); + sp<Layer> childMirror; + createEffectLayer(mirrorArgs, &unused, &childMirror); + childMirror->setClonedChild(layer->createClone()); + if (mTransactionTracing) { + mTransactionTracing->onLayerAddedToDrawingState(childMirror->getSequence(), + vsyncId.value); + } + childMirror->reparent(mirrorDisplay.rootHandle); + } + } + return true; +} + +bool SurfaceFlinger::commitCreatedLayers(VsyncId vsyncId) { std::vector<LayerCreatedState> createdLayers; { std::scoped_lock<std::mutex> lock(mCreatedLayersLock); @@ -7387,33 +7238,92 @@ bool SurfaceFlinger::commitCreatedLayers() { Mutex::Autolock _l(mStateLock); for (const auto& createdLayer : createdLayers) { - handleLayerCreatedLocked(createdLayer); + handleLayerCreatedLocked(createdLayer, vsyncId); } createdLayers.clear(); mLayersAdded = true; return true; } +void SurfaceFlinger::updateLayerMetadataSnapshot() { + LayerMetadata parentMetadata; + for (const auto& layer : mDrawingState.layersSortedByZ) { + layer->updateMetadataSnapshot(parentMetadata); + } + + std::unordered_set<Layer*> visited; + mDrawingState.traverse([&visited](Layer* layer) { + if (visited.find(layer) != visited.end()) { + return; + } + + // If the layer isRelativeOf, then either it's relative metadata will be set + // recursively when updateRelativeMetadataSnapshot is called on its relative parent or + // it's relative parent has been deleted. Clear the layer's relativeLayerMetadata to ensure + // that layers with deleted relative parents don't hold stale relativeLayerMetadata. + if (layer->getDrawingState().isRelativeOf) { + layer->editLayerSnapshot()->relativeLayerMetadata = {}; + return; + } + + layer->updateRelativeMetadataSnapshot({}, visited); + }); +} + // gui::ISurfaceComposer +binder::Status SurfaceComposerAIDL::bootFinished() { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + mFlinger->bootFinished(); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::createDisplayEventConnection( + VsyncSource vsyncSource, EventRegistration eventRegistration, + sp<IDisplayEventConnection>* outConnection) { + sp<IDisplayEventConnection> conn = + mFlinger->createDisplayEventConnection(vsyncSource, eventRegistration); + if (conn == nullptr) { + *outConnection = nullptr; + return binderStatusFromStatusT(BAD_VALUE); + } else { + *outConnection = conn; + return binder::Status::ok(); + } +} + +binder::Status SurfaceComposerAIDL::createConnection(sp<gui::ISurfaceComposerClient>* outClient) { + const sp<Client> client = sp<Client>::make(mFlinger); + if (client->initCheck() == NO_ERROR) { + *outClient = client; + return binder::Status::ok(); + } else { + *outClient = nullptr; + return binderStatusFromStatusT(BAD_VALUE); + } +} + binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure, sp<IBinder>* outDisplay) { status_t status = checkAccessPermission(); - if (status == OK) { - String8 displayName8 = String8::format("%s", displayName.c_str()); - *outDisplay = mFlinger->createDisplay(displayName8, secure); - return binder::Status::ok(); + if (status != OK) { + return binderStatusFromStatusT(status); } - return binder::Status::fromStatusT(status); + String8 displayName8 = String8::format("%s", displayName.c_str()); + *outDisplay = mFlinger->createDisplay(displayName8, secure); + return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) { status_t status = checkAccessPermission(); - if (status == OK) { - mFlinger->destroyDisplay(display); - return binder::Status::ok(); + if (status != OK) { + return binderStatusFromStatusT(status); } - return binder::Status::fromStatusT(status); + mFlinger->destroyDisplay(display); + return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) { @@ -7427,20 +7337,6 @@ binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* return binder::Status::ok(); } -binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) { - status_t status = checkAccessPermission(); - if (status != OK) { - return binder::Status::fromStatusT(status); - } - - PhysicalDisplayId id; - status = mFlinger->getPrimaryPhysicalDisplayId(&id); - if (status == NO_ERROR) { - *outDisplayId = id.value; - } - return binder::Status::fromStatusT(status); -} - binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) { const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId)); @@ -7450,12 +7346,25 @@ binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId, binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->setPowerMode(display, mode); return binder::Status::ok(); } +binder::Status SurfaceComposerAIDL::getSupportedFrameTimestamps( + std::vector<FrameEvent>* outSupported) { + status_t status; + if (!outSupported) { + status = UNEXPECTED_NULL; + } else { + outSupported->clear(); + status = mFlinger->getSupportedFrameTimestamps(outSupported); + } + return binderStatusFromStatusT(status); +} + binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display, gui::DisplayStatInfo* outStatInfo) { DisplayStatInfo statInfo; @@ -7464,7 +7373,7 @@ binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display, outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime); outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod); } - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display, @@ -7477,37 +7386,174 @@ binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display, outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width; outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height; } - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } -binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) { +binder::Status SurfaceComposerAIDL::getStaticDisplayInfo(const sp<IBinder>& display, + gui::StaticDisplayInfo* outInfo) { + using Tag = gui::DeviceProductInfo::ManufactureOrModelDate::Tag; + ui::StaticDisplayInfo info; + status_t status = mFlinger->getStaticDisplayInfo(display, &info); + if (status == NO_ERROR) { + // convert ui::StaticDisplayInfo to gui::StaticDisplayInfo + outInfo->connectionType = static_cast<gui::DisplayConnectionType>(info.connectionType); + outInfo->density = info.density; + outInfo->secure = info.secure; + outInfo->installOrientation = static_cast<gui::Rotation>(info.installOrientation); + + gui::DeviceProductInfo dinfo; + std::optional<DeviceProductInfo> dpi = info.deviceProductInfo; + dinfo.name = std::move(dpi->name); + dinfo.manufacturerPnpId = + std::vector<uint8_t>(dpi->manufacturerPnpId.begin(), dpi->manufacturerPnpId.end()); + dinfo.productId = dpi->productId; + dinfo.relativeAddress = + std::vector<uint8_t>(dpi->relativeAddress.begin(), dpi->relativeAddress.end()); + if (const auto* model = + std::get_if<DeviceProductInfo::ModelYear>(&dpi->manufactureOrModelDate)) { + gui::DeviceProductInfo::ModelYear modelYear; + modelYear.year = model->year; + dinfo.manufactureOrModelDate.set<Tag::modelYear>(modelYear); + } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureYear>( + &dpi->manufactureOrModelDate)) { + gui::DeviceProductInfo::ManufactureYear date; + date.modelYear.year = manufacture->year; + dinfo.manufactureOrModelDate.set<Tag::manufactureYear>(date); + } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureWeekAndYear>( + &dpi->manufactureOrModelDate)) { + gui::DeviceProductInfo::ManufactureWeekAndYear date; + date.manufactureYear.modelYear.year = manufacture->year; + date.week = manufacture->week; + dinfo.manufactureOrModelDate.set<Tag::manufactureWeekAndYear>(date); + } + + outInfo->deviceProductInfo = dinfo; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDynamicDisplayInfo(const sp<IBinder>& display, + gui::DynamicDisplayInfo* outInfo) { + ui::DynamicDisplayInfo info; + status_t status = mFlinger->getDynamicDisplayInfo(display, &info); + if (status == NO_ERROR) { + // convert ui::DynamicDisplayInfo to gui::DynamicDisplayInfo + outInfo->supportedDisplayModes.clear(); + outInfo->supportedDisplayModes.reserve(info.supportedDisplayModes.size()); + for (const auto& mode : info.supportedDisplayModes) { + gui::DisplayMode outMode; + outMode.id = mode.id; + outMode.resolution.width = mode.resolution.width; + outMode.resolution.height = mode.resolution.height; + outMode.xDpi = mode.xDpi; + outMode.yDpi = mode.yDpi; + outMode.refreshRate = mode.refreshRate; + outMode.appVsyncOffset = mode.appVsyncOffset; + outMode.sfVsyncOffset = mode.sfVsyncOffset; + outMode.presentationDeadline = mode.presentationDeadline; + outMode.group = mode.group; + outInfo->supportedDisplayModes.push_back(outMode); + } + + outInfo->activeDisplayModeId = info.activeDisplayModeId; + + outInfo->supportedColorModes.clear(); + outInfo->supportedColorModes.reserve(info.supportedColorModes.size()); + for (const auto& cmode : info.supportedColorModes) { + outInfo->supportedColorModes.push_back(static_cast<int32_t>(cmode)); + } + + outInfo->activeColorMode = static_cast<int32_t>(info.activeColorMode); + + gui::HdrCapabilities& hdrCapabilities = outInfo->hdrCapabilities; + hdrCapabilities.supportedHdrTypes.clear(); + hdrCapabilities.supportedHdrTypes.reserve( + info.hdrCapabilities.getSupportedHdrTypes().size()); + for (const auto& hdr : info.hdrCapabilities.getSupportedHdrTypes()) { + hdrCapabilities.supportedHdrTypes.push_back(static_cast<int32_t>(hdr)); + } + hdrCapabilities.maxLuminance = info.hdrCapabilities.getDesiredMaxLuminance(); + hdrCapabilities.maxAverageLuminance = info.hdrCapabilities.getDesiredMaxAverageLuminance(); + hdrCapabilities.minLuminance = info.hdrCapabilities.getDesiredMinLuminance(); + + outInfo->autoLowLatencyModeSupported = info.autoLowLatencyModeSupported; + outInfo->gameContentTypeSupported = info.gameContentTypeSupported; + outInfo->preferredBootDisplayMode = info.preferredBootDisplayMode; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayNativePrimaries(const sp<IBinder>& display, + gui::DisplayPrimaries* outPrimaries) { + ui::DisplayPrimaries primaries; + status_t status = mFlinger->getDisplayNativePrimaries(display, primaries); + if (status == NO_ERROR) { + outPrimaries->red.X = primaries.red.X; + outPrimaries->red.Y = primaries.red.Y; + outPrimaries->red.Z = primaries.red.Z; + + outPrimaries->green.X = primaries.green.X; + outPrimaries->green.Y = primaries.green.Y; + outPrimaries->green.Z = primaries.green.Z; + + outPrimaries->blue.X = primaries.blue.X; + outPrimaries->blue.Y = primaries.blue.Y; + outPrimaries->blue.Z = primaries.blue.Z; + + outPrimaries->white.X = primaries.white.X; + outPrimaries->white.Y = primaries.white.Y; + outPrimaries->white.Z = primaries.white.Z; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setActiveColorMode(const sp<IBinder>& display, int colorMode) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->setActiveColorMode(display, static_cast<ui::ColorMode>(colorMode)); + } + return binderStatusFromStatusT(status); +} - status = mFlinger->clearBootDisplayMode(display); - return binder::Status::fromStatusT(status); +binder::Status SurfaceComposerAIDL::setBootDisplayMode(const sp<IBinder>& display, + int displayModeId) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->setBootDisplayMode(display, DisplayModeId{displayModeId}); + } + return binderStatusFromStatusT(status); } -binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) { +binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->clearBootDisplayMode(display); + } + return binderStatusFromStatusT(status); +} - status = mFlinger->getBootDisplayModeSupport(outMode); - return binder::Status::fromStatusT(status); +binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->getBootDisplayModeSupport(outMode); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->setAutoLowLatencyMode(display, on); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->setGameContentType(display, on); return binder::Status::ok(); } @@ -7515,7 +7561,7 @@ binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& displa binder::Status SurfaceComposerAIDL::captureDisplay( const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { status_t status = mFlinger->captureDisplay(args, captureListener); - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::captureDisplayById( @@ -7529,60 +7575,431 @@ binder::Status SurfaceComposerAIDL::captureDisplayById( } else { status = PERMISSION_DENIED; } - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::captureLayers( const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { status_t status = mFlinger->captureLayers(args, captureListener); - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp<IBinder>& display, + const std::vector<int32_t>& hdrTypes) { + // overrideHdrTypes is used by CTS tests, which acquire the necessary + // permission dynamically. Don't use the permission cache for this check. + status_t status = checkAccessPermission(false); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + std::vector<ui::Hdr> hdrTypesVector; + for (int32_t i : hdrTypes) { + hdrTypesVector.push_back(static_cast<ui::Hdr>(i)); + } + status = mFlinger->overrideHdrTypes(display, hdrTypesVector); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) { + status_t status; + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid != AID_SYSTEM) { + status = PERMISSION_DENIED; + } else { + status = mFlinger->onPullAtom(atomId, &outPullData->data, &outPullData->success); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::enableVSyncInjections(bool enable) { + if (!mFlinger->hasMockHwc()) { + return binderStatusFromStatusT(PERMISSION_DENIED); + } + + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->enableVSyncInjections(enable); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::injectVSync(int64_t when) { + if (!mFlinger->hasMockHwc()) { + return binderStatusFromStatusT(PERMISSION_DENIED); + } + + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->injectVSync(when); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) { + if (!outLayers) { + return binderStatusFromStatusT(UNEXPECTED_NULL); + } + + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return binderStatusFromStatusT(PERMISSION_DENIED); + } + status_t status = mFlinger->getLayerDebugInfo(outLayers); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getColorManagement(bool* outGetColorManagement) { + status_t status = mFlinger->getColorManagement(outGetColorManagement); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getCompositionPreference(gui::CompositionPreference* outPref) { + ui::Dataspace dataspace; + ui::PixelFormat pixelFormat; + ui::Dataspace wideColorGamutDataspace; + ui::PixelFormat wideColorGamutPixelFormat; + status_t status = + mFlinger->getCompositionPreference(&dataspace, &pixelFormat, &wideColorGamutDataspace, + &wideColorGamutPixelFormat); + if (status == NO_ERROR) { + outPref->defaultDataspace = static_cast<int32_t>(dataspace); + outPref->defaultPixelFormat = static_cast<int32_t>(pixelFormat); + outPref->wideColorGamutDataspace = static_cast<int32_t>(wideColorGamutDataspace); + outPref->wideColorGamutPixelFormat = static_cast<int32_t>(wideColorGamutPixelFormat); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayedContentSamplingAttributes( + const sp<IBinder>& display, gui::ContentSamplingAttributes* outAttrs) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + ui::PixelFormat format; + ui::Dataspace dataspace; + uint8_t componentMask; + status = mFlinger->getDisplayedContentSamplingAttributes(display, &format, &dataspace, + &componentMask); + if (status == NO_ERROR) { + outAttrs->format = static_cast<int32_t>(format); + outAttrs->dataspace = static_cast<int32_t>(dataspace); + outAttrs->componentMask = static_cast<int8_t>(componentMask); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setDisplayContentSamplingEnabled(const sp<IBinder>& display, + bool enable, + int8_t componentMask, + int64_t maxFrames) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->setDisplayContentSamplingEnabled(display, enable, + static_cast<uint8_t>(componentMask), + static_cast<uint64_t>(maxFrames)); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayedContentSample(const sp<IBinder>& display, + int64_t maxFrames, int64_t timestamp, + gui::DisplayedFrameStats* outStats) { + if (!outStats) { + return binderStatusFromStatusT(BAD_VALUE); + } + + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + DisplayedFrameStats stats; + status = mFlinger->getDisplayedContentSample(display, static_cast<uint64_t>(maxFrames), + static_cast<uint64_t>(timestamp), &stats); + if (status == NO_ERROR) { + // convert from ui::DisplayedFrameStats to gui::DisplayedFrameStats + outStats->numFrames = static_cast<int64_t>(stats.numFrames); + outStats->component_0_sample.reserve(stats.component_0_sample.size()); + for (const auto& s : stats.component_0_sample) { + outStats->component_0_sample.push_back(static_cast<int64_t>(s)); + } + outStats->component_1_sample.reserve(stats.component_1_sample.size()); + for (const auto& s : stats.component_1_sample) { + outStats->component_1_sample.push_back(static_cast<int64_t>(s)); + } + outStats->component_2_sample.reserve(stats.component_2_sample.size()); + for (const auto& s : stats.component_2_sample) { + outStats->component_2_sample.push_back(static_cast<int64_t>(s)); + } + outStats->component_3_sample.reserve(stats.component_3_sample.size()); + for (const auto& s : stats.component_3_sample) { + outStats->component_3_sample.push_back(static_cast<int64_t>(s)); + } + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getProtectedContentSupport(bool* outSupported) { + status_t status = mFlinger->getProtectedContentSupport(outSupported); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token, bool* outIsWideColorDisplay) { status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay); - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addRegionSamplingListener( + const gui::ARect& samplingArea, const sp<IBinder>& stopLayerHandle, + const sp<gui::IRegionSamplingListener>& listener) { + status_t status = checkReadFrameBufferPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + android::Rect rect; + rect.left = samplingArea.left; + rect.top = samplingArea.top; + rect.right = samplingArea.right; + rect.bottom = samplingArea.bottom; + status = mFlinger->addRegionSamplingListener(rect, stopLayerHandle, listener); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeRegionSamplingListener( + const sp<gui::IRegionSamplingListener>& listener) { + status_t status = checkReadFrameBufferPermission(); + if (status == OK) { + status = mFlinger->removeRegionSamplingListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addFpsListener(int32_t taskId, + const sp<gui::IFpsListener>& listener) { + status_t status = checkReadFrameBufferPermission(); + if (status == OK) { + status = mFlinger->addFpsListener(taskId, listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeFpsListener(const sp<gui::IFpsListener>& listener) { + status_t status = checkReadFrameBufferPermission(); + if (status == OK) { + status = mFlinger->removeFpsListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->addTunnelModeEnabledListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->removeTunnelModeEnabledListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setDesiredDisplayModeSpecs( + const sp<IBinder>& displayToken, int32_t defaultMode, bool allowGroupSwitching, + float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->setDesiredDisplayModeSpecs(displayToken, + static_cast<ui::DisplayModeId>(defaultMode), + allowGroupSwitching, primaryRefreshRateMin, + primaryRefreshRateMax, + appRequestRefreshRateMin, + appRequestRefreshRateMax); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, + gui::DisplayModeSpecs* outSpecs) { + if (!outSpecs) { + return binderStatusFromStatusT(BAD_VALUE); + } + + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + ui::DisplayModeId displayModeId; + bool allowGroupSwitching; + float primaryRefreshRateMin; + float primaryRefreshRateMax; + float appRequestRefreshRateMin; + float appRequestRefreshRateMax; + status = mFlinger->getDesiredDisplayModeSpecs(displayToken, &displayModeId, + &allowGroupSwitching, &primaryRefreshRateMin, + &primaryRefreshRateMax, &appRequestRefreshRateMin, + &appRequestRefreshRateMax); + if (status == NO_ERROR) { + outSpecs->defaultMode = displayModeId; + outSpecs->allowGroupSwitching = allowGroupSwitching; + outSpecs->primaryRefreshRateMin = primaryRefreshRateMin; + outSpecs->primaryRefreshRateMax = primaryRefreshRateMax; + outSpecs->appRequestRefreshRateMin = appRequestRefreshRateMin; + outSpecs->appRequestRefreshRateMax = appRequestRefreshRateMax; + } + + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) { status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport); - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken, const gui::DisplayBrightness& brightness) { status_t status = checkControlDisplayBrightnessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - - status = mFlinger->setDisplayBrightness(displayToken, brightness); - return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->setDisplayBrightness(displayToken, brightness); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener( const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { status_t status = checkControlDisplayBrightnessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - - status = mFlinger->addHdrLayerInfoListener(displayToken, listener); - return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->addHdrLayerInfoListener(displayToken, listener); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener( const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { status_t status = checkControlDisplayBrightnessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - - status = mFlinger->removeHdrLayerInfoListener(displayToken, listener); - return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->removeHdrLayerInfoListener(displayToken, listener); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->notifyPowerBoost(boostId); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setGlobalShadowSettings(const gui::Color& ambientColor, + const gui::Color& spotColor, + float lightPosY, float lightPosZ, + float lightRadius) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } - status = mFlinger->notifyPowerBoost(boostId); - return binder::Status::fromStatusT(status); + half4 ambientColorHalf = {ambientColor.r, ambientColor.g, ambientColor.b, ambientColor.a}; + half4 spotColorHalf = {spotColor.r, spotColor.g, spotColor.b, spotColor.a}; + status = mFlinger->setGlobalShadowSettings(ambientColorHalf, spotColorHalf, lightPosY, + lightPosZ, lightRadius); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayDecorationSupport( + const sp<IBinder>& displayToken, std::optional<gui::DisplayDecorationSupport>* outSupport) { + std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> support; + status_t status = mFlinger->getDisplayDecorationSupport(displayToken, &support); + if (status != NO_ERROR) { + ALOGE("getDisplayDecorationSupport failed with error %d", status); + return binderStatusFromStatusT(status); + } + + if (!support || !support.has_value()) { + outSupport->reset(); + } else { + outSupport->emplace(); + outSupport->value().format = static_cast<int32_t>(support->format); + outSupport->value().alphaInterpretation = + static_cast<int32_t>(support->alphaInterpretation); + } + + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::setOverrideFrameRate(int32_t uid, float frameRate) { + status_t status; + const int c_uid = IPCThreadState::self()->getCallingUid(); + if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) { + status = mFlinger->setOverrideFrameRate(uid, frameRate); + } else { + ALOGE("setOverrideFrameRate() permission denied for uid: %d", c_uid); + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addTransactionTraceListener( + const sp<gui::ITransactionTraceListener>& listener) { + status_t status; + IPCThreadState* ipc = IPCThreadState::self(); + const int uid = ipc->getCallingUid(); + if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { + status = mFlinger->addTransactionTraceListener(listener); + } else { + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getGpuContextPriority(int32_t* outPriority) { + *outPriority = mFlinger->getGpuContextPriority(); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::getMaxAcquiredBufferCount(int32_t* buffers) { + status_t status = mFlinger->getMaxAcquiredBufferCount(buffers); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) { + status_t status; + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_SYSTEM || uid == AID_GRAPHICS) { + status = mFlinger->addWindowInfosListener(windowInfosListener); + } else { + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) { + status_t status; + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_SYSTEM || uid == AID_GRAPHICS) { + status = mFlinger->removeWindowInfosListener(windowInfosListener); + } else { + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); } status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) { @@ -7607,6 +8024,17 @@ status_t SurfaceComposerAIDL::checkControlDisplayBrightnessPermission() { return OK; } +status_t SurfaceComposerAIDL::checkReadFrameBufferPermission() { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS) && !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + return OK; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 2cd304e79c..85d11bad04 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -25,15 +25,16 @@ #include <android/gui/BnSurfaceComposer.h> #include <android/gui/DisplayStatInfo.h> #include <android/gui/DisplayState.h> +#include <android/gui/ISurfaceComposerClient.h> #include <cutils/atomic.h> #include <cutils/compiler.h> #include <ftl/future.h> -#include <ftl/small_map.h> #include <gui/BufferQueue.h> +#include <gui/CompositorTiming.h> #include <gui/FrameTimestamps.h> #include <gui/ISurfaceComposer.h> -#include <gui/ISurfaceComposerClient.h> #include <gui/ITransactionCompletedListener.h> +#include <gui/LayerDebugInfo.h> #include <gui/LayerState.h> #include <layerproto/LayerProtoHeader.h> #include <math/mat4.h> @@ -50,11 +51,15 @@ #include <utils/Trace.h> #include <utils/threads.h> -#include <compositionengine/FenceResult.h> #include <compositionengine/OutputColorSetting.h> #include <scheduler/Fps.h> +#include <scheduler/PresentLatencyTracker.h> +#include <scheduler/Time.h> +#include <ui/FenceResult.h> #include "ClientCache.h" +#include "Display/DisplayMap.h" +#include "Display/PhysicalDisplay.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" #include "DisplayHardware/PowerAdvisor.h" @@ -63,6 +68,7 @@ #include "FlagManager.h" #include "FrameTracker.h" #include "LayerVector.h" +#include "LocklessQueue.h" #include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/RefreshRateStats.h" #include "Scheduler/Scheduler.h" @@ -92,12 +98,12 @@ #include <utility> #include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h> +#include "Client.h" using namespace android::surfaceflinger; namespace android { -class Client; class EventThread; class FlagManager; class FpsReporter; @@ -166,24 +172,6 @@ enum class LatchUnsignaledConfig { using DisplayColorSetting = compositionengine::OutputColorSetting; -struct SurfaceFlingerBE { - // protected by mCompositorTimingLock; - mutable std::mutex mCompositorTimingLock; - CompositorTiming mCompositorTiming; - - // Only accessed from the main thread. - struct CompositePresentTime { - nsecs_t composite = -1; - std::shared_ptr<FenceTime> display = FenceTime::NO_FENCE; - }; - std::queue<CompositePresentTime> mCompositePresentTimes; - - static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ - nsecs_t mFrameBuckets[NUM_BUCKETS] = {}; - nsecs_t mTotalTime = 0; - std::atomic<nsecs_t> mLastSwapTime = 0; -}; - class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, private IBinder::DeathRecipient, @@ -204,29 +192,6 @@ public: static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } - // This is the phase offset in nanoseconds of the software vsync event - // relative to the vsync event reported by HWComposer. The software vsync - // event is when SurfaceFlinger and Choreographer-based applications run each - // frame. - // - // This phase offset allows adjustment of the minimum latency from application - // wake-up time (by Choreographer) to the time at which the resulting window - // image is displayed. This value may be either positive (after the HW vsync) - // or negative (before the HW vsync). Setting it to 0 will result in a lower - // latency bound of two vsync periods because the app and SurfaceFlinger - // will run just after the HW vsync. Setting it to a positive number will - // result in the minimum latency being: - // - // (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD)) - // - // Note that reducing this latency makes it more likely for the applications - // to not have their window content image ready in time. When this happens - // the latency will end up being an additional vsync period, and animations - // will hiccup. Therefore, this latency should be tuned somewhat - // conservatively (or at least with awareness of the trade-off being made). - static int64_t vsyncPhaseOffsetNs; - static int64_t sfVsyncPhaseOffsetNs; - // If fences from sync Framework are supported. static bool hasSyncFramework; @@ -280,9 +245,6 @@ public: // starts SurfaceFlinger main loop in the current thread void run() ANDROID_API; - SurfaceFlingerBE& getBE() { return mBE; } - const SurfaceFlingerBE& getBE() const { return mBE; } - // Indicates frame activity, i.e. whether commit and/or composite is taking place. enum class FrameHint { kNone, kActive }; @@ -309,9 +271,6 @@ public: renderengine::RenderEngine& getRenderEngine() const; - bool authenticateSurfaceTextureLocked( - const sp<IGraphicBufferProducer>& bufferProducer) const; - void onLayerFirstRef(Layer*); void onLayerDestroyed(Layer*); void onLayerUpdate(); @@ -335,7 +294,6 @@ public: // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; - void windowInfosReported(); // Disables expensive rendering for all displays // This is scheduled on the main thread @@ -375,13 +333,10 @@ protected: private: friend class BufferLayer; - friend class BufferQueueLayer; - friend class BufferStateLayer; friend class Client; friend class FpsReporter; friend class TunnelModeEnabledReporter; friend class Layer; - friend class MonitoredProducer; friend class RefreshRateOverlay; friend class RegionSamplingThread; friend class LayerRenderArea; @@ -399,10 +354,6 @@ private: using DumpArgs = Vector<String16>; using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>; - // This value is specified in number of frames. Log frame stats at most - // every half hour. - enum { LOG_FRAME_STATS_PERIOD = 30*60*60 }; - class State { public: explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {} @@ -422,7 +373,20 @@ private: const LayerVector::StateSet stateSet = LayerVector::StateSet::Invalid; LayerVector layersSortedByZ; - DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays; + + // TODO(b/241285876): Replace deprecated DefaultKeyedVector with ftl::SmallMap. + DefaultKeyedVector<wp<IBinder>, DisplayDeviceState> displays; + + std::optional<size_t> getDisplayIndex(PhysicalDisplayId displayId) const { + for (size_t i = 0; i < displays.size(); i++) { + const auto& state = displays.valueAt(i); + if (state.physical && state.physical->id == displayId) { + return i; + } + } + + return {}; + } bool colorMatrixChanged = true; mat4 colorMatrix; @@ -481,11 +445,6 @@ private: FINISHED, }; - struct HotplugEvent { - hal::HWDisplayId hwcDisplayId; - hal::Connection connection = hal::Connection::INVALID; - }; - template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr> static Dumper dumper(F&& dump) { using namespace std::placeholders; @@ -519,10 +478,11 @@ private: } } - static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB // Maximum allowed number of display frames that can be set through backdoor static const int MAX_ALLOWED_DISPLAY_FRAMES = 2048; + static const size_t MAX_LAYERS = 4096; + // Implements IBinder. status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override; status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); } @@ -530,14 +490,12 @@ private: EXCLUDES(mStateLock); // Implements ISurfaceComposer - sp<ISurfaceComposerClient> createConnection() override; sp<IBinder> createDisplay(const String8& displayName, bool secure); void destroyDisplay(const sp<IBinder>& displayToken); std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) { Mutex::Autolock lock(mStateLock); return getPhysicalDisplayIdsLocked(); } - status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const EXCLUDES(mStateLock); sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const; status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, @@ -549,13 +507,12 @@ private: const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) override; - void bootFinished() override; - bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const override; - status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override; + void bootFinished(); + virtual status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const; sp<IDisplayEventConnection> createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override; + gui::ISurfaceComposer::VsyncSource vsyncSource = + gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + EventRegistrationFlags eventRegistration = {}); status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&); status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&); @@ -565,62 +522,56 @@ private: status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) EXCLUDES(mStateLock); status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*) - EXCLUDES(mStateLock) override; + EXCLUDES(mStateLock); status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*) - EXCLUDES(mStateLock) override; - status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken, - ui::DisplayPrimaries&) override; - status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override; + EXCLUDES(mStateLock); + status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken, ui::DisplayPrimaries&); + status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode); status_t getBootDisplayModeSupport(bool* outSupport) const; - status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override; + status_t setBootDisplayMode(const sp<display::DisplayToken>&, DisplayModeId); status_t clearBootDisplayMode(const sp<IBinder>& displayToken); void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on); void setGameContentType(const sp<IBinder>& displayToken, bool on); void setPowerMode(const sp<IBinder>& displayToken, int mode); - status_t clearAnimationFrameStats() override; - status_t getAnimationFrameStats(FrameStats* outStats) const override; status_t overrideHdrTypes(const sp<IBinder>& displayToken, - const std::vector<ui::Hdr>& hdrTypes) override; - status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) override; - status_t enableVSyncInjections(bool enable) override; - status_t injectVSync(nsecs_t when) override; - status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override; - status_t getColorManagement(bool* outGetColorManagement) const override; + const std::vector<ui::Hdr>& hdrTypes); + status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success); + status_t enableVSyncInjections(bool enable); + status_t injectVSync(nsecs_t when); + status_t getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers); + status_t getColorManagement(bool* outGetColorManagement) const; status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, ui::Dataspace* outWideColorGamutDataspace, - ui::PixelFormat* outWideColorGamutPixelFormat) const override; + ui::PixelFormat* outWideColorGamutPixelFormat) const; status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const override; + uint8_t* outComponentMask) const; status_t setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken, bool enable, - uint8_t componentMask, uint64_t maxFrames) override; + uint8_t componentMask, uint64_t maxFrames); status_t getDisplayedContentSample(const sp<IBinder>& displayToken, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const override; - status_t getProtectedContentSupport(bool* outSupported) const override; + uint64_t timestamp, DisplayedFrameStats* outStats) const; + status_t getProtectedContentSupport(bool* outSupported) const; status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const; status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, - const sp<IRegionSamplingListener>& listener) override; - status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override; - status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) override; - status_t removeFpsListener(const sp<gui::IFpsListener>& listener) override; - status_t addTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) override; - status_t removeTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) override; + const sp<IRegionSamplingListener>& listener); + status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener); + status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener); + status_t removeFpsListener(const sp<gui::IFpsListener>& listener); + status_t addTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& listener); + status_t removeTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& listener); status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, ui::DisplayModeId displayModeId, bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, - float appRequestRefreshRateMax) override; + float appRequestRefreshRateMax); status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, ui::DisplayModeId* outDefaultMode, bool* outAllowGroupSwitching, float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax, float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) override; + float* outAppRequestRefreshRateMax); status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const; status_t setDisplayBrightness(const sp<IBinder>& displayToken, const gui::DisplayBrightness& brightness); @@ -630,36 +581,34 @@ private: const sp<gui::IHdrLayerInfoListener>& listener); status_t notifyPowerBoost(int32_t boostId); status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, float lightRadius) override; + float lightPosY, float lightPosZ, float lightRadius); status_t getDisplayDecorationSupport( const sp<IBinder>& displayToken, std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* - outSupport) const override; + outSupport) const; status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility, int8_t changeFrameRateStrategy) override; + int8_t compatibility, int8_t changeFrameRateStrategy); status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, - const FrameTimelineInfo& frameTimelineInfo) override; + const gui::FrameTimelineInfo& frameTimelineInfo); - status_t setOverrideFrameRate(uid_t uid, float frameRate) override; + status_t setOverrideFrameRate(uid_t uid, float frameRate); - status_t addTransactionTraceListener( - const sp<gui::ITransactionTraceListener>& listener) override; + status_t addTransactionTraceListener(const sp<gui::ITransactionTraceListener>& listener); - int getGPUContextPriority() override; + int getGpuContextPriority(); - status_t getMaxAcquiredBufferCount(int* buffers) const override; + status_t getMaxAcquiredBufferCount(int* buffers) const; - status_t addWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) const override; + status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener) const; status_t removeWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) const override; + const sp<gui::IWindowInfosListener>& windowInfosListener) const; // Implements IBinder::DeathRecipient. void binderDied(const wp<IBinder>& who) override; // HWC2::ComposerCallback overrides: - void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp, + void onComposerHalVsync(hal::HWDisplayId, nsecs_t timestamp, std::optional<hal::VsyncPeriodNanos>) override; void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) override; void onComposerHalRefresh(hal::HWDisplayId) override; @@ -670,20 +619,21 @@ private: // ICompositor overrides: + // Configures physical displays, processing hotplug and/or mode setting via the Composer HAL. + void configure() override; + // Commits transactions for layers and displays. Returns whether any state has been invalidated, // i.e. whether a frame should be composited for each display. - bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) override; + bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) override; // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition // via RenderEngine and the Composer HAL, respectively. - void composite(nsecs_t frameTime, int64_t vsyncId) override; + void composite(TimePoint frameTime, VsyncId) override; // Samples the composited frame via RegionSamplingThread. void sample() override; - /* - * ISchedulerCallback - */ + // ISchedulerCallback overrides: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; @@ -693,6 +643,7 @@ private: void kernelTimerChanged(bool expired) override; // Called when the frame rate override list changed to trigger an event. void triggerOnFrameRateOverridesChanged() override; + // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. void toggleKernelIdleTimer() REQUIRES(mStateLock); // Get the controller and timeout that will help decide how the kernel idle timer will be @@ -709,40 +660,46 @@ private: // Show spinner with refresh rate overlay bool mRefreshRateOverlaySpinner = false; - // Called on the main thread in response to initializeDisplays() - void onInitializeDisplays() REQUIRES(mStateLock); // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode. void setDesiredActiveMode(const ActiveModeInfo& info) REQUIRES(mStateLock); - status_t setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int id); + status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId); // Sets the active mode and a new refresh rate in SF. - void updateInternalStateWithChangedMode() REQUIRES(mStateLock); + void updateInternalStateWithChangedMode() REQUIRES(mStateLock, kMainThreadContext); // Calls to setActiveMode on the main thread if there is a pending mode change // that needs to be applied. - void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock); + void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock, kMainThreadContext); void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock); // Called when active mode is no longer is progress void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock); // Called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) - REQUIRES(mStateLock); + REQUIRES(mStateLock, kMainThreadContext); // Returns true if the display has a visible HDR layer in its layer stack. bool hasVisibleHdrLayer(const sp<DisplayDevice>& display) REQUIRES(mStateLock); + // Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that + // display. Falls back to the display's defaultModeId otherwise. + std::optional<DisplayModePtr> getPreferredDisplayMode(PhysicalDisplayId, + DisplayModeId defaultModeId) const + REQUIRES(mStateLock); + // Sets the desired display mode specs. status_t setDesiredDisplayModeSpecsInternal( const sp<DisplayDevice>& display, const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) EXCLUDES(mStateLock); - void commitTransactions() EXCLUDES(mStateLock); - void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock); + void commitTransactions() EXCLUDES(mStateLock) REQUIRES(kMainThreadContext); + void commitTransactionsLocked(uint32_t transactionFlags) + REQUIRES(mStateLock, kMainThreadContext); void doCommitTransactions() REQUIRES(mStateLock); // Returns whether a new buffer has been latched. bool latchBuffers(); void updateLayerGeometry(); + void updateLayerMetadataSnapshot(); void updateInputFlinger(); void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext); @@ -751,7 +708,7 @@ private: void commitInputWindowCommands() REQUIRES(mStateLock); void updateCursorAsync(); - void initScheduler(const sp<DisplayDevice>& display) REQUIRES(mStateLock); + void initScheduler(const sp<const DisplayDevice>&) REQUIRES(mStateLock); void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock); void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod); @@ -768,22 +725,15 @@ private: const std::vector<ListenerCallbacks>& listenerCallbacks, int originPid, int originUid, uint64_t transactionId) REQUIRES(mStateLock); - // flush pending transaction that was presented after desiredPresentTime. - bool flushTransactionQueues(int64_t vsyncId); + // Flush pending transactions that were presented after desiredPresentTime. + bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext); // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); int flushPendingTransactionQueues( std::vector<TransactionState>& transactions, std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, - std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions, - bool tryApplyUnsignaled) REQUIRES(mStateLock, mQueueLock); - - int flushUnsignaledPendingTransactionQueues( - std::vector<TransactionState>& transactions, - std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, - std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions) - REQUIRES(mStateLock, mQueueLock); + bool tryApplyUnsignaled) REQUIRES(mStateLock) REQUIRES(kMainThreadContext); uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&, int64_t desiredPresentTime, bool isAutoTimestamp, @@ -807,23 +757,24 @@ private: Ready, ReadyUnsignaled, }; - TransactionReadiness transactionIsReadyToBeApplied(TransactionState& state, - const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, - uid_t originUid, const Vector<ComposerState>& states, - const std::unordered_map< - sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, - size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock); + TransactionReadiness transactionIsReadyToBeApplied( + TransactionState&, const FrameTimelineInfo&, bool isAutoTimestamp, + TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>&, + const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& + bufferLayersReadyToPresent, + size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock) + REQUIRES(kMainThreadContext); + static LatchUnsignaledConfig getLatchUnsignaledConfig(); bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates, size_t totalTXapplied) const; - bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& - applyTokensWithUnsignaledTransactions) const; - bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId) + bool applyTransactions(std::vector<TransactionState>& transactions, VsyncId) REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); - bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const; + bool frameIsEarly(TimePoint expectedPresentTime, VsyncId) const; + /* * Layer management */ @@ -832,22 +783,18 @@ private: const sp<Layer>& parentLayer = nullptr, uint32_t* outTransformHint = nullptr); - status_t createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, - sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp, - sp<Layer>* outLayer); - status_t createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* outHandle, sp<Layer>* outLayer); status_t createEffectLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle, sp<Layer>* outLayer); - status_t createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle, - sp<Layer>* outLayer); - status_t mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle, int32_t* outLayerId); + status_t mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args, + sp<IBinder>* outHandle, int32_t* outLayerId); + // called when all clients have released all their references to // this layer meaning it is entirely safe to destroy all // resources associated to this layer. @@ -889,8 +836,14 @@ private: /* * Display and layer stack management */ - // called when starting, or restarting after system_server death + + // Called during boot, and restart after system_server death. void initializeDisplays(); + void onInitializeDisplays() REQUIRES(mStateLock, kMainThreadContext); + + bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) { + return display->getDisplayToken() == mActiveDisplayToken; + } sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const REQUIRES(mStateLock) { @@ -939,6 +892,21 @@ private: return getDefaultDisplayDeviceLocked(); } + using DisplayDeviceAndSnapshot = + std::pair<sp<DisplayDevice>, display::PhysicalDisplay::SnapshotRef>; + + // Combinator for ftl::Optional<PhysicalDisplay>::and_then. + auto getDisplayDeviceAndSnapshot() REQUIRES(mStateLock) { + return [this](const display::PhysicalDisplay& display) REQUIRES( + mStateLock) -> ftl::Optional<DisplayDeviceAndSnapshot> { + if (auto device = getDisplayDeviceLocked(display.snapshot().displayId())) { + return std::make_pair(std::move(device), display.snapshotRef()); + } + + return {}; + }; + } + // Returns the first display that matches a `bool(const DisplayDevice&)` predicate. template <typename Predicate> sp<DisplayDevice> findDisplay(Predicate p) const REQUIRES(mStateLock) { @@ -954,8 +922,13 @@ private: // region of all screens presenting this layer stack. void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty); - bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) { - return display->getDisplayToken() == mActiveDisplayToken; + ui::LayerFilter makeLayerFilterForDisplay(DisplayId displayId, ui::LayerStack layerStack) + REQUIRES(mStateLock) { + return {layerStack, + PhysicalDisplayId::tryCast(displayId) + .and_then(display::getPhysicalDisplay(mPhysicalDisplays)) + .transform(&display::PhysicalDisplay::isInternal) + .value_or(false)}; } /* @@ -972,14 +945,7 @@ private: /* * Compositing */ - void postComposition(); - void getCompositorTiming(CompositorTiming* compositorTiming); - void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, - std::shared_ptr<FenceTime>& presentFenceTime); - void setCompositorTimingSnapped(const DisplayStatInfo& stats, - nsecs_t compositeToPresentLatency); - - void postFrame() REQUIRES(kMainThreadContext); + void postComposition() REQUIRES(kMainThreadContext); /* * Display management @@ -987,18 +953,30 @@ private: std::pair<DisplayModes, DisplayModePtr> loadDisplayModes(PhysicalDisplayId) const REQUIRES(mStateLock); + // TODO(b/241285876): Move to DisplayConfigurator. + // + // Returns whether displays have been added/changed/removed, i.e. whether ICompositor should + // commit display transactions. + bool configureLocked() REQUIRES(mStateLock) REQUIRES(kMainThreadContext) + EXCLUDES(mHotplugMutex); + + // Returns a string describing the hotplug, or nullptr if it was rejected. + const char* processHotplug(PhysicalDisplayId, hal::HWDisplayId, bool connected, + DisplayIdentificationInfo&&) REQUIRES(mStateLock) + REQUIRES(kMainThreadContext); + sp<DisplayDevice> setupNewDisplayDeviceInternal( const wp<IBinder>& displayToken, std::shared_ptr<compositionengine::Display> compositionDisplay, const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer) REQUIRES(mStateLock); - void processDisplayChangesLocked() REQUIRES(mStateLock); + void processDisplayChangesLocked() REQUIRES(mStateLock, kMainThreadContext); void processDisplayRemoved(const wp<IBinder>& displayToken) REQUIRES(mStateLock); void processDisplayChanged(const wp<IBinder>& displayToken, const DisplayDeviceState& currentState, - const DisplayDeviceState& drawingState) REQUIRES(mStateLock); - void processDisplayHotplugEventsLocked() REQUIRES(mStateLock); + const DisplayDeviceState& drawingState) + REQUIRES(mStateLock, kMainThreadContext); void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected); @@ -1012,50 +990,31 @@ private: getHwComposer().setVsyncEnabled(id, enabled); } - struct FenceWithFenceTime { - sp<Fence> fence = Fence::NO_FENCE; - std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE; - }; - - // Gets the fence for the previous frame. - // Must be called on the main thread. - FenceWithFenceTime previousFrameFence(); + using FenceTimePtr = std::shared_ptr<FenceTime>; - // Whether the previous frame has not yet been presented to the display. - // If graceTimeMs is positive, this method waits for at most the provided - // grace period before reporting if the frame missed. - // Must be called on the main thread. - bool previousFramePending(int graceTimeMs = 0); + const FenceTimePtr& getPreviousPresentFence(TimePoint frameTime, Period) + REQUIRES(kMainThreadContext); - // Returns the previous time that the frame was presented. If the frame has - // not been presented yet, then returns Fence::SIGNAL_TIME_PENDING. If there - // is no pending frame, then returns Fence::SIGNAL_TIME_INVALID. - // Must be called on the main thread. - nsecs_t previousFramePresentTime(); + // Blocks the thread waiting for up to graceTimeMs in case the fence is about to signal. + static bool isFencePending(const FenceTimePtr&, int graceTimeMs); // Calculates the expected present time for this frame. For negative offsets, performs a // correction using the predicted vsync for the next frame instead. - - nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const; + TimePoint calculateExpectedPresentTime(TimePoint frameTime) const; /* * Display identification */ - sp<IBinder> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const + sp<display::DisplayToken> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const REQUIRES(mStateLock) { - const sp<IBinder> nullToken; - return mPhysicalDisplayTokens.get(displayId).value_or(std::cref(nullToken)); + const sp<display::DisplayToken> nullToken; + return mPhysicalDisplays.get(displayId) + .transform([](const display::PhysicalDisplay& display) { return display.token(); }) + .value_or(std::cref(nullToken)); } std::optional<PhysicalDisplayId> getPhysicalDisplayIdLocked( - const sp<IBinder>& displayToken) const REQUIRES(mStateLock) { - for (const auto& [id, token] : mPhysicalDisplayTokens) { - if (token == displayToken) { - return id; - } - } - return {}; - } + const sp<display::DisplayToken>&) const REQUIRES(mStateLock); // Returns the first display connected at boot. // @@ -1078,15 +1037,17 @@ private: VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock); void releaseVirtualDisplay(VirtualDisplayId); - void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) REQUIRES(mStateLock); + void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) + REQUIRES(mStateLock, kMainThreadContext); - void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay); + void onActiveDisplaySizeChanged(const sp<const DisplayDevice>&); /* * Debugging & dumpsys */ void dumpAllLocked(const DumpArgs& args, const std::string& compositionLayers, std::string& result) const REQUIRES(mStateLock); + void dumpHwcLayersMinidumpLocked(std::string& result) const REQUIRES(mStateLock); void appendSfConfigString(std::string& result) const; void listLayersLocked(std::string& result) const; @@ -1094,10 +1055,9 @@ private: void clearStatsLocked(const DumpArgs& args, std::string& result); void dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const; void dumpFrameTimeline(const DumpArgs& args, std::string& result) const; - void logFrameStats() REQUIRES(kMainThreadContext); + void logFrameStats(TimePoint now) REQUIRES(kMainThreadContext); void dumpVSync(std::string& result) const REQUIRES(mStateLock); - void dumpStaticScreenStats(std::string& result) const; void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock); void dumpDisplays(std::string& result) const REQUIRES(mStateLock); @@ -1134,7 +1094,7 @@ private: status_t CheckTransactCodeCredentials(uint32_t code); // Add transaction to the Transaction Queue - void queueTransaction(TransactionState& state) EXCLUDES(mQueueLock); + void queueTransaction(TransactionState& state); void waitForSynchronousTransaction(const CountDownLatch& transactionCommittedSignal); void signalSynchronousTransactions(const uint32_t flag); @@ -1146,14 +1106,14 @@ private: /* * Misc */ - std::vector<ui::ColorMode> getDisplayColorModes(const DisplayDevice&) REQUIRES(mStateLock); + std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId) REQUIRES(mStateLock); static int calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency); int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const; void updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) - REQUIRES(mStateLock); + REQUIRES(mStateLock, kMainThreadContext); bool isHdrLayer(Layer* layer) const; @@ -1170,7 +1130,6 @@ private: State mCurrentState{LayerVector::StateSet::Current}; std::atomic<int32_t> mTransactionFlags = 0; std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals; - bool mAnimTransactionPending = false; std::atomic<uint32_t> mUniqueTransactionId = 1; SortedVector<sp<Layer>> mLayersPendingRemoval; @@ -1179,7 +1138,7 @@ private: float mGlobalSaturationFactor = 1.0f; mat4 mClientColorMatrix; - size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS; + size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS; // If there are more GraphicBufferProducers tracked by SurfaceFlinger than // this threshold, then begin logging. size_t mGraphicBufferProducerListSizeLogThreshold = @@ -1213,20 +1172,20 @@ private: // Set during transaction application stage to track if the input info or children // for a layer has changed. // TODO: Also move visibleRegions over to a boolean system. - bool mInputInfoChanged = false; + bool mUpdateInputInfo = false; bool mSomeChildrenChanged; bool mSomeDataspaceChanged = false; bool mForceTransactionDisplayChange = false; - bool mAnimCompositionPending = false; + // Set if LayerMetadata has changed since the last LayerMetadata snapshot. + bool mLayerMetadataSnapshotNeeded = false; // Tracks layers that have pending frames which are candidates for being // latched. std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames; // Tracks layers that need to update a display's dirty region. std::vector<sp<Layer>> mLayersPendingRefresh; - // size should be longest sf-duration / shortest vsync period and round up - std::array<FenceWithFenceTime, 5> mPreviousPresentFences; // currently consider 166hz. + // True if in the previous frame at least one layer was composed via the GPU. bool mHadClientComposition = false; // True if in the previous frame at least one layer was composed via HW Composer. @@ -1240,17 +1199,21 @@ private: BootStage mBootStage = BootStage::BOOTLOADER; - std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mStateLock); + struct HotplugEvent { + hal::HWDisplayId hwcDisplayId; + hal::Connection connection = hal::Connection::INVALID; + }; + + std::mutex mHotplugMutex; + std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex); // Displays are composited in `mDisplays` order. Internal displays are inserted at boot and // never removed, so take precedence over external and virtual displays. // - // The static capacities were chosen to exceed a typical number of physical/virtual displays. - // // May be read from any thread, but must only be written from the main thread. - ftl::SmallMap<wp<IBinder>, const sp<DisplayDevice>, 5> mDisplays GUARDED_BY(mStateLock); - ftl::SmallMap<PhysicalDisplayId, const sp<IBinder>, 3> mPhysicalDisplayTokens - GUARDED_BY(mStateLock); + display::DisplayMap<wp<IBinder>, const sp<DisplayDevice>> mDisplays GUARDED_BY(mStateLock); + + display::PhysicalDisplays mPhysicalDisplays GUARDED_BY(mStateLock); struct { DisplayIdGenerator<GpuVirtualDisplayId> gpu; @@ -1277,6 +1240,8 @@ private: const std::unique_ptr<FrameTracer> mFrameTracer; const std::unique_ptr<frametimeline::FrameTimeline> mFrameTimeline; + VsyncId mLastCommittedVsyncId; + // If blurs should be enabled on this device. bool mSupportsBlur = false; // If blurs are considered expensive and should require high GPU frequency. @@ -1287,9 +1252,6 @@ private: TransactionCallbackInvoker mTransactionCallbackInvoker; - // Thread-safe. - FrameTracker mAnimFrameTracker; - // We maintain a pool of pre-generated texture names to hand out to avoid // layer creation needing to run on the main thread (which it would // otherwise need to do to access RenderEngine). @@ -1297,18 +1259,10 @@ private: uint32_t mTexturePoolSize = 0; std::vector<uint32_t> mTexturePool; - mutable Mutex mQueueLock; - Condition mTransactionQueueCV; std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> - mPendingTransactionQueues GUARDED_BY(mQueueLock); - std::deque<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock); - /* - * Feature prototyping - */ - - // Static screen stats - bool mHasPoweredOff = false; - + mPendingTransactionQueues; + LocklessQueue<TransactionState> mLocklessTransactionQueue; + std::atomic<size_t> mPendingTransactionCount = 0; std::atomic<size_t> mNumLayers = 0; // to linkToDeath @@ -1336,7 +1290,6 @@ private: ui::Dataspace mColorSpaceAgnosticDataspace; float mDimmingRatio = -1.f; - SurfaceFlingerBE mBE; std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine; // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by // any mutex. @@ -1360,9 +1313,17 @@ private: sp<VsyncModulator> mVsyncModulator; std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; + scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext); + + struct FenceWithFenceTime { + sp<Fence> fence = Fence::NO_FENCE; + FenceTimePtr fenceTime = FenceTime::NO_FENCE; + }; + std::array<FenceWithFenceTime, 2> mPreviousPresentFences; + + TimePoint mScheduledPresentTime GUARDED_BY(kMainThreadContext); + TimePoint mExpectedPresentTime GUARDED_BY(kMainThreadContext); - std::atomic<nsecs_t> mExpectedPresentTime = 0; - nsecs_t mScheduledPresentTime = 0; hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE; hal::Vsync mLastHWCVsyncState = hal::Vsync::DISABLE; @@ -1384,7 +1345,7 @@ private: std::unique_ptr<Hwc2::PowerAdvisor> mPowerAdvisor; - void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock); + void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock, kMainThreadContext); // Flag used to set override desired display mode from backdoor bool mDebugDisplayModeSetByBackdoor = false; @@ -1416,8 +1377,21 @@ private: // A temporay pool that store the created layers and will be added to current state in main // thread. std::vector<LayerCreatedState> mCreatedLayers GUARDED_BY(mCreatedLayersLock); - bool commitCreatedLayers(); - void handleLayerCreatedLocked(const LayerCreatedState& state) REQUIRES(mStateLock); + bool commitCreatedLayers(VsyncId); + void handleLayerCreatedLocked(const LayerCreatedState&, VsyncId) REQUIRES(mStateLock); + + mutable std::mutex mMirrorDisplayLock; + struct MirrorDisplayState { + MirrorDisplayState(ui::LayerStack layerStack, sp<IBinder>& rootHandle, + const sp<Client>& client) + : layerStack(layerStack), rootHandle(rootHandle), client(client) {} + + ui::LayerStack layerStack; + sp<IBinder> rootHandle; + const sp<Client> client; + }; + std::vector<MirrorDisplayState> mMirrorDisplays GUARDED_BY(mMirrorDisplayLock); + bool commitMirrorDisplays(VsyncId); std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint; @@ -1451,19 +1425,32 @@ private: class SurfaceComposerAIDL : public gui::BnSurfaceComposer { public: - SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; } + SurfaceComposerAIDL(sp<SurfaceFlinger> sf) : mFlinger(std::move(sf)) {} + binder::Status bootFinished() override; + binder::Status createDisplayEventConnection( + VsyncSource vsyncSource, EventRegistration eventRegistration, + sp<gui::IDisplayEventConnection>* outConnection) override; + binder::Status createConnection(sp<gui::ISurfaceComposerClient>* outClient) override; binder::Status createDisplay(const std::string& displayName, bool secure, sp<IBinder>* outDisplay) override; binder::Status destroyDisplay(const sp<IBinder>& display) override; binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override; - binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override; binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override; binder::Status setPowerMode(const sp<IBinder>& display, int mode) override; + binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override; binder::Status getDisplayStats(const sp<IBinder>& display, gui::DisplayStatInfo* outStatInfo) override; binder::Status getDisplayState(const sp<IBinder>& display, gui::DisplayState* outState) override; + binder::Status getStaticDisplayInfo(const sp<IBinder>& display, + gui::StaticDisplayInfo* outInfo) override; + binder::Status getDynamicDisplayInfo(const sp<IBinder>& display, + gui::DynamicDisplayInfo* outInfo) override; + binder::Status getDisplayNativePrimaries(const sp<IBinder>& display, + gui::DisplayPrimaries* outPrimaries) override; + binder::Status setActiveColorMode(const sp<IBinder>& display, int colorMode) override; + binder::Status setBootDisplayMode(const sp<IBinder>& display, int displayModeId) override; binder::Status clearBootDisplayMode(const sp<IBinder>& display) override; binder::Status getBootDisplayModeSupport(bool* outMode) override; binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override; @@ -1473,8 +1460,52 @@ public: binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override; binder::Status captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override; + + // TODO(b/239076119): Remove deprecated AIDL. + [[deprecated]] binder::Status clearAnimationFrameStats() override { + return binder::Status::ok(); + } + [[deprecated]] binder::Status getAnimationFrameStats(gui::FrameStats*) override { + return binder::Status::ok(); + } + + binder::Status overrideHdrTypes(const sp<IBinder>& display, + const std::vector<int32_t>& hdrTypes) override; + binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override; + binder::Status enableVSyncInjections(bool enable) override; + binder::Status injectVSync(int64_t when) override; + binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) override; + binder::Status getColorManagement(bool* outGetColorManagement) override; + binder::Status getCompositionPreference(gui::CompositionPreference* outPref) override; + binder::Status getDisplayedContentSamplingAttributes( + const sp<IBinder>& display, gui::ContentSamplingAttributes* outAttrs) override; + binder::Status setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, + int8_t componentMask, + int64_t maxFrames) override; + binder::Status getDisplayedContentSample(const sp<IBinder>& display, int64_t maxFrames, + int64_t timestamp, + gui::DisplayedFrameStats* outStats) override; + binder::Status getProtectedContentSupport(bool* outSupporte) override; binder::Status isWideColorDisplay(const sp<IBinder>& token, bool* outIsWideColorDisplay) override; + binder::Status addRegionSamplingListener( + const gui::ARect& samplingArea, const sp<IBinder>& stopLayerHandle, + const sp<gui::IRegionSamplingListener>& listener) override; + binder::Status removeRegionSamplingListener( + const sp<gui::IRegionSamplingListener>& listener) override; + binder::Status addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) override; + binder::Status removeFpsListener(const sp<gui::IFpsListener>& listener) override; + binder::Status addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) override; + binder::Status removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) override; + binder::Status setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, int32_t defaultMode, + bool allowGroupSwitching, float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) override; + binder::Status getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, + gui::DisplayModeSpecs* outSpecs) override; binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) override; binder::Status setDisplayBrightness(const sp<IBinder>& displayToken, @@ -1485,11 +1516,27 @@ public: const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) override; binder::Status notifyPowerBoost(int boostId) override; + binder::Status setGlobalShadowSettings(const gui::Color& ambientColor, + const gui::Color& spotColor, float lightPosY, + float lightPosZ, float lightRadius) override; + binder::Status getDisplayDecorationSupport( + const sp<IBinder>& displayToken, + std::optional<gui::DisplayDecorationSupport>* outSupport) override; + binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override; + binder::Status addTransactionTraceListener( + const sp<gui::ITransactionTraceListener>& listener) override; + binder::Status getGpuContextPriority(int32_t* outPriority) override; + binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; + binder::Status addWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) override; + binder::Status removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) override; private: static const constexpr bool kUsePermissionCache = true; status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache); status_t checkControlDisplayBrightnessPermission(); + status_t checkReadFrameBufferPermission(); private: sp<SurfaceFlinger> mFlinger; diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index b81b445dad..3e30dcb817 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -22,15 +22,9 @@ #include <cutils/properties.h> #include <ui/GraphicBuffer.h> -#include "BufferLayerConsumer.h" -#include "BufferQueueLayer.h" -#include "BufferStateLayer.h" -#include "ContainerLayer.h" #include "DisplayDevice.h" -#include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "Layer.h" -#include "MonitoredProducer.h" #include "NativeWindowSurface.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerDefaultFactory.h" @@ -38,6 +32,7 @@ #include "SurfaceInterceptor.h" #include "DisplayHardware/ComposerHal.h" +#include "FrameTimeline/FrameTimeline.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" #include "Scheduler/VsyncController.h" @@ -60,22 +55,22 @@ std::unique_ptr<scheduler::VsyncConfiguration> DefaultFactory::createVsyncConfig } sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() { - return new android::impl::SurfaceInterceptor(); + return sp<android::impl::SurfaceInterceptor>::make(); } sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread( bool timestampPropertyValue) { - return new StartPropertySetThread(timestampPropertyValue); + return sp<StartPropertySetThread>::make(timestampPropertyValue); } sp<DisplayDevice> DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) { - return new DisplayDevice(creationArgs); + return sp<DisplayDevice>::make(creationArgs); } sp<GraphicBuffer> DefaultFactory::createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) { - return new GraphicBuffer(width, height, format, layerCount, usage, requestorName); + return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName); } void DefaultFactory::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, @@ -84,18 +79,6 @@ void DefaultFactory::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger); } -sp<IGraphicBufferProducer> DefaultFactory::createMonitoredProducer( - const sp<IGraphicBufferProducer>& producer, const sp<SurfaceFlinger>& flinger, - const wp<Layer>& layer) { - return new MonitoredProducer(producer, flinger, layer); -} - -sp<BufferLayerConsumer> DefaultFactory::createBufferLayerConsumer( - const sp<IGraphicBufferConsumer>& consumer, renderengine::RenderEngine& renderEngine, - uint32_t textureName, Layer* layer) { - return new BufferLayerConsumer(consumer, renderEngine, textureName, layer); -} - std::unique_ptr<surfaceflinger::NativeWindowSurface> DefaultFactory::createNativeWindowSurface( const sp<IGraphicBufferProducer>& producer) { return surfaceflinger::impl::createNativeWindowSurface(producer); @@ -105,20 +88,12 @@ std::unique_ptr<compositionengine::CompositionEngine> DefaultFactory::createComp return compositionengine::impl::createCompositionEngine(); } -sp<ContainerLayer> DefaultFactory::createContainerLayer(const LayerCreationArgs& args) { - return new ContainerLayer(args); -} - -sp<BufferQueueLayer> DefaultFactory::createBufferQueueLayer(const LayerCreationArgs& args) { - return new BufferQueueLayer(args); -} - -sp<BufferStateLayer> DefaultFactory::createBufferStateLayer(const LayerCreationArgs& args) { - return new BufferStateLayer(args); +sp<Layer> DefaultFactory::createBufferStateLayer(const LayerCreationArgs& args) { + return sp<Layer>::make(args); } -sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) { - return new EffectLayer(args); +sp<Layer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) { + return sp<Layer>::make(args); } std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() { diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 501629d4da..6fca402641 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -38,19 +38,11 @@ public: void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) override; - sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&, - const sp<SurfaceFlinger>&, - const wp<Layer>&) override; - sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&, - renderengine::RenderEngine&, uint32_t tex, - Layer*) override; std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer>&) override; std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override; - sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override; - sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override; - sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override; - sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override; + sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) override; + sp<Layer> createEffectLayer(const LayerCreationArgs& args) override; std::unique_ptr<FrameTracer> createFrameTracer() override; std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline( std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) override; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp index 3997b04f5f..7bd6cf69f3 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp @@ -26,7 +26,7 @@ namespace android::surfaceflinger { sp<SurfaceFlinger> createSurfaceFlinger() { static DefaultFactory factory; - return new SurfaceFlinger(factory); + return sp<SurfaceFlinger>::make(factory); } } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 6153e8e354..6d18adea39 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -30,12 +30,8 @@ namespace android { typedef int32_t PixelFormat; -class BufferQueueLayer; class BufferLayerConsumer; -class BufferStateLayer; -class ContainerLayer; class DisplayDevice; -class EffectLayer; class FrameTracer; class GraphicBuffer; class HWComposer; @@ -86,22 +82,14 @@ public: virtual void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) = 0; - virtual sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&, - const sp<SurfaceFlinger>&, - const wp<Layer>&) = 0; - virtual sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&, - renderengine::RenderEngine&, - uint32_t tex, Layer*) = 0; virtual std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer>&) = 0; virtual std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() = 0; - virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0; - virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0; - virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0; - virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0; + virtual sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) = 0; + virtual sp<Layer> createEffectLayer(const LayerCreationArgs& args) = 0; virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0; virtual std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline( std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) = 0; diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 0782fef8ea..6797aa697b 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -46,7 +46,7 @@ void SurfaceInterceptor::addTransactionTraceListener( std::scoped_lock lock(mListenersMutex); - asBinder->linkToDeath(this); + asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); listener->onToggled(mEnabled); // notifies of current state @@ -115,8 +115,9 @@ void SurfaceInterceptor::saveExistingSurfacesLocked(const SortedVector<sp<Layer> ATRACE_CALL(); for (const auto& l : layers) { l->traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* layer) { - addSurfaceCreationLocked(createTraceIncrementLocked(), layer); - addInitialSurfaceStateLocked(createTraceIncrementLocked(), layer); + addSurfaceCreationLocked(createTraceIncrementLocked(), sp<Layer>::fromExisting(layer)); + addInitialSurfaceStateLocked(createTraceIncrementLocked(), + sp<Layer>::fromExisting(layer)); }); } } @@ -134,8 +135,6 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, layer->mDrawingState.transform.ty()); addDepthLocked(transaction, layerId, layer->mDrawingState.z); addAlphaLocked(transaction, layerId, layer->mDrawingState.color.a); - addTransparentRegionLocked(transaction, layerId, - layer->mDrawingState.activeTransparentRegion_legacy); addLayerStackLocked(transaction, layerId, layer->mDrawingState.layerStack); addCropLocked(transaction, layerId, layer->mDrawingState.crop); addCornerRadiusLocked(transaction, layerId, layer->mDrawingState.cornerRadius); @@ -419,9 +418,6 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, if (state.what & layer_state_t::eLayerChanged) { addDepthLocked(transaction, layerId, state.z); } - if (state.what & layer_state_t::eSizeChanged) { - addSizeLocked(transaction, layerId, state.w, state.h); - } if (state.what & layer_state_t::eAlphaChanged) { addAlphaLocked(transaction, layerId, state.alpha); } @@ -521,8 +517,6 @@ void SurfaceInterceptor::addSurfaceCreationLocked(Increment* increment, SurfaceCreation* creation(increment->mutable_surface_creation()); creation->set_id(getLayerId(layer)); creation->set_name(layer->getName()); - creation->set_w(layer->mDrawingState.active_legacy.w); - creation->set_h(layer->mDrawingState.active_legacy.h); } void SurfaceInterceptor::addSurfaceDeletionLocked(Increment* increment, diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 7a159b8eb7..61d7c22a2a 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -34,6 +34,8 @@ #include <scheduler/Fps.h> +using android::gui::GameMode; +using android::gui::LayerMetadata; using namespace android::surfaceflinger; namespace android { diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 237ae8d761..60aa810e8b 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -24,6 +24,9 @@ #include <unordered_map> #include <vector> +using android::gui::GameMode; +using android::gui::LayerMetadata; + namespace android { namespace surfaceflinger { diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index 49554c7dd8..566d55353f 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -89,6 +89,9 @@ LayersTraceFileProto LayerTracing::createTraceFileProto() const { LayersTraceFileProto fileProto; fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); + auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) - + systemTime(SYSTEM_TIME_MONOTONIC)); + fileProto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs); return fileProto; } @@ -98,7 +101,7 @@ void LayerTracing::dump(std::string& result) const { mBuffer->dump(result); } -void LayerTracing::notify(bool visibleRegionDirty, int64_t time) { +void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId) { std::scoped_lock lock(mTraceLock); if (!mEnabled) { return; @@ -129,6 +132,7 @@ void LayerTracing::notify(bool visibleRegionDirty, int64_t time) { entry.set_excludes_composition_state(true); } mFlinger.dumpDisplayProto(entry); + entry.set_vsync_id(vsyncId); mBuffer->emplace(std::move(entry)); } diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h index 88a19ecdf1..e73dac62e4 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.h +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -47,7 +47,7 @@ public: bool isEnabled() const; status_t writeToFile(); LayersTraceFileProto createTraceFileProto() const; - void notify(bool visibleRegionDirty, int64_t time); + void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId); enum : uint32_t { TRACE_INPUT = 1 << 1, diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index a73eccf0e5..dcc529ecc5 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -15,6 +15,7 @@ */ #include <gui/SurfaceComposerClient.h> +#include <ui/Fence.h> #include <ui/Rect.h> #include "LayerProtoHelper.h" @@ -87,10 +88,7 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { if (layer.what & layer_state_t::eLayerChanged) { proto.set_z(layer.z); } - if (layer.what & layer_state_t::eSizeChanged) { - proto.set_w(layer.w); - proto.set_h(layer.h); - } + if (layer.what & layer_state_t::eLayerStackChanged) { proto.set_layer_stack(layer.layerStack.id); } @@ -375,10 +373,6 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta if (proto.what() & layer_state_t::eLayerChanged) { layer.z = proto.z(); } - if (proto.what() & layer_state_t::eSizeChanged) { - layer.w = proto.w(); - layer.h = proto.h(); - } if (proto.what() & layer_state_t::eLayerStackChanged) { layer.layerStack.id = proto.layer_stack(); } @@ -456,9 +450,9 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta layer.parentSurfaceControlForChild = nullptr; } else { layer.parentSurfaceControlForChild = - new SurfaceControl(SurfaceComposerClient::getDefault(), - mMapper->getLayerHandle(static_cast<int32_t>(layerId)), - nullptr, static_cast<int32_t>(layerId)); + sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), + mMapper->getLayerHandle(static_cast<int32_t>(layerId)), + static_cast<int32_t>(layerId)); } } if (proto.what() & layer_state_t::eRelativeLayerChanged) { @@ -467,9 +461,9 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta layer.relativeLayerSurfaceControl = nullptr; } else { layer.relativeLayerSurfaceControl = - new SurfaceControl(SurfaceComposerClient::getDefault(), - mMapper->getLayerHandle(static_cast<int32_t>(layerId)), - nullptr, static_cast<int32_t>(layerId)); + sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), + mMapper->getLayerHandle(static_cast<int32_t>(layerId)), + static_cast<int32_t>(layerId)); } layer.z = proto.z(); } @@ -497,8 +491,13 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta inputInfo.replaceTouchableRegionWithCrop = windowInfoProto.replace_touchable_region_with_crop(); int64_t layerId = windowInfoProto.crop_layer_id(); - inputInfo.touchableRegionCropHandle = - mMapper->getLayerHandle(static_cast<int32_t>(layerId)); + if (layerId != -1) { + inputInfo.touchableRegionCropHandle = + mMapper->getLayerHandle(static_cast<int32_t>(layerId)); + } else { + inputInfo.touchableRegionCropHandle = wp<IBinder>(); + } + layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo); } if (proto.what() & layer_state_t::eBackgroundColorChanged) { diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index 6381758c7b..cb5320b88c 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -134,6 +134,9 @@ proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const { proto::TransactionTraceFile proto; proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 | proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L); + auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) - + systemTime(SYSTEM_TIME_MONOTONIC)); + proto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs); return proto; } @@ -152,17 +155,33 @@ void TransactionTracing::addQueuedTransaction(const TransactionState& transactio mTransactionQueue.push(state); } -void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions, - int64_t vsyncId) { +TransactionTracing::CommittedTransactions& +TransactionTracing::findOrCreateCommittedTransactionRecord(int64_t vsyncId) { + for (auto& pendingTransaction : mPendingTransactions) { + if (pendingTransaction.vsyncId == vsyncId) { + return pendingTransaction; + } + } + CommittedTransactions committedTransactions; committedTransactions.vsyncId = vsyncId; committedTransactions.timestamp = systemTime(); + mPendingTransactions.emplace_back(committedTransactions); + return mPendingTransactions.back(); +} + +void TransactionTracing::onLayerAddedToDrawingState(int layerId, int64_t vsyncId) { + CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId); + committedTransactions.createdLayerIds.emplace_back(layerId); +} + +void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions, + int64_t vsyncId) { + CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId); committedTransactions.transactionIds.reserve(transactions.size()); for (const auto& transaction : transactions) { committedTransactions.transactionIds.emplace_back(transaction.id); } - - mPendingTransactions.emplace_back(committedTransactions); tryPushToTracingThread(); } @@ -235,15 +254,24 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm for (const CommittedTransactions& entry : committedTransactions) { entryProto.set_elapsed_realtime_nanos(entry.timestamp); entryProto.set_vsync_id(entry.vsyncId); - entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size())); - for (auto& newLayer : mCreatedLayers) { - entryProto.mutable_added_layers()->Add(std::move(newLayer)); + entryProto.mutable_added_layers()->Reserve( + static_cast<int32_t>(entry.createdLayerIds.size())); + + for (const int32_t& id : entry.createdLayerIds) { + auto it = mCreatedLayers.find(id); + if (it != mCreatedLayers.end()) { + entryProto.mutable_added_layers()->Add(std::move(it->second)); + mCreatedLayers.erase(it); + } else { + ALOGW("Could not created layer with id %d", id); + } } + entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size())); for (auto& removedLayer : removedLayers) { entryProto.mutable_removed_layers()->Add(removedLayer); + mCreatedLayers.erase(removedLayer); } - mCreatedLayers.clear(); entryProto.mutable_transactions()->Reserve( static_cast<int32_t>(entry.transactionIds.size())); for (const uint64_t& id : entry.transactionIds) { @@ -256,6 +284,14 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm } } + entryProto.mutable_removed_layer_handles()->Reserve( + static_cast<int32_t>(mRemovedLayerHandles.size())); + for (auto& [handle, layerId] : mRemovedLayerHandles) { + entryProto.mutable_removed_layer_handles()->Add(layerId); + mLayerHandles.erase(handle); + } + mRemovedLayerHandles.clear(); + std::string serializedProto; entryProto.SerializeToString(&serializedProto); entryProto.Clear(); @@ -263,13 +299,6 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm removedEntries.reserve(removedEntries.size() + entries.size()); removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()), std::make_move_iterator(entries.end())); - - entryProto.mutable_removed_layer_handles()->Reserve( - static_cast<int32_t>(mRemovedLayerHandles.size())); - for (auto& handle : mRemovedLayerHandles) { - entryProto.mutable_removed_layer_handles()->Add(handle); - } - mRemovedLayerHandles.clear(); } proto::TransactionTraceEntry removedEntryProto; @@ -304,7 +333,7 @@ void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const s ALOGW("Duplicate handles found. %p", layerHandle); } mLayerHandles[layerHandle] = layerId; - mCreatedLayers.push_back(mProtoParser.toProto(args)); + mCreatedLayers[layerId] = mProtoParser.toProto(args); } void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId, @@ -315,7 +344,7 @@ void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId, ALOGW("Duplicate handles found. %p", layerHandle); } mLayerHandles[layerHandle] = layerId; - mCreatedLayers.emplace_back(mProtoParser.toProto(args)); + mCreatedLayers[layerId] = mProtoParser.toProto(args); } void TransactionTracing::onLayerRemoved(int32_t layerId) { @@ -330,9 +359,7 @@ void TransactionTracing::onHandleRemoved(BBinder* layerHandle) { ALOGW("handle not found. %p", layerHandle); return; } - - mRemovedLayerHandles.push_back(it->second); - mLayerHandles.erase(it); + mRemovedLayerHandles.emplace_back(layerHandle, it->second); } void TransactionTracing::tryPushToTracingThread() { @@ -376,10 +403,15 @@ void TransactionTracing::updateStartingStateLocked( } } + for (const int32_t removedLayerHandleId : removedEntry.removed_layer_handles()) { + mRemovedLayerHandlesAtStart.insert(removedLayerHandleId); + } + // Clean up stale starting states since the layer has been removed and the buffer does not // contain any references to the layer. for (const int32_t removedLayerId : removedEntry.removed_layers()) { mStartingStates.erase(removedLayerId); + mRemovedLayerHandlesAtStart.erase(removedLayerId); } } @@ -401,6 +433,12 @@ void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFi transactionProto.set_vsync_id(0); transactionProto.set_post_time(mStartingTimestamp); entryProto->mutable_transactions()->Add(std::move(transactionProto)); + + entryProto->mutable_removed_layer_handles()->Reserve( + static_cast<int32_t>(mRemovedLayerHandlesAtStart.size())); + for (const int32_t removedLayerHandleId : mRemovedLayerHandlesAtStart) { + entryProto->mutable_removed_layer_handles()->Add(removedLayerHandleId); + } } proto::TransactionTraceFile TransactionTracing::writeToProto() { diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index 4c291f960f..ae01d3c0cc 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -64,6 +64,7 @@ public: int mirrorFromId); void onLayerRemoved(int layerId); void onHandleRemoved(BBinder* layerHandle); + void onLayerAddedToDrawingState(int layerId, int64_t vsyncId); void dump(std::string&) const; static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024; static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024; @@ -81,11 +82,13 @@ private: GUARDED_BY(mTraceLock); LocklessStack<proto::TransactionState> mTransactionQueue; nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock); - std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock); + std::unordered_map<int, proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock); std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles GUARDED_BY(mTraceLock); - std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock); + std::vector<std::pair<BBinder* /* layerHandle */, int32_t /* layerId */>> mRemovedLayerHandles + GUARDED_BY(mTraceLock); std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock); + std::set<int32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock); TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock); // Parses the transaction to proto without holding any tracing locks so we can generate proto // in the binder thread without any contention. @@ -100,6 +103,7 @@ private: std::condition_variable mTransactionsAddedToBufferCv; struct CommittedTransactions { std::vector<uint64_t> transactionIds; + std::vector<int32_t> createdLayerIds; int64_t vsyncId; int64_t timestamp; }; @@ -117,7 +121,7 @@ private: void tryPushToTracingThread() EXCLUDES(mMainThreadLock); void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock); void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock); - + CommittedTransactions& findOrCreateCommittedTransactionRecord(int64_t vsyncId); // TEST // Wait until all the committed transactions for the specified vsync id are added to the buffer. void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock); diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp index cf44effe50..88171785c7 100644 --- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp @@ -16,6 +16,7 @@ #undef LOG_TAG #define LOG_TAG "LayerTraceGenerator" +//#define LOG_NDEBUG 0 #include <TestableSurfaceFlinger.h> #include <Tracing/TransactionProtoParser.h> @@ -47,42 +48,29 @@ public: } sp<SurfaceInterceptor> createSurfaceInterceptor() override { - return new android::impl::SurfaceInterceptor(); + return sp<android::impl::SurfaceInterceptor>::make(); } sp<StartPropertySetThread> createStartPropertySetThread( bool /* timestampPropertyValue */) override { - return nullptr; + return sp<StartPropertySetThread>(); } sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override { - return nullptr; + return sp<DisplayDevice>(); } sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */, PixelFormat /* format */, uint32_t /* layerCount */, uint64_t /* usage */, std::string /* requestorName */) override { - return nullptr; + return sp<GraphicBuffer>(); } void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */, sp<IGraphicBufferConsumer>* /* outConsumer */, bool /* consumerIsSurfaceFlinger */) override {} - sp<IGraphicBufferProducer> createMonitoredProducer( - const sp<IGraphicBufferProducer>& /* producer */, - const sp<SurfaceFlinger>& /* flinger */, const wp<Layer>& /* layer */) override { - return nullptr; - } - - sp<BufferLayerConsumer> createBufferLayerConsumer( - const sp<IGraphicBufferConsumer>& /* consumer */, - renderengine::RenderEngine& /* renderEngine */, uint32_t /* textureName */, - Layer* /* layer */) override { - return nullptr; - } - std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer>& /* producer */) override { return nullptr; @@ -92,21 +80,11 @@ public: return compositionengine::impl::createCompositionEngine(); } - sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) { - return sp<ContainerLayer>::make(args); - } - - sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) { - return new BufferStateLayer(args); - } - - sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) { - return new EffectLayer(args); + sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) { + return sp<Layer>::make(args); } - sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override { - return nullptr; - } + sp<Layer> createEffectLayer(const LayerCreationArgs& args) { return sp<Layer>::make(args); } std::unique_ptr<FrameTracer> createFrameTracer() override { return std::make_unique<testing::NiceMock<mock::FrameTracer>>(); @@ -142,6 +120,14 @@ public: transact(1033, data, &reply, 0 /* flags */); } + void setLayerTraceSize(int32_t sizeInKb) { + Parcel data; + Parcel reply; + data.writeInterfaceToken(String16("android.ui.ISurfaceComposer")); + data.writeInt32(sizeInKb); + transact(1029, data, &reply, 0 /* flags */); + } + void startLayerTracing(int64_t traceStartTime) { Parcel data; Parcel reply; @@ -181,11 +167,12 @@ public: bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, const char* outputLayersTracePath) { if (traceFile.entry_size() == 0) { + ALOGD("Trace file is empty"); return false; } Factory mFactory; - sp<MockSurfaceFlinger> flinger = new MockSurfaceFlinger(mFactory); + sp<MockSurfaceFlinger> flinger = sp<MockSurfaceFlinger>::make(mFactory); TestableSurfaceFlinger mFlinger(flinger); mFlinger.setupRenderEngine( std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>()); @@ -205,21 +192,21 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, mFlinger.mutableMaxRenderTargetSize() = 16384; flinger->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS); + flinger->setLayerTraceSize(512 * 1024); // 512MB buffer size flinger->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos()); std::unique_ptr<TraceGenFlingerDataMapper> mapper = std::make_unique<TraceGenFlingerDataMapper>(); TraceGenFlingerDataMapper* dataMapper = mapper.get(); TransactionProtoParser parser(std::move(mapper)); - nsecs_t frameTime; - int64_t vsyncId; ALOGD("Generating %d transactions...", traceFile.entry_size()); for (int i = 0; i < traceFile.entry_size(); i++) { proto::TransactionTraceEntry entry = traceFile.entry(i); ALOGV(" Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64 - " layers +%d -%d transactions=%d", + " layers +%d -%d handles -%d transactions=%d", i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(), - entry.added_layers_size(), entry.removed_layers_size(), entry.transactions_size()); + entry.added_layers_size(), entry.removed_layers_size(), + entry.removed_layer_handles_size(), entry.transactions_size()); for (int j = 0; j < entry.added_layers_size(); j++) { // create layers @@ -238,7 +225,7 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, (dataMapper->mLayerHandles.find(tracingArgs.parentId) == dataMapper->mLayerHandles.end())) { args.addToRoot = false; - } else { + } else if (tracingArgs.parentId != -1) { parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId); } mFlinger.createLayer(args, &outHandle, parentHandle, &outLayerId, @@ -265,13 +252,13 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, transaction.listenerCallbacks, transaction.id); } + const auto frameTime = TimePoint::fromNs(entry.elapsed_realtime_nanos()); + const auto vsyncId = VsyncId{entry.vsync_id()}; + mFlinger.commit(frameTime, vsyncId); + for (int j = 0; j < entry.removed_layer_handles_size(); j++) { dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j)); } - - frameTime = entry.elapsed_realtime_nanos(); - vsyncId = entry.vsync_id(); - mFlinger.commit(frameTime, vsyncId); } flinger->stopLayerTracing(outputLayersTracePath); @@ -280,4 +267,4 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, return true; } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index d2c2e29a2f..e5de7591ef 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -178,8 +178,8 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& return NO_ERROR; } -void TransactionCallbackInvoker::addPresentFence(const sp<Fence>& presentFence) { - mPresentFence = presentFence; +void TransactionCallbackInvoker::addPresentFence(sp<Fence> presentFence) { + mPresentFence = std::move(presentFence); } void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) { diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 81d79f0777..23ea7a551a 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -26,10 +26,10 @@ #include <android-base/thread_annotations.h> #include <binder/IBinder.h> -#include <compositionengine/FenceResult.h> #include <ftl/future.h> #include <gui/ITransactionCompletedListener.h> #include <ui/Fence.h> +#include <ui/FenceResult.h> namespace android { @@ -70,7 +70,7 @@ public: status_t registerUnpresentedCallbackHandle(const sp<CallbackHandle>& handle); void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks); - void addPresentFence(const sp<Fence>& presentFence); + void addPresentFence(sp<Fence>); void sendCallbacks(bool onCommitOnly); void clearCompletedTransactions() { diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h index 900d566942..61f0fa6b64 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -98,7 +98,6 @@ struct TransactionState { int originUid; uint64_t id; std::shared_ptr<CountDownLatch> transactionCommittedSignal; - int64_t queueTime = 0; bool sentFenceTimeoutWarning = false; }; @@ -106,7 +105,6 @@ class CountDownLatch { public: enum { eSyncTransaction = 1 << 0, - eSyncInputWindows = 1 << 1, }; explicit CountDownLatch(uint32_t flags) : mFlags(flags) {} diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.cpp b/services/surfaceflinger/TunnelModeEnabledReporter.cpp index 4497cafa58..bc9b870075 100644 --- a/services/surfaceflinger/TunnelModeEnabledReporter.cpp +++ b/services/surfaceflinger/TunnelModeEnabledReporter.cpp @@ -59,7 +59,7 @@ void TunnelModeEnabledReporter::binderDied(const wp<IBinder>& who) { void TunnelModeEnabledReporter::addListener(const sp<gui::ITunnelModeEnabledListener>& listener) { sp<IBinder> asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(this); + asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); bool tunnelModeEnabled = false; { std::scoped_lock lock(mMutex); diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 30b9d8f1cb..a1313e3a03 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -26,25 +26,43 @@ using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -struct WindowInfosListenerInvoker::WindowInfosReportedListener - : gui::BnWindowInfosReportedListener { - explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker) : mInvoker(invoker) {} +struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowInfosReportedListener, + DeathRecipient { + explicit WindowInfosReportedListener( + size_t callbackCount, + const std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>>& + windowInfosReportedListeners) + : mCallbacksPending(callbackCount), + mWindowInfosReportedListeners(windowInfosReportedListeners) {} binder::Status onWindowInfosReported() override { - mInvoker.windowInfosReported(); + // TODO(b/222421815) There could potentially be callbacks that we don't need to wait for + // before calling the WindowInfosReportedListeners coming from InputWindowCommands. Filter + // the list of callbacks down to those from system server. + if (--mCallbacksPending == 0) { + for (const auto& listener : mWindowInfosReportedListeners) { + sp<IBinder> asBinder = IInterface::asBinder(listener); + if (asBinder->isBinderAlive()) { + listener->onWindowInfosReported(); + } + } + } return binder::Status::ok(); } - WindowInfosListenerInvoker& mInvoker; -}; + void binderDied(const wp<IBinder>&) { onWindowInfosReported(); } -WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger) - : mFlinger(flinger), - mWindowInfosReportedListener(sp<WindowInfosReportedListener>::make(*this)) {} +private: + std::atomic<size_t> mCallbacksPending; + std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>> + mWindowInfosReportedListeners; +}; void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) { sp<IBinder> asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(this); + asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); std::scoped_lock lock(mListenersMutex); mWindowInfosListeners.try_emplace(asBinder, std::move(listener)); @@ -55,7 +73,7 @@ void WindowInfosListenerInvoker::removeWindowInfosListener( sp<IBinder> asBinder = IInterface::asBinder(listener); std::scoped_lock lock(mListenersMutex); - asBinder->unlinkToDeath(this); + asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this)); mWindowInfosListeners.erase(asBinder); } @@ -64,9 +82,11 @@ void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) { mWindowInfosListeners.erase(who); } -void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos, - const std::vector<DisplayInfo>& displayInfos, - bool shouldSync) { +void WindowInfosListenerInvoker::windowInfosChanged( + const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos, + const std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>>& + windowInfosReportedListeners) { ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners; { std::scoped_lock lock(mListenersMutex); @@ -75,18 +95,25 @@ void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo } } - mCallbacksPending = windowInfosListeners.size(); - + auto windowInfosReportedListener = windowInfosReportedListeners.empty() + ? nullptr + : sp<WindowInfosReportedListener>::make(windowInfosListeners.size(), + windowInfosReportedListeners); for (const auto& listener : windowInfosListeners) { - listener->onWindowInfosChanged(windowInfos, displayInfos, - shouldSync ? mWindowInfosReportedListener : nullptr); - } -} + sp<IBinder> asBinder = IInterface::asBinder(listener); + + // linkToDeath is used here to ensure that the windowInfosReportedListeners + // are called even if one of the windowInfosListeners dies before + // calling onWindowInfosReported. + if (windowInfosReportedListener) { + asBinder->linkToDeath(windowInfosReportedListener); + } -void WindowInfosListenerInvoker::windowInfosReported() { - mCallbacksPending--; - if (mCallbacksPending == 0) { - mFlinger.windowInfosReported(); + auto status = listener->onWindowInfosChanged(windowInfos, displayInfos, + windowInfosReportedListener); + if (windowInfosReportedListener && !status.isOk()) { + windowInfosReportedListener->onWindowInfosReported(); + } } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index d8d8d0f570..a1d66a186e 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -29,22 +29,21 @@ class SurfaceFlinger; class WindowInfosListenerInvoker : public IBinder::DeathRecipient { public: - explicit WindowInfosListenerInvoker(SurfaceFlinger&); - void addWindowInfosListener(sp<gui::IWindowInfosListener>); void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener); void windowInfosChanged(const std::vector<gui::WindowInfo>&, - const std::vector<gui::DisplayInfo>&, bool shouldSync); + const std::vector<gui::DisplayInfo>&, + const std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>>& + windowInfosReportedListeners); protected: void binderDied(const wp<IBinder>& who) override; private: struct WindowInfosReportedListener; - void windowInfosReported(); - SurfaceFlinger& mFlinger; std::mutex mListenersMutex; static constexpr size_t kStaticCapacity = 3; @@ -52,7 +51,6 @@ private: mWindowInfosListeners GUARDED_BY(mListenersMutex); sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener; - std::atomic<size_t> mCallbacksPending{0}; }; } // namespace android diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp index b0b6bf14ab..7350e09cb5 100644 --- a/services/surfaceflinger/fuzzer/Android.bp +++ b/services/surfaceflinger/fuzzer/Android.bp @@ -127,3 +127,13 @@ cc_fuzz { "surfaceflinger_layer_fuzzer.cpp", ], } + +cc_fuzz { + name: "surfaceflinger_frametracer_fuzzer", + defaults: [ + "surfaceflinger_fuzz_defaults", + ], + srcs: [ + "surfaceflinger_frametracer_fuzzer.cpp", + ], +} diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md index 78a7596ef3..a06c41b139 100644 --- a/services/surfaceflinger/fuzzer/README.md +++ b/services/surfaceflinger/fuzzer/README.md @@ -4,6 +4,7 @@ + [DisplayHardware](#DisplayHardware) + [Scheduler](#Scheduler) + [Layer](#Layer) ++ [FrameTracer](#FrameTracer) # <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger @@ -77,9 +78,8 @@ You can find the possible values in the fuzzer's source code. Layer supports the following parameters: 1. Display Connection Types (parameter name: `fakeDisplay`) 2. State Sets (parameter name: `traverseInZOrder`) -3. State Subsets (parameter name: `prepareCompositionState`) -4. Disconnect modes (parameter name: `disconnect`) -5. Data Spaces (parameter name: `setDataspace`) +3. Disconnect modes (parameter name: `disconnect`) +4. Data Spaces (parameter name: `setDataspace`) You can find the possible values in the fuzzer's source code. @@ -93,3 +93,16 @@ You can find the possible values in the fuzzer's source code. $ adb sync data $ adb shell /data/fuzz/arm64/surfaceflinger_layer_fuzzer/surfaceflinger_layer_fuzzer ``` + +# <a name="FrameTracer"></a> Fuzzer for FrameTracer + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) surfaceflinger_frametracer_fuzzer +``` +2. To run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/surfaceflinger_frametracer_fuzzer/surfaceflinger_frametracer_fuzzer +``` diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp index a605a2fd9b..fae916542a 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp @@ -116,7 +116,8 @@ static constexpr hal::HWConfigId kActiveConfig = 0; class DisplayHardwareFuzzer { public: DisplayHardwareFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) { - mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value(); + mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value_or( + PhysicalDisplayId::fromPort(mFdp.ConsumeIntegral<uint8_t>())); }; void process(); @@ -480,8 +481,8 @@ void DisplayHardwareFuzzer::invokeFrameBufferSurface() { BufferQueue::createBufferQueue(&bqProducer, &bqConsumer); sp<FramebufferSurface> surface = - new FramebufferSurface(mHwc, mPhysicalDisplayId, bqConsumer, getFuzzedSize() /*size*/, - getFuzzedSize() /*maxSize*/); + sp<FramebufferSurface>::make(mHwc, mPhysicalDisplayId, bqConsumer, + getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/); surface->beginFrame(mFdp.ConsumeBool()); surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes)); @@ -497,15 +498,15 @@ void DisplayHardwareFuzzer::invokeVirtualDisplaySurface() { DisplayIdGenerator<HalVirtualDisplayId> mGenerator; VirtualDisplayId VirtualDisplayId = mGenerator.generateId().value(); - sp<SurfaceComposerClient> mClient = new SurfaceComposerClient(); + sp<SurfaceComposerClient> mClient = sp<SurfaceComposerClient>::make(); sp<SurfaceControl> mSurfaceControl = mClient->createSurface(String8("TestSurface"), 100, 100, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ nullptr); - sp<BLASTBufferQueue> mBlastBufferQueueAdapter = - new BLASTBufferQueue("TestBLASTBufferQueue", mSurfaceControl, 100, 100, - PIXEL_FORMAT_RGBA_8888); + auto mBlastBufferQueueAdapter = + sp<BLASTBufferQueue>::make("TestBLASTBufferQueue", mSurfaceControl, 100, 100, + PIXEL_FORMAT_RGBA_8888); sp<IGraphicBufferProducer> sink = mBlastBufferQueueAdapter->getIGraphicBufferProducer(); sp<IGraphicBufferProducer> bqProducer = mBlastBufferQueueAdapter->getIGraphicBufferProducer(); @@ -513,9 +514,9 @@ void DisplayHardwareFuzzer::invokeVirtualDisplaySurface() { BufferQueue::createBufferQueue(&bqProducer, &bqConsumer); BufferQueue::createBufferQueue(&sink, &bqConsumer); - sp<VirtualDisplaySurface> surface = - new VirtualDisplaySurface(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer, - mFdp.ConsumeRandomLengthString().c_str() /*name*/); + auto surface = + sp<VirtualDisplaySurface>::make(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer, + mFdp.ConsumeRandomLengthString().c_str() /*name*/); surface->beginFrame(mFdp.ConsumeBool()); surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes)); @@ -565,7 +566,7 @@ void DisplayHardwareFuzzer::invokeComposer() { mHwc.getLayerReleaseFence(halDisplayID, layer); - mHwc.setOutputBuffer(halVirtualDisplayId, sp<Fence>::make().get(), sp<GraphicBuffer>::make()); + mHwc.setOutputBuffer(halVirtualDisplayId, sp<Fence>::make(), sp<GraphicBuffer>::make()); mHwc.clearReleaseFences(halDisplayID); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp new file mode 100644 index 0000000000..a22a778989 --- /dev/null +++ b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp @@ -0,0 +1,132 @@ +/* + * Copyright 2021 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 <FrameTracer/FrameTracer.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <perfetto/trace/trace.pb.h> + +namespace android::fuzz { + +using namespace google::protobuf; + +constexpr size_t kMaxStringSize = 100; +constexpr size_t kMinLayerIds = 1; +constexpr size_t kMaxLayerIds = 10; +constexpr int32_t kConfigDuration = 500; +constexpr int32_t kBufferSize = 1024; +constexpr int32_t kTimeOffset = 100000; + +class FrameTracerFuzzer { +public: + FrameTracerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) { + // Fuzzer is single-threaded, so no need to be thread-safe. + static bool wasInitialized = false; + if (!wasInitialized) { + perfetto::TracingInitArgs args; + args.backends = perfetto::kInProcessBackend; + perfetto::Tracing::Initialize(args); + wasInitialized = true; + } + mFrameTracer = std::make_unique<android::FrameTracer>(); + } + ~FrameTracerFuzzer() { mFrameTracer.reset(); } + void process(); + +private: + std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest(); + void traceTimestamp(); + std::vector<int32_t> generateLayerIds(size_t numLayerIds); + void traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds); + void traceFence(std::vector<int32_t> layerIds, size_t numLayerIds); + std::unique_ptr<android::FrameTracer> mFrameTracer = nullptr; + FuzzedDataProvider mFdp; + android::FenceToFenceTimeMap mFenceFactory; +}; + +std::unique_ptr<perfetto::TracingSession> FrameTracerFuzzer::getTracingSessionForTest() { + perfetto::TraceConfig cfg; + cfg.set_duration_ms(kConfigDuration); + cfg.add_buffers()->set_size_kb(kBufferSize); + auto* dsCfg = cfg.add_data_sources()->mutable_config(); + dsCfg->set_name(android::FrameTracer::kFrameTracerDataSource); + + auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); + tracingSession->Setup(cfg); + return tracingSession; +} + +std::vector<int32_t> FrameTracerFuzzer::generateLayerIds(size_t numLayerIds) { + std::vector<int32_t> layerIds; + for (size_t i = 0; i < numLayerIds; ++i) { + layerIds.push_back(mFdp.ConsumeIntegral<int32_t>()); + } + return layerIds; +} + +void FrameTracerFuzzer::traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds) { + int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1)); + mFrameTracer->traceTimestamp(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/, + mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, + mFdp.ConsumeIntegral<nsecs_t>() /*timestamp*/, + android::FrameTracer::FrameEvent::UNSPECIFIED, + mFdp.ConsumeIntegral<nsecs_t>() /*duration*/); +} + +void FrameTracerFuzzer::traceFence(std::vector<int32_t> layerIds, size_t numLayerIds) { + const nsecs_t signalTime = systemTime(); + const nsecs_t startTime = signalTime + kTimeOffset; + auto fence = mFenceFactory.createFenceTimeForTest(android::Fence::NO_FENCE); + mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, signalTime); + int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1)); + mFrameTracer->traceFence(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/, + mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, fence, + android::FrameTracer::FrameEvent::ACQUIRE_FENCE, startTime); +} + +void FrameTracerFuzzer::process() { + mFrameTracer->registerDataSource(); + + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + + size_t numLayerIds = mFdp.ConsumeIntegralInRange<size_t>(kMinLayerIds, kMaxLayerIds); + std::vector<int32_t> layerIds = generateLayerIds(numLayerIds); + + for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { + mFrameTracer->traceNewLayer(*it /*layerId*/, + mFdp.ConsumeRandomLengthString(kMaxStringSize) /*layerName*/); + } + + traceTimestamp(layerIds, numLayerIds); + traceFence(layerIds, numLayerIds); + + mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, systemTime()); + + tracingSession->StopBlocking(); + + for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { + mFrameTracer->onDestroy(*it); + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FrameTracerFuzzer frameTracerFuzzer(data, size); + frameTracerFuzzer.process(); + return 0; +} + +} // namespace android::fuzz diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index f25043cd6d..79112bd998 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -103,7 +103,7 @@ static constexpr uint32_t kMaxCode = 1050; class SurfaceFlingerFuzzer { public: SurfaceFlingerFuzzer(const uint8_t *data, size_t size) : mFdp(data, size) { - mFlinger = mTestableFlinger.flinger(); + mFlinger = sp<SurfaceFlinger>::fromExisting(mTestableFlinger.flinger()); }; void process(const uint8_t *data, size_t size); @@ -151,7 +151,6 @@ void SurfaceFlingerFuzzer::invokeFlinger() { sp<IBinder> handle = defaultServiceManager()->checkService( String16(mFdp.ConsumeRandomLengthString().c_str())); mFlinger->fromHandle(handle); - mFlinger->windowInfosReported(); mFlinger->disableExpensiveRendering(); } @@ -238,14 +237,14 @@ void SurfaceFlingerFuzzer::process(const uint8_t *data, size_t size) { mTestableFlinger.enableHalVirtualDisplays(mFdp.ConsumeBool()); - mTestableFlinger.commitTransactionsLocked(mFdp.ConsumeIntegral<uint32_t>()); + FTL_FAKE_GUARD(kMainThreadContext, + mTestableFlinger.commitTransactionsLocked(mFdp.ConsumeIntegral<uint32_t>())); mTestableFlinger.notifyPowerBoost(mFdp.ConsumeIntegral<int32_t>()); setDisplayStateLocked(); setTransactionState(); - mTestableFlinger.flushTransactionQueues(); onTransact(data, size); } diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 867a1985bd..69dbfe0280 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -30,12 +30,8 @@ #include <ui/DisplayStatInfo.h> #include <ui/DynamicDisplayInfo.h> -#include "BufferQueueLayer.h" -#include "BufferStateLayer.h" -#include "ContainerLayer.h" #include "DisplayDevice.h" #include "DisplayHardware/ComposerHal.h" -#include "EffectLayer.h" #include "FrameTimeline/FrameTimeline.h" #include "FrameTracer/FrameTracer.h" #include "Layer.h" @@ -155,14 +151,22 @@ static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888, ui::PixelFormat::YCBCR_P010, ui::PixelFormat::HSV_888}; -FloatRect getFuzzedFloatRect(FuzzedDataProvider *fdp) { +inline VsyncId getFuzzedVsyncId(FuzzedDataProvider& fdp) { + return VsyncId{fdp.ConsumeIntegral<int64_t>()}; +} + +inline TimePoint getFuzzedTimePoint(FuzzedDataProvider& fdp) { + return TimePoint::fromNs(fdp.ConsumeIntegral<nsecs_t>()); +} + +inline FloatRect getFuzzedFloatRect(FuzzedDataProvider* fdp) { return FloatRect(fdp->ConsumeFloatingPoint<float>() /*left*/, fdp->ConsumeFloatingPoint<float>() /*right*/, fdp->ConsumeFloatingPoint<float>() /*top*/, fdp->ConsumeFloatingPoint<float>() /*bottom*/); } -HdrMetadata getFuzzedHdrMetadata(FuzzedDataProvider *fdp) { +inline HdrMetadata getFuzzedHdrMetadata(FuzzedDataProvider* fdp) { HdrMetadata hdrMetadata; if (fdp->ConsumeBool()) { hdrMetadata.cta8613.maxContentLightLevel = fdp->ConsumeFloatingPoint<float>(); @@ -272,8 +276,9 @@ public: private: // ICompositor overrides: - bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } - void composite(nsecs_t, int64_t) override {} + void configure() override {} + bool commit(TimePoint, VsyncId, TimePoint) override { return false; } + void composite(TimePoint, VsyncId) override {} void sample() override {} // MessageQueue overrides: @@ -286,13 +291,18 @@ private: namespace surfaceflinger::test { class Factory final : public surfaceflinger::Factory { + struct NoOpMessageQueue : android::impl::MessageQueue { + using android::impl::MessageQueue::MessageQueue; + void onFrameSignal(ICompositor&, VsyncId, TimePoint) override {} + }; + public: ~Factory() = default; - std::unique_ptr<HWComposer> createHWComposer(const std::string &) override { return nullptr; } + std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; } - std::unique_ptr<MessageQueue> createMessageQueue(ICompositor &compositor) { - return std::make_unique<android::impl::MessageQueue>(compositor); + std::unique_ptr<MessageQueue> createMessageQueue(ICompositor& compositor) { + return std::make_unique<NoOpMessageQueue>(compositor); } std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration( @@ -307,21 +317,21 @@ public: } sp<SurfaceInterceptor> createSurfaceInterceptor() override { - return new android::impl::SurfaceInterceptor(); + return sp<android::impl::SurfaceInterceptor>::make(); } sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override { - return new StartPropertySetThread(timestampPropertyValue); + return sp<StartPropertySetThread>::make(timestampPropertyValue); } sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs &creationArgs) override { - return new DisplayDevice(creationArgs); + return sp<DisplayDevice>::make(creationArgs); } sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) override { - return new GraphicBuffer(width, height, format, layerCount, usage, requestorName); + return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName); } void createBufferQueue(sp<IGraphicBufferProducer> *outProducer, @@ -334,18 +344,6 @@ public: mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger); } - sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer> &producer, - const sp<SurfaceFlinger> &flinger, - const wp<Layer> &layer) override { - return new MonitoredProducer(producer, flinger, layer); - } - - sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer> &consumer, - renderengine::RenderEngine &renderEngine, - uint32_t textureName, Layer *layer) override { - return new BufferLayerConsumer(consumer, renderEngine, textureName, layer); - } - std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer> &producer) override { if (!mCreateNativeWindowSurface) return nullptr; @@ -356,20 +354,10 @@ public: return compositionengine::impl::createCompositionEngine(); } - sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs &) override { - return nullptr; - } - - sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs &) override { - return nullptr; - } - - sp<EffectLayer> createEffectLayer(const LayerCreationArgs &args) override { - return new EffectLayer(args); - } + sp<Layer> createBufferStateLayer(const LayerCreationArgs &) override { return nullptr; } - sp<ContainerLayer> createContainerLayer(const LayerCreationArgs &args) override { - return new ContainerLayer(args); + sp<Layer> createEffectLayer(const LayerCreationArgs &args) override { + return sp<Layer>::make(args); } std::unique_ptr<FrameTracer> createFrameTracer() override { @@ -447,15 +435,13 @@ public: mFlinger->clearStatsLocked(dumpArgs, result); mFlinger->dumpTimeStats(dumpArgs, fdp->ConsumeBool(), result); - FTL_FAKE_GUARD(kMainThreadContext, mFlinger->logFrameStats()); + FTL_FAKE_GUARD(kMainThreadContext, + mFlinger->logFrameStats(TimePoint::fromNs(fdp->ConsumeIntegral<nsecs_t>()))); result = fdp->ConsumeRandomLengthString().c_str(); mFlinger->dumpFrameTimeline(dumpArgs, result); result = fdp->ConsumeRandomLengthString().c_str(); - mFlinger->dumpStaticScreenStats(result); - - result = fdp->ConsumeRandomLengthString().c_str(); mFlinger->dumpRawDisplayIdentificationData(dumpArgs, result); LayersProto layersProto = mFlinger->dumpDrawingStateProto(fdp->ConsumeIntegral<uint32_t>()); @@ -540,19 +526,9 @@ public: mFlinger->setVsyncConfig(vsyncConfig, fdp->ConsumeIntegral<nsecs_t>()); } - void updateCompositorTiming(FuzzedDataProvider *fdp) { - std::shared_ptr<FenceTime> presentFenceTime = FenceTime::NO_FENCE; - mFlinger->updateCompositorTiming({}, fdp->ConsumeIntegral<nsecs_t>(), presentFenceTime); - } - - void getCompositorTiming() { - CompositorTiming compositorTiming; - mFlinger->getCompositorTiming(&compositorTiming); - } - sp<IBinder> fuzzBoot(FuzzedDataProvider *fdp) { mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool()); - mFlinger->createConnection(); + const sp<Client> client = sp<Client>::make(mFlinger); DisplayIdGenerator<HalVirtualDisplayId> kGenerator; HalVirtualDisplayId halVirtualDisplayId = kGenerator.generateId().value(); @@ -561,7 +537,9 @@ public: ui::PixelFormat pixelFormat{}; mFlinger->getHwComposer().allocateVirtualDisplay(halVirtualDisplayId, uiSize, &pixelFormat); - PhysicalDisplayId physicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value(); + PhysicalDisplayId physicalDisplayId = + SurfaceComposerClient::getInternalDisplayId().value_or( + PhysicalDisplayId::fromPort(fdp->ConsumeIntegral<uint8_t>())); mFlinger->getHwComposer().allocatePhysicalDisplay(kHwDisplayId, physicalDisplayId); sp<IBinder> display = @@ -585,7 +563,6 @@ public: sp<IBinder> display = fuzzBoot(&mFdp); sp<IGraphicBufferProducer> bufferProducer = sp<mock::GraphicBufferProducer>::make(); - mFlinger->authenticateSurfaceTexture(bufferProducer.get()); mFlinger->createDisplayEventConnection(); @@ -598,7 +575,6 @@ public: mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool()); mFlinger->setGameContentType(display, mFdp.ConsumeBool()); mFlinger->setPowerMode(display, mFdp.ConsumeIntegral<int>()); - mFlinger->clearAnimationFrameStats(); overrideHdrTypes(display, &mFdp); @@ -620,19 +596,24 @@ public: mFlinger->binderDied(display); mFlinger->onFirstRef(); - mFlinger->commitTransactions(); mFlinger->updateInputFlinger(); mFlinger->updateCursorAsync(); setVsyncConfig(&mFdp); - mFlinger->flushTransactionQueues(0); + { + ftl::FakeGuard guard(kMainThreadContext); + + mFlinger->commitTransactions(); + mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)); + mFlinger->postComposition(); + } mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>()); mFlinger->clearTransactionFlags(mFdp.ConsumeIntegral<uint32_t>()); mFlinger->commitOffscreenLayers(); - mFlinger->frameIsEarly(mFdp.ConsumeIntegral<nsecs_t>(), mFdp.ConsumeIntegral<int64_t>()); + mFlinger->frameIsEarly(getFuzzedTimePoint(mFdp), getFuzzedVsyncId(mFdp)); mFlinger->computeLayerBounds(); mFlinger->startBootAnim(); @@ -643,14 +624,6 @@ public: mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mFdp.ConsumeIntegral<uid_t>()); - mFlinger->postComposition(); - - getCompositorTiming(); - - updateCompositorTiming(&mFdp); - - mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral<nsecs_t>()); - FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame()); mFlinger->calculateExpectedPresentTime({}); mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool()); @@ -689,7 +662,8 @@ public: } mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60); - const auto fps = mRefreshRateConfigs->getActiveMode()->getFps(); + const auto fps = + FTL_FAKE_GUARD(kMainThreadContext, mRefreshRateConfigs->getActiveMode().getFps()); mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps); mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); @@ -740,9 +714,9 @@ public: void enableHalVirtualDisplays(bool enable) { mFlinger->enableHalVirtualDisplays(enable); } - auto commitTransactionsLocked(uint32_t transactionFlags) { + void commitTransactionsLocked(uint32_t transactionFlags) FTL_FAKE_GUARD(kMainThreadContext) { Mutex::Autolock lock(mFlinger->mStateLock); - return mFlinger->commitTransactionsLocked(transactionFlags); + mFlinger->commitTransactionsLocked(transactionFlags); } auto setDisplayStateLocked(const DisplayState &s) { @@ -758,7 +732,7 @@ public: return mFlinger->setPowerModeInternal(display, mode); } - auto &getTransactionQueue() { return mFlinger->mTransactionQueue; } + auto &getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; } auto &getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } auto setTransactionState( @@ -773,13 +747,11 @@ public: listenerCallbacks, transactionId); } - auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); }; - auto onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { return mFlinger->onTransact(code, data, reply, flags); } - auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); } + auto getGpuContextPriority() { return mFlinger->getGpuContextPriority(); } auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { @@ -815,7 +787,8 @@ private: void triggerOnFrameRateOverridesChanged() override {} surfaceflinger::test::Factory mFactory; - sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); + sp<SurfaceFlinger> mFlinger = + sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization); scheduler::TestableScheduler *mScheduler = nullptr; std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; }; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp index 34cf90628a..0a142c3ce6 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp @@ -14,13 +14,9 @@ * limitations under the License. * */ -#include <BufferStateLayer.h> #include <Client.h> #include <DisplayDevice.h> -#include <EffectLayer.h> -#include <LayerRejecter.h> #include <LayerRenderArea.h> -#include <MonitoredProducer.h> #include <ftl/future.h> #include <fuzzer/FuzzedDataProvider.h> #include <gui/IProducerListener.h> @@ -59,8 +55,10 @@ Rect LayerFuzzer::getFuzzedRect() { } FrameTimelineInfo LayerFuzzer::getFuzzedFrameTimelineInfo() { - return FrameTimelineInfo{.vsyncId = mFdp.ConsumeIntegral<int64_t>(), - .inputEventId = mFdp.ConsumeIntegral<int32_t>()}; + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = mFdp.ConsumeIntegral<int64_t>(); + ftInfo.inputEventId = mFdp.ConsumeIntegral<int32_t>(); + return ftInfo; } LayerCreationArgs LayerFuzzer::createLayerCreationArgs(TestableSurfaceFlinger* flinger, @@ -77,15 +75,15 @@ LayerCreationArgs LayerFuzzer::createLayerCreationArgs(TestableSurfaceFlinger* f void LayerFuzzer::invokeEffectLayer() { TestableSurfaceFlinger flinger; - sp<Client> client = sp<Client>::make(flinger.flinger()); + sp<Client> client = sp<Client>::make(sp<SurfaceFlinger>::fromExisting(flinger.flinger())); const LayerCreationArgs layerCreationArgs = createLayerCreationArgs(&flinger, client); - sp<EffectLayer> effectLayer = sp<EffectLayer>::make(layerCreationArgs); + sp<Layer> effectLayer = sp<Layer>::make(layerCreationArgs); effectLayer->setColor({(mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*x*/, mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*y*/, mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*z*/)}); effectLayer->setDataspace(mFdp.PickValueInArray(kDataspaces)); - sp<EffectLayer> parent = sp<EffectLayer>::make(layerCreationArgs); + sp<Layer> parent = sp<Layer>::make(layerCreationArgs); effectLayer->setChildrenDrawingParent(parent); const FrameTimelineInfo frameInfo = getFuzzedFrameTimelineInfo(); @@ -109,24 +107,22 @@ void LayerFuzzer::invokeEffectLayer() { void LayerFuzzer::invokeBufferStateLayer() { TestableSurfaceFlinger flinger; - sp<Client> client = sp<Client>::make(flinger.flinger()); - sp<BufferStateLayer> layer = - sp<BufferStateLayer>::make(createLayerCreationArgs(&flinger, client)); + sp<Client> client = sp<Client>::make(sp<SurfaceFlinger>::fromExisting(flinger.flinger())); + sp<Layer> layer = sp<Layer>::make(createLayerCreationArgs(&flinger, client)); sp<Fence> fence = sp<Fence>::make(); const std::shared_ptr<FenceTime> fenceTime = std::make_shared<FenceTime>(fence); - const CompositorTiming compositor = {mFdp.ConsumeIntegral<int64_t>(), - mFdp.ConsumeIntegral<int64_t>(), - mFdp.ConsumeIntegral<int64_t>()}; + const CompositorTiming compositorTiming(mFdp.ConsumeIntegral<int64_t>(), + mFdp.ConsumeIntegral<int64_t>(), + mFdp.ConsumeIntegral<int64_t>(), + mFdp.ConsumeIntegral<int64_t>()); layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share()); layer->onLayerDisplayed( ftl::yield<FenceResult>(base::unexpected(mFdp.ConsumeIntegral<status_t>())).share()); layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>()); - layer->finalizeFrameEventHistory(fenceTime, compositor); - layer->onPostComposition(nullptr, fenceTime, fenceTime, compositor); - layer->isBufferDue(mFdp.ConsumeIntegral<int64_t>()); + layer->onPostComposition(nullptr, fenceTime, fenceTime, compositorTiming); layer->setTransform(mFdp.ConsumeIntegral<uint32_t>()); layer->setTransformToDisplayInverse(mFdp.ConsumeBool()); @@ -150,8 +146,8 @@ void LayerFuzzer::invokeBufferStateLayer() { layer->computeSourceBounds(getFuzzedFloatRect(&mFdp)); layer->fenceHasSignaled(); - layer->framePresentTimeIsCurrent(mFdp.ConsumeIntegral<int64_t>()); - layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>()); + layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>(), + false /*updatingOutputGeometryThisFrame*/); const std::vector<sp<CallbackHandle>> callbacks; layer->setTransactionCompletedListeners(callbacks); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index da60a6981b..66bac44a3b 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -19,6 +19,8 @@ #include <fuzzer/FuzzedDataProvider.h> #include <processgroup/sched_policy.h> +#include <scheduler/PresentLatencyTracker.h> + #include "Scheduler/DispSyncSource.h" #include "Scheduler/OneShotTimer.h" #include "Scheduler/VSyncDispatchTimerQueue.h" @@ -58,6 +60,7 @@ public: private: void fuzzRefreshRateSelection(); void fuzzRefreshRateConfigs(); + void fuzzPresentLatencyTracker(); void fuzzVSyncModulator(); void fuzzVSyncPredictor(); void fuzzVSyncReactor(); @@ -93,8 +96,8 @@ void SchedulerFuzzer::fuzzEventThread() { thread->onHotplugReceived(getPhysicalDisplayId(), mFdp.ConsumeBool()); sp<EventThreadConnection> connection = - new EventThreadConnection(thread.get(), mFdp.ConsumeIntegral<uint16_t>(), nullptr, - {} /*eventRegistration*/); + sp<EventThreadConnection>::make(thread.get(), mFdp.ConsumeIntegral<uint16_t>(), + nullptr); thread->requestNextVsync(connection); thread->setVsyncRate(mFdp.ConsumeIntegral<uint32_t>() /*rate*/, connection); @@ -224,8 +227,8 @@ void SchedulerFuzzer::fuzzLayerHistory() { nsecs_t time2 = time1; uint8_t historySize = mFdp.ConsumeIntegral<uint8_t>(); - sp<FuzzImplLayer> layer1 = new FuzzImplLayer(flinger.flinger()); - sp<FuzzImplLayer> layer2 = new FuzzImplLayer(flinger.flinger()); + sp<FuzzImplLayer> layer1 = sp<FuzzImplLayer>::make(flinger.flinger()); + sp<FuzzImplLayer> layer2 = sp<FuzzImplLayer>::make(flinger.flinger()); for (int i = 0; i < historySize; ++i) { historyV1.record(layer1.get(), time1, time1, @@ -260,7 +263,7 @@ void SchedulerFuzzer::fuzzVSyncReactor() { reactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed); reactor.addHwVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>() /*newPeriod*/, std::nullopt, &periodFlushed); - sp<Fence> fence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING)); + sp<Fence> fence = sp<Fence>::make(memfd_create("fd", MFD_ALLOW_SEALING)); std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence); vSyncTracker->addVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>()); FenceTime::Snapshot snap(mFdp.ConsumeIntegral<nsecs_t>()); @@ -319,7 +322,7 @@ void SchedulerFuzzer::fuzzRefreshRateSelection() { LayerCreationArgs args(flinger.flinger(), client, mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/, mFdp.ConsumeIntegral<uint16_t>() /*layerFlags*/, LayerMetadata()); - sp<Layer> layer = new BufferQueueLayer(args); + sp<Layer> layer = sp<Layer>::make(args); layer->setFrameRateSelectionPriority(mFdp.ConsumeIntegral<int16_t>()); } @@ -347,7 +350,7 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() { const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; std::vector<LayerRequirement> layers = {{.weight = mFdp.ConsumeFloatingPoint<float>()}}; - refreshRateConfigs.getBestRefreshRate(layers, globalSignals); + refreshRateConfigs.getRankedRefreshRates(layers, globalSignals); layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength); layers[0].ownerUid = mFdp.ConsumeIntegral<uint16_t>(); @@ -363,7 +366,7 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() { {modeId, {Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()), Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}}); - refreshRateConfigs.setActiveModeId(modeId); + FTL_FAKE_GUARD(kMainThreadContext, refreshRateConfigs.setActiveModeId(modeId)); RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue( mFdp.ConsumeFloatingPoint<float>()), @@ -376,15 +379,23 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() { RefreshRateStats refreshRateStats(timeStats, Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()), PowerMode::OFF); - const auto fpsOpt = displayModes.get(modeId, [](const auto& mode) { return mode->getFps(); }); + const auto fpsOpt = displayModes.get(modeId).transform( + [](const DisplayModePtr& mode) { return mode->getFps(); }); refreshRateStats.setRefreshRate(*fpsOpt); refreshRateStats.setPowerMode(mFdp.PickValueInArray(kPowerModes)); } +void SchedulerFuzzer::fuzzPresentLatencyTracker() { + scheduler::PresentLatencyTracker tracker; + tracker.trackPendingFrame(TimePoint::fromNs(mFdp.ConsumeIntegral<nsecs_t>()), + FenceTime::NO_FENCE); +} + void SchedulerFuzzer::process() { fuzzRefreshRateSelection(); fuzzRefreshRateConfigs(); + fuzzPresentLatencyTracker(); fuzzVSyncModulator(); fuzzVSyncPredictor(); fuzzVSyncReactor(); diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp index 973a4392a2..7287dd0103 100644 --- a/services/surfaceflinger/layerproto/Android.bp +++ b/services/surfaceflinger/layerproto/Android.bp @@ -44,10 +44,11 @@ cc_library { } java_library_static { - name: "layersprotosnano", + name: "layersprotoslite", host_supported: true, proto: { - type: "nano", + type: "lite", + include_dirs: ["external/protobuf/src"], }, srcs: ["*.proto"], sdk_version: "core_platform", @@ -56,7 +57,7 @@ java_library_static { jarjar_rules: "jarjar-rules.txt", }, host: { - static_libs: ["libprotobuf-java-nano"], + static_libs: ["libprotobuf-java-lite"], }, }, } diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h index 52503bad3a..cdc2706ee2 100644 --- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h +++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h @@ -24,6 +24,8 @@ #include <unordered_map> #include <vector> +using android::gui::LayerMetadata; + namespace android { namespace surfaceflinger { diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto index 13647b669e..804a4994ee 100644 --- a/services/surfaceflinger/layerproto/layerstrace.proto +++ b/services/surfaceflinger/layerproto/layerstrace.proto @@ -38,9 +38,13 @@ message LayersTraceFileProto { optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */ repeated LayersTraceProto entry = 2; + + /* offset between real-time clock and elapsed time clock in nanoseconds. + Calculated as: systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC) */ + optional fixed64 real_to_elapsed_time_offset_nanos = 3; } -/* one window manager trace entry. */ +/* one layers trace entry. */ message LayersTraceProto { /* required: elapsed realtime in nanos since boot of when this entry was logged */ optional sfixed64 elapsed_realtime_nanos = 1; @@ -60,4 +64,6 @@ message LayersTraceProto { optional uint32 missed_entries = 6; repeated DisplayProto displays = 7; + + optional int64 vsync_id = 8; } diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index 4f99b192a3..b687abc918 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -36,6 +36,10 @@ message TransactionTraceFile { fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */ repeated TransactionTraceEntry entry = 2; + + /* offset between real-time clock and elapsed time clock in nanoseconds. + Calculated as: systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC) */ + fixed64 real_to_elapsed_time_offset_nanos = 3; } message TransactionTraceEntry { @@ -78,7 +82,7 @@ message LayerState { eChangesLsbNone = 0; ePositionChanged = 0x00000001; eLayerChanged = 0x00000002; - eSizeChanged = 0x00000004; + // unused = 0x00000004; eAlphaChanged = 0x00000008; eMatrixChanged = 0x00000010; diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index ec180548e1..fedd71e921 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -67,7 +67,7 @@ static void startDisplayService() { using android::frameworks::displayservice::V1_0::implementation::DisplayService; using android::frameworks::displayservice::V1_0::IDisplayService; - sp<IDisplayService> displayservice = new DisplayService(); + sp<IDisplayService> displayservice = sp<DisplayService>::make(); status_t err = displayservice->registerAsService(); // b/141930622 @@ -153,7 +153,7 @@ int main(int, char**) { IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO); // publish gui::ISurfaceComposer, the new AIDL interface - sp<SurfaceComposerAIDL> composerAIDL = new SurfaceComposerAIDL(flinger); + sp<SurfaceComposerAIDL> composerAIDL = sp<SurfaceComposerAIDL>::make(flinger); sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false, IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO); diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index ceddf2727a..13ce65d4af 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -23,7 +23,10 @@ package { cc_test { name: "SurfaceFlinger_test", - defaults: ["surfaceflinger_defaults"], + defaults: [ + "android.hardware.graphics.common-ndk_shared", + "surfaceflinger_defaults", + ], test_suites: ["device-tests"], srcs: [ "BootDisplayMode_test.cpp", @@ -34,6 +37,7 @@ cc_test { "DisplayConfigs_test.cpp", "DisplayEventReceiver_test.cpp", "EffectLayer_test.cpp", + "LayerBorder_test.cpp", "InvalidHandles_test.cpp", "LayerCallback_test.cpp", "LayerRenderTypeTransaction_test.cpp", @@ -63,7 +67,6 @@ cc_test { "android.hardware.graphics.composer@2.1", ], shared_libs: [ - "android.hardware.graphics.common-V3-ndk", "android.hardware.graphics.common@1.2", "libandroid", "libbase", diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp index d70908e390..432e227cae 100644 --- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp +++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp @@ -18,6 +18,7 @@ #include <gtest/gtest.h> +#include <gui/AidlStatusUtil.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> #include <private/gui/ComposerServiceAIDL.h> @@ -25,15 +26,17 @@ namespace android { +using gui::aidl_utils::statusTFromBinderStatus; + TEST(BootDisplayModeTest, setBootDisplayMode) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService()); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); auto displayToken = SurfaceComposerClient::getInternalDisplayToken(); bool bootModeSupport = false; - binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport); - ASSERT_NO_FATAL_FAILURE(status.transactionError()); + binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport); + ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status)); if (bootModeSupport) { - ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0)); + status = sf->setBootDisplayMode(displayToken, 0); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); } } @@ -42,10 +45,10 @@ TEST(BootDisplayModeTest, clearBootDisplayMode) { auto displayToken = SurfaceComposerClient::getInternalDisplayToken(); bool bootModeSupport = false; binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport); - ASSERT_NO_FATAL_FAILURE(status.transactionError()); + ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status)); if (bootModeSupport) { status = sf->clearBootDisplayMode(displayToken); - ASSERT_EQ(NO_ERROR, status.transactionError()); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); } } diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp index 47a150dd35..d74bd55987 100644 --- a/services/surfaceflinger/tests/BufferGenerator.cpp +++ b/services/surfaceflinger/tests/BufferGenerator.cpp @@ -70,12 +70,13 @@ public: consumer->setDefaultBufferSize(width, height); consumer->setDefaultBufferFormat(format); - mBufferItemConsumer = new BufferItemConsumer(consumer, GraphicBuffer::USAGE_HW_TEXTURE); + mBufferItemConsumer = + sp<BufferItemConsumer>::make(consumer, GraphicBuffer::USAGE_HW_TEXTURE); - mListener = new BufferListener(consumer, callback); + mListener = sp<BufferListener>::make(consumer, callback); mBufferItemConsumer->setFrameAvailableListener(mListener); - mSurface = new Surface(producer, true); + mSurface = sp<Surface>::make(producer, true); } /* Used by Egl manager. The surface is never displayed. */ @@ -364,7 +365,7 @@ status_t BufferGenerator::get(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) *outBuffer = mGraphicBuffer; } if (outFence) { - *outFence = new Fence(mFence); + *outFence = sp<Fence>::make(mFence); } else { close(mFence); } diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 434c297cc9..775de4a8fe 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -18,13 +18,14 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#include <android/gui/ISurfaceComposer.h> #include <gtest/gtest.h> -#include <gui/ISurfaceComposer.h> +#include <gui/AidlStatusUtil.h> #include <gui/LayerDebugInfo.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/android_filesystem_config.h> -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <ui/DisplayMode.h> #include <ui/DynamicDisplayInfo.h> #include <utils/String8.h> @@ -34,6 +35,8 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; +using gui::LayerDebugInfo; +using gui::aidl_utils::statusTFromBinderStatus; using ui::ColorMode; namespace { @@ -67,7 +70,7 @@ protected: sp<SurfaceControl> mVirtualSurfaceControl; void initClient() { - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); } @@ -149,7 +152,7 @@ TEST_F(CredentialsTest, ClientInitTest) { // Anyone else can init the client. { UIDFaker f(AID_BIN); - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_NO_FATAL_FAILURE(initClient()); } } @@ -301,27 +304,31 @@ TEST_F(CredentialsTest, CaptureLayersTest) { */ TEST_F(CredentialsTest, GetLayerDebugInfo) { setupBackgroundSurface(); - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); // Historically, only root and shell can access the getLayerDebugInfo which // is called when we call dumpsys. I don't see a reason why we should change this. std::vector<LayerDebugInfo> outLayers; + binder::Status status = binder::Status::ok(); // Check with root. { UIDFaker f(AID_ROOT); - ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers)); + status = sf->getLayerDebugInfo(&outLayers); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); } // Check as a shell. { UIDFaker f(AID_SHELL); - ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers)); + status = sf->getLayerDebugInfo(&outLayers); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); } // Check as anyone else. { UIDFaker f(AID_BIN); - ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers)); + status = sf->getLayerDebugInfo(&outLayers); + ASSERT_EQ(PERMISSION_DENIED, statusTFromBinderStatus(status)); } } diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp index 0e54664f77..0df7e2fafa 100644 --- a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp +++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp @@ -36,7 +36,8 @@ TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) { EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now) << "Deadline timestamp should be greater than frame time"; for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { - EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].vsyncId); + EXPECT_NE(gui::FrameTimelineInfo::INVALID_VSYNC_ID, + vsyncEventData.frameTimelines[i].vsyncId); EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, vsyncEventData.frameTimelines[i].deadlineTimestamp) << "Expected vsync timestamp should be greater than deadline"; @@ -51,4 +52,4 @@ TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) { } } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index ce94dab907..c63d251c31 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -136,7 +136,7 @@ public: } status_t initClient() override { - mClient = new SurfaceComposerClient; + mClient = sp<SurfaceComposerClient>::make(); auto err = mClient->initCheck(); return err; } @@ -221,7 +221,7 @@ public: ProcessState::self()->startThreadPool(); } void SetUp() { - mClient = new SurfaceComposerClient; + mClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mClient->initCheck()); mPrimaryDisplay = mClient->getInternalDisplayToken(); diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp index d192a2d83d..741b6f73e5 100644 --- a/services/surfaceflinger/tests/InvalidHandles_test.cpp +++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp @@ -42,13 +42,13 @@ protected: sp<SurfaceComposerClient> mScc; sp<SurfaceControl> mNotSc; void SetUp() override { - mScc = new SurfaceComposerClient; + mScc = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mScc->initCheck()); mNotSc = makeNotSurfaceControl(); } sp<SurfaceControl> makeNotSurfaceControl() { - return new SurfaceControl(mScc, new NotALayer(), nullptr, true); + return sp<SurfaceControl>::make(mScc, sp<NotALayer>::make(), 1); } }; @@ -64,4 +64,4 @@ TEST_F(InvalidHandleTest, captureLayersInvalidHandle) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/LayerBorder_test.cpp b/services/surfaceflinger/tests/LayerBorder_test.cpp new file mode 100644 index 0000000000..85108ad8e6 --- /dev/null +++ b/services/surfaceflinger/tests/LayerBorder_test.cpp @@ -0,0 +1,285 @@ +/* + * 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. + */ + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +// TODO: Amend all tests when screenshots become fully reworked for borders +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +#include <chrono> // std::chrono::seconds +#include <thread> // std::this_thread::sleep_for +#include "LayerTransactionTest.h" + +namespace android { + +class LayerBorderTest : public LayerTransactionTest { +protected: + virtual void SetUp() { + LayerTransactionTest::SetUp(); + ASSERT_EQ(NO_ERROR, mClient->initCheck()); + + toHalf3 = ColorTransformHelper::toHalf3; + toHalf4 = ColorTransformHelper::toHalf4; + + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); + mColorOrange = toHalf4({255, 140, 0, 255}); + mParentLayer = createColorLayer("Parent layer", Color::RED); + + mContainerLayer = mClient->createSurface(String8("Container Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceContainer | + ISurfaceComposerClient::eNoColorFill, + mParentLayer->getHandle()); + EXPECT_NE(nullptr, mContainerLayer.get()) << "failed to create container layer"; + + mEffectLayer1 = mClient->createSurface(String8("Effect Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + EXPECT_NE(nullptr, mEffectLayer1.get()) << "failed to create effect layer 1"; + + mEffectLayer2 = mClient->createSurface(String8("Effect Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + + EXPECT_NE(nullptr, mEffectLayer2.get()) << "failed to create effect layer 2"; + + asTransaction([&](Transaction& t) { + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); + t.setLayer(mParentLayer, INT32_MAX - 20).show(mParentLayer); + t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); + + t.setColor(mEffectLayer1, toHalf3(Color::BLUE)); + + t.setColor(mEffectLayer2, toHalf3(Color::GREEN)); + }); + } + + virtual void TearDown() { + // Uncomment the line right below when running any of the tests + // std::this_thread::sleep_for (std::chrono::seconds(30)); + LayerTransactionTest::TearDown(); + mParentLayer = 0; + } + + std::function<half3(Color)> toHalf3; + std::function<half4(Color)> toHalf4; + sp<SurfaceControl> mParentLayer, mContainerLayer, mEffectLayer1, mEffectLayer2; + half4 mColorOrange; +}; + +TEST_F(LayerBorderTest, OverlappingVisibleRegions) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, PartiallyCoveredVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, NonOverlappingVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200)); + t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, EmptyVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(200, 200, 400, 400)); + t.setCrop(mEffectLayer2, Rect(0, 0, 600, 600)); + + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, ZOrderAdjustment) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setLayer(mParentLayer, 10); + t.setLayer(mEffectLayer1, 30); + t.setLayer(mEffectLayer2, 20); + + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, GrandChildHierarchy) { + sp<SurfaceControl> containerLayer2 = + mClient->createSurface(String8("Container Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceContainer | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + EXPECT_NE(nullptr, containerLayer2.get()) << "failed to create container layer 2"; + + sp<SurfaceControl> effectLayer3 = + mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + containerLayer2->getHandle()); + + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setCrop(effectLayer3, Rect(400, 400, 800, 800)); + t.setColor(effectLayer3, toHalf3(Color::BLUE)); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(effectLayer3); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, TransparentAlpha) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setAlpha(mEffectLayer1, 0.0f); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, SemiTransparentAlpha) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setAlpha(mEffectLayer2, 0.5f); + + t.enableBorder(mEffectLayer2, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, InvisibleLayers) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.hide(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, LayerWithBuffer) { + asTransaction([&](Transaction& t) { + t.hide(mEffectLayer1); + t.hide(mEffectLayer2); + t.show(mContainerLayer); + + sp<SurfaceControl> layer = + mClient->createSurface(String8("BufferState"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + mContainerLayer->getHandle()); + + sp<GraphicBuffer> buffer = + sp<GraphicBuffer>::make(400u, 400u, PIXEL_FORMAT_RGBA_8888, 1u, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY | + BufferUsage::GPU_TEXTURE, + "test"); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 200, 200), Color::GREEN); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(200, 200, 400, 400), Color::BLUE); + + t.setBuffer(layer, buffer); + t.setPosition(layer, 100, 100); + t.show(layer); + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + }); +} + +TEST_F(LayerBorderTest, CustomWidth) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 50, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, CustomColor) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, toHalf4({255, 0, 255, 255})); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, CustomWidthAndColorAndOpacity) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200)); + t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600)); + + t.enableBorder(mContainerLayer, true, 40, toHalf4({255, 255, 0, 128})); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +} // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 219db8c148..26dbc76c3c 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -51,7 +51,7 @@ public: LayerTransactionTest::TearDown(); } - virtual sp<SurfaceControl> createBufferStateLayer() { + virtual sp<SurfaceControl> createLayerWithBuffer() { return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState); } @@ -164,7 +164,7 @@ public: TEST_F(LayerCallbackTest, BufferColor) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -183,7 +183,7 @@ TEST_F(LayerCallbackTest, BufferColor) { TEST_F(LayerCallbackTest, NoBufferNoColor) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -206,7 +206,7 @@ TEST_F(LayerCallbackTest, NoBufferNoColor) { TEST_F(LayerCallbackTest, BufferNoColor) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -228,7 +228,7 @@ TEST_F(LayerCallbackTest, BufferNoColor) { TEST_F(LayerCallbackTest, NoBufferColor) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -266,7 +266,7 @@ TEST_F(LayerCallbackTest, NoStateChange) { TEST_F(LayerCallbackTest, OffScreen) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -288,8 +288,8 @@ TEST_F(LayerCallbackTest, OffScreen) { TEST_F(LayerCallbackTest, MergeBufferNoColor) { sp<SurfaceControl> layer1, layer2; - ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer()); - ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer1 = createLayerWithBuffer()); + ASSERT_NO_FATAL_FAILURE(layer2 = createLayerWithBuffer()); Transaction transaction1, transaction2; CallbackHelper callback1, callback2; @@ -322,8 +322,8 @@ TEST_F(LayerCallbackTest, MergeBufferNoColor) { TEST_F(LayerCallbackTest, MergeNoBufferColor) { sp<SurfaceControl> layer1, layer2; - ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer()); - ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer1 = createLayerWithBuffer()); + ASSERT_NO_FATAL_FAILURE(layer2 = createLayerWithBuffer()); Transaction transaction1, transaction2; CallbackHelper callback1, callback2; @@ -357,8 +357,8 @@ TEST_F(LayerCallbackTest, MergeNoBufferColor) { TEST_F(LayerCallbackTest, MergeOneBufferOneColor) { sp<SurfaceControl> layer1, layer2; - ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer()); - ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer1 = createLayerWithBuffer()); + ASSERT_NO_FATAL_FAILURE(layer2 = createLayerWithBuffer()); Transaction transaction1, transaction2; CallbackHelper callback1, callback2; @@ -392,8 +392,8 @@ TEST_F(LayerCallbackTest, MergeOneBufferOneColor) { } TEST_F(LayerCallbackTest, Merge_SameCallback) { sp<SurfaceControl> layer1, layer2; - ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer()); - ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer1 = createLayerWithBuffer()); + ASSERT_NO_FATAL_FAILURE(layer2 = createLayerWithBuffer()); Transaction transaction1, transaction2; CallbackHelper callback; @@ -418,7 +418,7 @@ TEST_F(LayerCallbackTest, Merge_SameCallback) { TEST_F(LayerCallbackTest, Merge_SameLayer) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction1, transaction2; CallbackHelper callback1, callback2; @@ -442,8 +442,8 @@ TEST_F(LayerCallbackTest, Merge_SameLayer) { } TEST_F(LayerCallbackTest, Merge_DifferentClients) { - sp<SurfaceComposerClient> client1(new SurfaceComposerClient), - client2(new SurfaceComposerClient); + sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()), + client2(sp<SurfaceComposerClient>::make()); ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient"; ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient"; @@ -485,7 +485,7 @@ TEST_F(LayerCallbackTest, Merge_DifferentClients) { TEST_F(LayerCallbackTest, MultipleTransactions) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -510,7 +510,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions) { TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -541,7 +541,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) { TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -579,8 +579,8 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { TEST_F(LayerCallbackTest, MultipleTransactions_Merge) { sp<SurfaceControl> layer1, layer2; - ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer()); - ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer1 = createLayerWithBuffer()); + ASSERT_NO_FATAL_FAILURE(layer2 = createLayerWithBuffer()); Transaction transaction1, transaction2; CallbackHelper callback1, callback2; @@ -620,8 +620,8 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge) { } TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) { - sp<SurfaceComposerClient> client1(new SurfaceComposerClient), - client2(new SurfaceComposerClient); + sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()), + client2(sp<SurfaceComposerClient>::make()); ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient"; ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient"; @@ -669,8 +669,8 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) { } TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) { - sp<SurfaceComposerClient> client1(new SurfaceComposerClient), - client2(new SurfaceComposerClient); + sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()), + client2(sp<SurfaceComposerClient>::make()); ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient"; ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient"; @@ -730,8 +730,8 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha } TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) { - sp<SurfaceComposerClient> client1(new SurfaceComposerClient), - client2(new SurfaceComposerClient); + sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()), + client2(sp<SurfaceComposerClient>::make()); ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient"; ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient"; @@ -799,7 +799,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC // TODO (b/183181768): Fix & re-enable TEST_F(LayerCallbackTest, DISABLED_MultipleTransactions_SingleFrame) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -823,7 +823,7 @@ TEST_F(LayerCallbackTest, DISABLED_MultipleTransactions_SingleFrame) { TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); // Normal call to set up test Transaction transaction; @@ -858,7 +858,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) { TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); // Normal call to set up test Transaction transaction; @@ -901,7 +901,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { TEST_F(LayerCallbackTest, DesiredPresentTime) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -925,7 +925,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime) { TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback1; @@ -971,7 +971,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) { // TODO (b/183181768): Fix & re-enable TEST_F(LayerCallbackTest, DISABLED_DesiredPresentTime_OutOfOrder) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback1; @@ -1015,7 +1015,7 @@ TEST_F(LayerCallbackTest, DISABLED_DesiredPresentTime_OutOfOrder) { TEST_F(LayerCallbackTest, DesiredPresentTime_Past) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -1039,7 +1039,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_Past) { TEST_F(LayerCallbackTest, ExpectedPresentTime) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -1050,7 +1050,10 @@ TEST_F(LayerCallbackTest, ExpectedPresentTime) { } const Vsync vsync = waitForNextVsync(); - transaction.setFrameTimelineInfo({vsync.vsyncId, 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = vsync.vsyncId; + ftInfo.inputEventId = 0; + transaction.setFrameTimelineInfo(ftInfo); transaction.apply(); ExpectedResult expected; @@ -1062,8 +1065,8 @@ TEST_F(LayerCallbackTest, ExpectedPresentTime) { // b202394221 TEST_F(LayerCallbackTest, EmptyBufferStateChanges) { sp<SurfaceControl> bufferLayer, emptyBufferLayer; - ASSERT_NO_FATAL_FAILURE(bufferLayer = createBufferStateLayer()); - ASSERT_NO_FATAL_FAILURE(emptyBufferLayer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayerWithBuffer()); + ASSERT_NO_FATAL_FAILURE(emptyBufferLayer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; @@ -1117,7 +1120,7 @@ TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) { TEST_F(LayerCallbackTest, CommitCallbackOffscreenLayer) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); sp<SurfaceControl> offscreenLayer = createSurface(mClient, "Offscreen Layer", 0, 0, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, layer.get()); @@ -1148,7 +1151,7 @@ TEST_F(LayerCallbackTest, CommitCallbackOffscreenLayer) { TEST_F(LayerCallbackTest, TransactionCommittedCallback_BSL) { sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer()); Transaction transaction; CallbackHelper callback; diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 0e2bc3df0e..bf7cae9091 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -328,7 +328,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); ASSERT_NO_FATAL_FAILURE( TransactionUtils::fillGraphicBufferColor(buffer, top, Color::TRANSPARENT)); @@ -352,7 +352,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState shot->expectColor(bottom, Color::BLACK); } - buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, top, Color::RED)); ASSERT_NO_FATAL_FAILURE( @@ -399,7 +399,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_Buffe .apply(); ASSERT_NO_FATAL_FAILURE( fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layerR, Color::RED, 32, 32)); getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED); } @@ -482,7 +482,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) { } } -// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill +// RED: Color layer base color and Layer buffer fill // BLUE: prior background color // GREEN: final background color // BLACK: no color or fill @@ -516,7 +516,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType case ISurfaceComposerClient::eFXSurfaceBufferState: ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType)); if (bufferFill) { - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, fillColor, width, height)); expectedColor = fillColor; } Transaction().setCrop(layer, Rect(0, 0, width, height)).apply(); @@ -832,7 +832,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); const Rect crop(8, 8, 24, 24); Transaction().setCrop(layer, crop).apply(); @@ -863,7 +863,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); { SCOPED_TRACE("empty rect"); @@ -894,7 +894,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState)); sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(32, 64, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED); @@ -944,7 +944,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); const Rect crop(8, 8, 24, 24); Transaction().setPosition(layer, 32, 32).setCrop(layer, crop).apply(); @@ -972,7 +972,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); const Rect frame(8, 8, 24, 24); Transaction t; @@ -988,7 +988,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); Transaction t; { @@ -1014,7 +1014,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 10, 10)); // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); @@ -1026,11 +1026,11 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { sp<SurfaceControl> parent, child; ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(parent, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE( child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); @@ -1047,7 +1047,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) { ASSERT_NO_FATAL_FAILURE( child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); @@ -1061,7 +1061,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); std::this_thread::sleep_for(500ms); @@ -1080,9 +1080,9 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) { child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); Transaction().reparent(child, parent).apply(); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(parent, Color::RED, 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(child, Color::BLUE, 10, 10)); Rect childDst(0, 16, 32, 32); Transaction t; TransactionUtils::setFrame(t, child, Rect(0, 0, 10, 10), childDst); @@ -1099,7 +1099,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) { ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); auto shot = getScreenCapture(); shot->expectColor(Rect(0, 0, 32, 32), Color::RED); @@ -1111,7 +1111,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); { SCOPED_TRACE("set buffer 1"); @@ -1120,7 +1120,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::BLUE, 32, 32)); { SCOPED_TRACE("set buffer 2"); @@ -1129,7 +1129,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); { SCOPED_TRACE("set buffer 3"); @@ -1148,7 +1148,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE( layer2 = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer1, Color::RED, 64, 64)); { SCOPED_TRACE("set layer 1 buffer red"); @@ -1156,7 +1156,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { shot->expectColor(Rect(0, 0, 64, 64), Color::RED); } - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer2, Color::BLUE, 32, 32)); { SCOPED_TRACE("set layer 2 buffer blue"); @@ -1166,7 +1166,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { shot->expectColor(Rect(0, 32, 32, 64), Color::RED); } - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer1, Color::GREEN, 64, 64)); { SCOPED_TRACE("set layer 1 buffer green"); auto shot = getScreenCapture(); @@ -1175,7 +1175,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN); } - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::WHITE, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer2, Color::WHITE, 32, 32)); { SCOPED_TRACE("set layer 2 buffer white"); @@ -1197,7 +1197,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) { size_t idx = 0; for (auto& buffer : buffers) { - buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); Color color = colors[idx % colors.size()]; TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); idx++; @@ -1230,7 +1230,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_Buffer size_t idx = 0; for (auto& buffer : buffers) { - buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); Color color = colors[idx % colors.size()]; TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); idx++; @@ -1263,7 +1263,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferSt size_t idx = 0; for (auto& buffer : buffers) { - buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); Color color = colors[idx % colors.size()]; TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); idx++; @@ -1344,7 +1344,7 @@ TEST_P(LayerRenderTypeTransactionTest, DISABLED_SetFenceBasic_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); sp<Fence> fence; @@ -1370,7 +1370,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); sp<Fence> fence = Fence::NO_FENCE; @@ -1388,7 +1388,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply(); @@ -1404,7 +1404,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); HdrMetadata hdrMetadata; @@ -1422,7 +1422,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); Region region; @@ -1440,7 +1440,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply(); diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index 094b0ffc0f..21813700a2 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -35,7 +35,7 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) { args.frameScaleX = 2; args.frameScaleY = 4; args.captureSecureLayers = true; - args.displayToken = new BBinder(); + args.displayToken = sp<BBinder>::make(); args.width = 10; args.height = 20; args.useIdentityTransform = true; @@ -67,8 +67,8 @@ TEST(LayerStateTest, ParcellingLayerCaptureArgs) { args.frameScaleX = 2; args.frameScaleY = 4; args.captureSecureLayers = true; - args.layerHandle = new BBinder(); - args.excludeHandles = {new BBinder(), new BBinder()}; + args.layerHandle = sp<BBinder>::make(); + args.excludeHandles = {sp<BBinder>::make(), sp<BBinder>::make()}; args.childrenOnly = false; args.grayscale = true; @@ -90,13 +90,12 @@ TEST(LayerStateTest, ParcellingLayerCaptureArgs) { ASSERT_EQ(args.grayscale, args2.grayscale); } -TEST(LayerStateTest, ParcellingScreenCaptureResults) { +TEST(LayerStateTest, ParcellingScreenCaptureResultsWithFence) { ScreenCaptureResults results; - results.buffer = new GraphicBuffer(100, 200, PIXEL_FORMAT_RGBA_8888, 1, 0); - results.fence = new Fence(dup(fileno(tmpfile()))); + results.buffer = sp<GraphicBuffer>::make(100u, 200u, PIXEL_FORMAT_RGBA_8888, 1u, 0u); + results.fenceResult = sp<Fence>::make(dup(fileno(tmpfile()))); results.capturedSecureLayers = true; results.capturedDataspace = ui::Dataspace::DISPLAY_P3; - results.result = BAD_VALUE; Parcel p; results.writeToParcel(&p); @@ -110,10 +109,41 @@ TEST(LayerStateTest, ParcellingScreenCaptureResults) { ASSERT_EQ(results.buffer->getWidth(), results2.buffer->getWidth()); ASSERT_EQ(results.buffer->getHeight(), results2.buffer->getHeight()); ASSERT_EQ(results.buffer->getPixelFormat(), results2.buffer->getPixelFormat()); - ASSERT_EQ(results.fence->isValid(), results2.fence->isValid()); + ASSERT_TRUE(results.fenceResult.ok()); + ASSERT_TRUE(results2.fenceResult.ok()); + ASSERT_EQ(results.fenceResult.value()->isValid(), results2.fenceResult.value()->isValid()); ASSERT_EQ(results.capturedSecureLayers, results2.capturedSecureLayers); ASSERT_EQ(results.capturedDataspace, results2.capturedDataspace); - ASSERT_EQ(results.result, results2.result); +} + +TEST(LayerStateTest, ParcellingScreenCaptureResultsWithNoFenceOrError) { + ScreenCaptureResults results; + + Parcel p; + results.writeToParcel(&p); + p.setDataPosition(0); + + ScreenCaptureResults results2; + results2.readFromParcel(&p); + + ASSERT_TRUE(results2.fenceResult.ok()); + ASSERT_EQ(results2.fenceResult.value(), Fence::NO_FENCE); +} + +TEST(LayerStateTest, ParcellingScreenCaptureResultsWithFenceError) { + ScreenCaptureResults results; + results.fenceResult = base::unexpected(BAD_VALUE); + + Parcel p; + results.writeToParcel(&p); + p.setDataPosition(0); + + ScreenCaptureResults results2; + results2.readFromParcel(&p); + + ASSERT_FALSE(results.fenceResult.ok()); + ASSERT_FALSE(results2.fenceResult.ok()); + ASSERT_EQ(results.fenceResult.error(), results2.fenceResult.error()); } } // namespace test diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 6bd7920a62..774c1d7b98 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -23,9 +23,11 @@ #include <cutils/properties.h> #include <gtest/gtest.h> +#include <gui/AidlStatusUtil.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <ui/DisplayMode.h> #include "BufferGenerator.h" @@ -39,13 +41,14 @@ using android::hardware::graphics::common::V1_1::BufferUsage; class LayerTransactionTest : public ::testing::Test { protected: void SetUp() override { - mClient = new SurfaceComposerClient; + mClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient"; ASSERT_NO_FATAL_FAILURE(SetUpDisplay()); - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed)); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); + binder::Status status = sf->getColorManagement(&mColorManagementUsed); + ASSERT_NO_FATAL_FAILURE(gui::aidl_utils::statusTFromBinderStatus(status)); mCaptureArgs.displayToken = mDisplay; } @@ -134,13 +137,16 @@ protected: postBufferQueueLayerBuffer(layer); } - virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color, - int32_t bufferWidth, int32_t bufferHeight) { + virtual void fillBufferLayerColor(const sp<SurfaceControl>& layer, const Color& color, + int32_t bufferWidth, int32_t bufferHeight) { sp<GraphicBuffer> buffer = - new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE, - "test"); + sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth), + static_cast<uint32_t>(bufferHeight), PIXEL_FORMAT_RGBA_8888, + 1u, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY | + BufferUsage::GPU_TEXTURE, + "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color); Transaction().setBuffer(layer, buffer).apply(); @@ -153,7 +159,7 @@ protected: fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight); break; case ISurfaceComposerClient::eFXSurfaceBufferState: - fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight); + fillBufferLayerColor(layer, color, bufferWidth, bufferHeight); break; default: ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType; @@ -206,10 +212,13 @@ protected: const Color& topRight, const Color& bottomLeft, const Color& bottomRight) { sp<GraphicBuffer> buffer = - new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE, - "test"); + sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth), + static_cast<uint32_t>(bufferHeight), PIXEL_FORMAT_RGBA_8888, + 1u, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY | + BufferUsage::GPU_TEXTURE, + "test"); ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0); @@ -224,7 +233,7 @@ protected: Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight); - Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply(); + Transaction().setBuffer(layer, buffer).apply(); } std::unique_ptr<ScreenCapture> screenshot() { diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp index ef992d6a40..cbd54e7aa9 100644 --- a/services/surfaceflinger/tests/LayerTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp @@ -32,7 +32,7 @@ TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) { Transaction().setTransformToDisplayInverse(layer, false).apply(); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::GREEN, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::GREEN, 32, 32)); Transaction().setTransformToDisplayInverse(layer, true).apply(); } @@ -80,7 +80,7 @@ TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDropp sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height)); const auto producer = layer->getIGraphicBufferProducer(); - const sp<IProducerListener> stubListener(new StubProducerListener); + const sp<IProducerListener> stubListener(sp<StubProducerListener>::make()); IGraphicBufferProducer::QueueBufferOutput queueBufferOutput; ASSERT_EQ(OK, producer->connect(stubListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput)); @@ -154,6 +154,36 @@ TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDropp ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU)); } + +// b/245052266 - we possible could support blur and a buffer at the same layer but +// might break existing assumptions at higher level. This test captures the current +// expectations. A layer drawing a buffer will not support blur. +TEST_F(LayerTransactionTest, BufferTakesPriorityOverBlur) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); + Transaction().setBackgroundBlurRadius(layer, 5).apply(); + { + SCOPED_TRACE("BufferTakesPriorityOverBlur"); + const Rect rect(0, 0, 32, 32); + auto shot = screenshot(); + shot->expectColor(rect, Color::RED); + } +} + +TEST_F(LayerTransactionTest, BufferTakesPriorityOverColor) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); + Transaction().setColor(layer, {Color::GREEN.r, Color::GREEN.g, Color::GREEN.b}).apply(); + { + SCOPED_TRACE("BufferTakesPriorityOverColor"); + const Rect rect(0, 0, 32, 32); + auto shot = screenshot(); + shot->expectColor(rect, Color::RED); + } +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index 9cb617a980..f247c9f088 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -799,7 +799,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBufferFormat) { sp<Surface> surface = layer->getSurface(); sp<GraphicBuffer> buffer = - new GraphicBuffer(width, height, PIXEL_FORMAT_RGBX_8888, 1, kUsageFlags, "test"); + sp<GraphicBuffer>::make(width, height, PIXEL_FORMAT_RGBX_8888, 1, kUsageFlags, "test"); ASSERT_NO_FATAL_FAILURE( TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT)); @@ -815,7 +815,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBufferFormat) { shot->expectColor(crop, Color::BLACK); } - buffer = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); + buffer = sp<GraphicBuffer>::make(width, height, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test"); ASSERT_NO_FATAL_FAILURE( TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT)); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index a921aa810e..faaef5d5ec 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -193,14 +193,14 @@ TEST_F(MirrorLayerTest, MirrorBufferLayer) { shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN); } - sp<SurfaceControl> bufferStateLayer = - createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState, + sp<SurfaceControl> layer = + createLayer("Layer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState, mChildLayer.get()); - fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200); - Transaction().show(bufferStateLayer).apply(); + fillBufferLayerColor(layer, Color::BLUE, 200, 200); + Transaction().show(layer).apply(); { - SCOPED_TRACE("Initial Mirror BufferStateLayer"); + SCOPED_TRACE("Initial Mirror Layer"); auto shot = screenshot(); // Buffer mirror shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE); @@ -208,9 +208,9 @@ TEST_F(MirrorLayerTest, MirrorBufferLayer) { shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN); } - fillBufferStateLayerColor(bufferStateLayer, Color::WHITE, 200, 200); + fillBufferLayerColor(layer, Color::WHITE, 200, 200); { - SCOPED_TRACE("Update BufferStateLayer"); + SCOPED_TRACE("Update Layer"); auto shot = screenshot(); // Buffer mirror shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE); @@ -218,9 +218,9 @@ TEST_F(MirrorLayerTest, MirrorBufferLayer) { shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN); } - Transaction().reparent(bufferStateLayer, nullptr).apply(); + Transaction().reparent(layer, nullptr).apply(); { - SCOPED_TRACE("Removed BufferStateLayer"); + SCOPED_TRACE("Removed Layer"); auto shot = screenshot(); // Buffer mirror shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN); @@ -283,7 +283,7 @@ TEST_F(MirrorLayerTest, OffscreenMirrorScreenshot) { sp<SurfaceControl> grandchild = createLayer("Grandchild layer", 50, 50, ISurfaceComposerClient::eFXSurfaceBufferState, mChildLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(grandchild, Color::BLUE, 50, 50)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(grandchild, Color::BLUE, 50, 50)); Rect childBounds = Rect(50, 50, 450, 450); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp index a6d7f5834f..16076eaac9 100644 --- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -110,10 +110,10 @@ public: } static sp<GraphicBuffer> getBuffer() { - return new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY, - "test"); + return sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); } static uint64_t generateFrameNumber() { static uint64_t sFrameNumber = 0; @@ -332,8 +332,10 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { } TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) { - sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener(); - sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener(); + sp<TransactionCompletedListener> firstCompletedListener = + sp<TransactionCompletedListener>::make(); + sp<TransactionCompletedListener> secondCompletedListener = + sp<TransactionCompletedListener>::make(); CallbackHelper callback1, callback2; @@ -433,8 +435,10 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) } TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) { - sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener(); - sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener(); + sp<TransactionCompletedListener> firstCompletedListener = + sp<TransactionCompletedListener>::make(); + sp<TransactionCompletedListener> secondCompletedListener = + sp<TransactionCompletedListener>::make(); TransactionCompletedListener::setInstance(firstCompletedListener); diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 6a7d8b8ca5..3a5e5328e2 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -371,7 +371,7 @@ TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) { ScreenCaptureResults captureResults; ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(args, captureResults)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(child, Color::RED, 32, 32)); SurfaceComposerClient::Transaction().apply(true); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults)); ScreenCapture sc(captureResults.buffer, captureResults.capturedHdrLayers); @@ -449,8 +449,8 @@ TEST_F(ScreenCaptureTest, CaptureCrop) { ISurfaceComposerClient::eFXSurfaceBufferState, redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(blueLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(blueLayer, Color::BLUE, 30, 30)); SurfaceComposerClient::Transaction() .setLayer(redLayer, INT32_MAX - 1) @@ -484,8 +484,8 @@ TEST_F(ScreenCaptureTest, CaptureSize) { ISurfaceComposerClient::eFXSurfaceBufferState, redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(blueLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(blueLayer, Color::BLUE, 30, 30)); SurfaceComposerClient::Transaction() .setLayer(redLayer, INT32_MAX - 1) @@ -519,7 +519,7 @@ TEST_F(ScreenCaptureTest, CaptureSize) { TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { LayerCaptureArgs args; - args.layerHandle = new BBinder(); + args.layerHandle = sp<BBinder>::make(); ScreenCaptureResults captureResults; // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND @@ -549,8 +549,8 @@ TEST_F(ScreenCaptureTest, CaptureSecureLayer) { ISurfaceComposerClient::eSecure | ISurfaceComposerClient::eFXSurfaceBufferState, redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(secureLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(secureLayer, Color::BLUE, 30, 30)); auto redLayerHandle = redLayer->getHandle(); Transaction() @@ -803,7 +803,7 @@ TEST_F(ScreenCaptureTest, CaptureWithGrayscale) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState, mBGSurfaceControl.get())); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); Transaction().show(layer).setLayer(layer, INT32_MAX).apply(); LayerCaptureArgs captureArgs; @@ -825,7 +825,7 @@ TEST_F(ScreenCaptureTest, CaptureWithGrayscale) { mCapture->expectColor(Rect(0, 0, 32, 32), Color{expectedColor, expectedColor, expectedColor, 255}, tolerance); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::BLUE, 32, 32)); ScreenCapture::captureLayers(&mCapture, captureArgs); expectedColor = luminance.b * 255; @@ -838,7 +838,7 @@ TEST_F(ScreenCaptureTest, CaptureOffscreen) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState, mBGSurfaceControl.get())); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::RED, 32, 32)); Transaction().show(layer).hide(mFGSurfaceControl).reparent(layer, nullptr).apply(); @@ -865,7 +865,7 @@ TEST_F(ScreenCaptureTest, CaptureNonHdrLayer) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState, mBGSurfaceControl.get())); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLACK, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::BLACK, 32, 32)); Transaction() .show(layer) .setLayer(layer, INT32_MAX) @@ -885,7 +885,7 @@ TEST_F(ScreenCaptureTest, CaptureHdrLayer) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState, mBGSurfaceControl.get())); - ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLACK, 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillBufferLayerColor(layer, Color::BLACK, 32, 32)); Transaction() .show(layer) .setLayer(layer, INT32_MAX) diff --git a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp index 4efec7738a..e43ef952d6 100644 --- a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp +++ b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ +#include <android/gui/ISurfaceComposer.h> #include <gtest/gtest.h> #include <gui/DisplayEventReceiver.h> -#include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <sys/epoll.h> #include <algorithm> @@ -24,12 +24,14 @@ namespace android { namespace { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; +using gui::ISurfaceComposer; class SetFrameRateOverrideTest : public ::testing::Test { protected: void SetUp() override { - const ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp; - const ISurfaceComposer::EventRegistrationFlags eventRegistration = { + const ISurfaceComposer::VsyncSource vsyncSource = + ISurfaceComposer::VsyncSource::eVsyncSourceApp; + const EventRegistrationFlags eventRegistration = { ISurfaceComposer::EventRegistration::frameRateOverride}; mDisplayEventReceiver = diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp index e9b6ba0f64..03201f7937 100644 --- a/services/surfaceflinger/tests/Stress_test.cpp +++ b/services/surfaceflinger/tests/Stress_test.cpp @@ -32,7 +32,7 @@ namespace android { TEST(SurfaceFlingerStress, create_and_destroy) { auto do_stress = []() { - sp<SurfaceComposerClient> client = new SurfaceComposerClient; + sp<SurfaceComposerClient> client = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, client->initCheck()); for (int j = 0; j < 1000; j++) { auto surf = client->createSurface(String8("t"), 100, 100, diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 28e8b8c78b..d79e59211b 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -138,8 +138,9 @@ protected: // Allow SurfaceInterceptor write to /data system("setenforce 0"); - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + GTEST_SKIP(); } void TearDown() override { @@ -342,9 +343,7 @@ void SurfaceInterceptorTest::positionUpdate(Transaction& t) { t.setPosition(mBGSurfaceControl, POSITION_UPDATE, POSITION_UPDATE); } -void SurfaceInterceptorTest::sizeUpdate(Transaction& t) { - t.setSize(mBGSurfaceControl, SIZE_UPDATE, SIZE_UPDATE); -} +void SurfaceInterceptorTest::sizeUpdate(Transaction&) {} void SurfaceInterceptorTest::alphaUpdate(Transaction& t) { t.setAlpha(mBGSurfaceControl, ALPHA_UPDATE); @@ -472,15 +471,8 @@ bool SurfaceInterceptorTest::positionUpdateFound(const SurfaceChange& change, bo return foundPosition; } -bool SurfaceInterceptorTest::sizeUpdateFound(const SurfaceChange& change, bool foundSize) { - bool hasWidth(change.size().h() == SIZE_UPDATE); - bool hasHeight(change.size().w() == SIZE_UPDATE); - if (hasWidth && hasHeight && !foundSize) { - foundSize = true; - } else if (hasWidth && hasHeight && foundSize) { - [] () { FAIL(); }(); - } - return foundSize; +bool SurfaceInterceptorTest::sizeUpdateFound(const SurfaceChange&, bool) { + return true; } bool SurfaceInterceptorTest::alphaUpdateFound(const SurfaceChange& change, bool foundAlpha) { diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index 8ce63bc64c..ad03ed3073 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -53,11 +53,11 @@ public: consumer->setConsumerName(String8("Virtual disp consumer")); consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); - itemConsumer = new BufferItemConsumer(consumer, - // Sample usage bits from screenrecord - GRALLOC_USAGE_HW_VIDEO_ENCODER | - GRALLOC_USAGE_SW_READ_OFTEN); - sp<BufferListener> listener = new BufferListener(this); + itemConsumer = sp<BufferItemConsumer>::make(consumer, + // Sample usage bits from screenrecord + GRALLOC_USAGE_HW_VIDEO_ENCODER | + GRALLOC_USAGE_SW_READ_OFTEN); + sp<BufferListener> listener = sp<BufferListener>::make(this); itemConsumer->setFrameAvailableListener(listener); vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp index 18e08062c0..f31f582ffd 100644 --- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp +++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp @@ -33,7 +33,7 @@ protected: consumer->setConsumerName(String8("Virtual disp consumer")); consumer->setDefaultBufferSize(100, 100); - mGLConsumer = new GLConsumer(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false); + mGLConsumer = sp<GLConsumer>::make(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false); } sp<IGraphicBufferProducer> mProducer; @@ -55,7 +55,7 @@ TEST_F(VirtualDisplayTest, VirtualDisplayDestroyedSurfaceReuse) { // add another sync since we are deferring the display destruction t.apply(true); - sp<Surface> surface = new Surface(mProducer); + sp<Surface> surface = sp<Surface>::make(mProducer); sp<ANativeWindow> window(surface); ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_EGL)); diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index bb522451a6..53c3c3998f 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -29,8 +29,8 @@ class WindowInfosListenerTest : public ::testing::Test { protected: void SetUp() override { seteuid(AID_SYSTEM); - mClient = new SurfaceComposerClient; - mWindowInfosListener = new SyncWindowInfosListener(); + mClient = sp<SurfaceComposerClient>::make(); + mWindowInfosListener = sp<SyncWindowInfosListener>::make(); mClient->addWindowInfosListener(mWindowInfosListener); } @@ -77,7 +77,7 @@ std::optional<WindowInfo> findMatchingWindowInfo(WindowInfo targetWindowInfo, TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { std::string name = "Test Layer"; - sp<IBinder> token = new BBinder(); + sp<IBinder> token = sp<BBinder>::make(); WindowInfo windowInfo; windowInfo.name = name; windowInfo.token = token; @@ -105,7 +105,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { TEST_F(WindowInfosListenerTest, WindowInfoChanged) { std::string name = "Test Layer"; - sp<IBinder> token = new BBinder(); + sp<IBinder> token = sp<BBinder>::make(); WindowInfo windowInfo; windowInfo.name = name; windowInfo.token = token; diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp index 704815de3a..06afdb10cc 100644 --- a/services/surfaceflinger/tests/fakehwc/Android.bp +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -9,7 +9,10 @@ package { cc_test { name: "sffakehwc_test", - defaults: ["surfaceflinger_defaults"], + defaults: [ + "android.hardware.graphics.composer3-ndk_shared", + "surfaceflinger_defaults", + ], test_suites: ["device-tests"], srcs: [ "FakeComposerClient.cpp", @@ -23,7 +26,6 @@ cc_test { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.graphics.composer3-V1-ndk", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", "android.hardware.graphics.mapper@4.0", diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp index b38032d265..a5cca3597c 100644 --- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp @@ -86,7 +86,9 @@ public: class DelayedEventGenerator { public: explicit DelayedEventGenerator(std::function<void()> onTimerExpired) - : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {} + : mOnTimerExpired(onTimerExpired) { + mThread = std::thread([this]() { loop(); }); + } ~DelayedEventGenerator() { ALOGI("DelayedEventGenerator exiting."); @@ -894,7 +896,7 @@ void FakeComposerClient::clearFrames() { void FakeComposerClient::onSurfaceFlingerStart() { mSurfaceComposer = nullptr; do { - mSurfaceComposer = new android::SurfaceComposerClient; + mSurfaceComposer = android::sp<android::SurfaceComposerClient>::make(); android::status_t initResult = mSurfaceComposer->initCheck(); if (initResult != android::NO_ERROR) { ALOGD("Init result: %d", initResult); diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index b3b4ec15cd..1d3401aa0f 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -29,6 +29,7 @@ #include "MockComposerHal.h" #include <binder/Parcel.h> +#include <gui/AidlStatusUtil.h> #include <gui/DisplayEventReceiver.h> #include <gui/ISurfaceComposer.h> #include <gui/LayerDebugInfo.h> @@ -43,6 +44,7 @@ #include <hwbinder/ProcessState.h> #include <log/log.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <ui/DisplayMode.h> #include <ui/DynamicDisplayInfo.h> #include <utils/Looper.h> @@ -218,8 +220,8 @@ protected: mFakeComposerClient = new FakeComposerClient(); mFakeComposerClient->setMockHal(mMockComposer.get()); - sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(mFakeComposerClient); - mFakeService = new FakeComposerService(client); + auto client = sp<V2_4::hal::ComposerClient>::make(mFakeComposerClient); + mFakeService = sp<FakeComposerService>::make(client); ASSERT_EQ(android::OK, mFakeService->registerAsService("mock")); android::hardware::ProcessState::self()->startThreadPool(); @@ -240,12 +242,13 @@ protected: // Fake composer wants to enable VSync injection mFakeComposerClient->onSurfaceFlingerStart(); - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - mReceiver.reset(new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp, - ISurfaceComposer::EventRegistration::modeChanged)); - mLooper = new Looper(false); + mReceiver.reset( + new DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + gui::ISurfaceComposer::EventRegistration::modeChanged)); + mLooper = sp<Looper>::make(false); mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this); } @@ -992,7 +995,7 @@ using DisplayTest_2_1 = DisplayTest<FakeComposerService_2_1>; // Tests that VSYNC injection can be safely toggled while invalidating. TEST_F(DisplayTest_2_1, VsyncInjection) { - const auto flinger = ComposerService::getComposerService(); + const auto flinger = ComposerServiceAIDL::getComposerService(); bool enable = true; for (int i = 0; i < 100; i++) { @@ -1140,8 +1143,8 @@ protected: // TODO: See TODO comment at DisplayTest::SetUp for background on // the lifetime of the FakeComposerClient. sFakeComposer = new FakeComposerClient; - sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(sFakeComposer); - sp<V2_1::IComposer> fakeService = new FakeComposerService(client); + auto client = sp<V2_4::hal::ComposerClient>::make(sFakeComposer); + sp<V2_1::IComposer> fakeService = sp<FakeComposerService>::make(client); (void)fakeService->registerAsService("mock"); android::hardware::ProcessState::self()->startThreadPool(); @@ -1164,7 +1167,7 @@ protected: void SetUp() override { ALOGI("TransactionTest::SetUp"); - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); ALOGI("TransactionTest::SetUp - display"); @@ -1238,9 +1241,10 @@ protected: sFakeComposer->clearFrames(); ASSERT_EQ(0, sFakeComposer->getFrameCount()); - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - std::vector<LayerDebugInfo> layers; - status_t result = sf->getLayerDebugInfo(&layers); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); + std::vector<gui::LayerDebugInfo> layers; + binder::Status status = sf->getLayerDebugInfo(&layers); + status_t result = gui::aidl_utils::statusTFromBinderStatus(status); if (result != NO_ERROR) { ALOGE("Failed to get layers %s %d", strerror(-result), result); } else { diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp index ac4354cde1..0e214af706 100644 --- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp +++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp @@ -83,6 +83,37 @@ protected: std::vector<std::filesystem::path> TransactionTraceTestSuite::sTransactionTraces{}; +struct LayerInfo { + int id; + std::string name; + int parent; + int z; + uint64_t curr_frame; + float x; + float y; +}; + +bool operator==(const LayerInfo& lh, const LayerInfo& rh) { + return std::make_tuple(lh.id, lh.name, lh.parent, lh.z, lh.curr_frame) == + std::make_tuple(rh.id, rh.name, rh.parent, rh.z, rh.curr_frame); +} + +bool compareById(const LayerInfo& a, const LayerInfo& b) { + return a.id < b.id; +} + +inline void PrintTo(const LayerInfo& info, ::std::ostream* os) { + *os << "Layer [" << info.id << "] name=" << info.name << " parent=" << info.parent + << " z=" << info.z << " curr_frame=" << info.curr_frame << " x=" << info.x + << " y=" << info.y; +} + +struct find_id : std::unary_function<LayerInfo, bool> { + int id; + find_id(int id) : id(id) {} + bool operator()(LayerInfo const& m) const { return m.id == id; } +}; + TEST_P(TransactionTraceTestSuite, validateEndState) { ASSERT_GT(mActualLayersTraceProto.entry_size(), 0); ASSERT_GT(mExpectedLayersTraceProto.entry_size(), 0); @@ -92,19 +123,64 @@ TEST_P(TransactionTraceTestSuite, validateEndState) { auto actualLastEntry = mActualLayersTraceProto.entry(mActualLayersTraceProto.entry_size() - 1); EXPECT_EQ(expectedLastEntry.layers().layers_size(), actualLastEntry.layers().layers_size()); - for (int i = 0; - i < expectedLastEntry.layers().layers_size() && i < actualLastEntry.layers().layers_size(); - i++) { - auto expectedLayer = expectedLastEntry.layers().layers(i); - auto actualLayer = actualLastEntry.layers().layers(i); - EXPECT_EQ(expectedLayer.id(), actualLayer.id()); - EXPECT_EQ(expectedLayer.name(), actualLayer.name()); - EXPECT_EQ(expectedLayer.parent(), actualLayer.parent()); - EXPECT_EQ(expectedLayer.z(), actualLayer.z()); - EXPECT_EQ(expectedLayer.curr_frame(), actualLayer.curr_frame()); - ALOGV("Validating %s[%d] parent=%d z=%d frame=%" PRIu64, expectedLayer.name().c_str(), - expectedLayer.id(), expectedLayer.parent(), expectedLayer.z(), - expectedLayer.curr_frame()); + + std::vector<LayerInfo> expectedLayers; + expectedLayers.reserve(static_cast<size_t>(expectedLastEntry.layers().layers_size())); + for (int i = 0; i < expectedLastEntry.layers().layers_size(); i++) { + auto layer = expectedLastEntry.layers().layers(i); + expectedLayers.push_back({layer.id(), layer.name(), layer.parent(), layer.z(), + layer.curr_frame(), + layer.has_position() ? layer.position().x() : -1, + layer.has_position() ? layer.position().y() : -1}); + } + std::sort(expectedLayers.begin(), expectedLayers.end(), compareById); + + std::vector<LayerInfo> actualLayers; + actualLayers.reserve(static_cast<size_t>(actualLastEntry.layers().layers_size())); + for (int i = 0; i < actualLastEntry.layers().layers_size(); i++) { + auto layer = actualLastEntry.layers().layers(i); + actualLayers.push_back({layer.id(), layer.name(), layer.parent(), layer.z(), + layer.curr_frame(), + layer.has_position() ? layer.position().x() : -1, + layer.has_position() ? layer.position().y() : -1}); + } + std::sort(actualLayers.begin(), actualLayers.end(), compareById); + + size_t i = 0; + for (; i < actualLayers.size() && i < expectedLayers.size(); i++) { + auto it = std::find_if(actualLayers.begin(), actualLayers.end(), + find_id(expectedLayers[i].id)); + EXPECT_NE(it, actualLayers.end()); + EXPECT_EQ(expectedLayers[i], *it); + ALOGV("Validating %s[%d] parent=%d z=%d frame=%" PRIu64, expectedLayers[i].name.c_str(), + expectedLayers[i].id, expectedLayers[i].parent, expectedLayers[i].z, + expectedLayers[i].curr_frame); + } + + EXPECT_EQ(expectedLayers.size(), actualLayers.size()); + + if (i < actualLayers.size()) { + for (size_t j = 0; j < actualLayers.size(); j++) { + if (std::find_if(expectedLayers.begin(), expectedLayers.end(), + find_id(actualLayers[j].id)) == expectedLayers.end()) { + ALOGD("actualLayers [%d]:%s parent=%d z=%d frame=%" PRIu64, actualLayers[j].id, + actualLayers[j].name.c_str(), actualLayers[j].parent, actualLayers[j].z, + actualLayers[j].curr_frame); + } + } + FAIL(); + } + + if (i < expectedLayers.size()) { + for (size_t j = 0; j < expectedLayers.size(); j++) { + if (std::find_if(actualLayers.begin(), actualLayers.end(), + find_id(expectedLayers[j].id)) == actualLayers.end()) { + ALOGD("expectedLayers [%d]:%s parent=%d z=%d frame=%" PRIu64, expectedLayers[j].id, + expectedLayers[j].name.c_str(), expectedLayers[j].parent, expectedLayers[j].z, + expectedLayers[j].curr_frame); + } + } + FAIL(); } } diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope Binary files differnew file mode 100644 index 0000000000..16a91ee6ee --- /dev/null +++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope Binary files differnew file mode 100644 index 0000000000..cd62ab8ce0 --- /dev/null +++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp index 53de4a6e56..513f77989b 100644 --- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp +++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp @@ -50,20 +50,15 @@ protected: sp<NiceMock<MockIPower>> mMockHal = nullptr; sp<NiceMock<MockIPowerHintSession>> mMockSession = nullptr; void verifyAndClearExpectations(); - void sendActualWorkDurationGroup(std::vector<WorkDuration> durations, - std::chrono::nanoseconds sleepBeforeLastSend); - std::chrono::nanoseconds mAllowedDeviation; - std::chrono::nanoseconds mStaleTimeout; + void sendActualWorkDurationGroup(std::vector<WorkDuration> durations); + static constexpr std::chrono::duration kStaleTimeout = 100ms; }; void AidlPowerHalWrapperTest::SetUp() { - mMockHal = new NiceMock<MockIPower>(); - mMockSession = new NiceMock<MockIPowerHintSession>(); + mMockHal = sp<NiceMock<MockIPower>>::make(); + mMockSession = sp<NiceMock<MockIPowerHintSession>>::make(); ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok())); mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal); - mWrapper->setAllowedActualDeviation(std::chrono::nanoseconds{10ms}.count()); - mAllowedDeviation = std::chrono::nanoseconds{mWrapper->mAllowedActualDeviation}; - mStaleTimeout = AidlPowerHalWrapper::kStaleTimeout; } void AidlPowerHalWrapperTest::verifyAndClearExpectations() { @@ -71,14 +66,11 @@ void AidlPowerHalWrapperTest::verifyAndClearExpectations() { Mock::VerifyAndClearExpectations(mMockSession.get()); } -void AidlPowerHalWrapperTest::sendActualWorkDurationGroup( - std::vector<WorkDuration> durations, std::chrono::nanoseconds sleepBeforeLastSend) { +void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(std::vector<WorkDuration> durations) { for (size_t i = 0; i < durations.size(); i++) { - if (i == durations.size() - 1) { - std::this_thread::sleep_for(sleepBeforeLastSend); - } auto duration = durations[i]; - mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos); + mWrapper->sendActualWorkDuration(Duration::fromNs(duration.durationNanos), + TimePoint::fromNs(duration.timeStampNanos)); } } @@ -164,13 +156,13 @@ TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration) { for (const auto& test : testCases) { // reset to 100ms baseline - mWrapper->setTargetWorkDuration(1); - mWrapper->setTargetWorkDuration(base.count()); + mWrapper->setTargetWorkDuration(1ns); + mWrapper->setTargetWorkDuration(base); - auto target = test.first; + std::chrono::nanoseconds target = test.first; EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(target.count())) .Times(test.second ? 1 : 0); - mWrapper->setTargetWorkDuration(target.count()); + mWrapper->setTargetWorkDuration(target); verifyAndClearExpectations(); } } @@ -187,7 +179,7 @@ TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration_shouldReconnectOnError) { EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1)) .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE))); - mWrapper->setTargetWorkDuration(1); + mWrapper->setTargetWorkDuration(1ns); EXPECT_TRUE(mWrapper->shouldReconnectHAL()); } @@ -206,58 +198,24 @@ TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration) { // 100ms const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>> testCases = {{{{-1ms, 100}}, false}, - {{{100ms - (mAllowedDeviation / 2), 100}}, false}, - {{{100ms + (mAllowedDeviation / 2), 100}}, false}, - {{{100ms + (mAllowedDeviation + 1ms), 100}}, true}, - {{{100ms - (mAllowedDeviation + 1ms), 100}}, true}, + {{{50ms, 100}}, true}, {{{100ms, 100}, {200ms, 200}}, true}, {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}}; for (const auto& test : testCases) { // reset actual duration - sendActualWorkDurationGroup({base}, mStaleTimeout); + sendActualWorkDurationGroup({base}); auto raw = test.first; std::vector<WorkDuration> durations(raw.size()); std::transform(raw.begin(), raw.end(), durations.begin(), [](auto d) { return toWorkDuration(d); }); - EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations)) - .Times(test.second ? 1 : 0); - sendActualWorkDurationGroup(durations, 0ms); - verifyAndClearExpectations(); - } -} - -TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) { - ASSERT_TRUE(mWrapper->supportsPowerHintSession()); - - std::vector<int32_t> threadIds = {1, 2}; - mWrapper->setPowerHintSessionThreadIds(threadIds); - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); - ASSERT_TRUE(mWrapper->startPowerHintSession()); - verifyAndClearExpectations(); - - auto base = toWorkDuration(100ms, 0); - // test cases with actual work durations and whether it should update hint against baseline - // 100ms - const std::vector<std::tuple<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, - std::chrono::nanoseconds, bool>> - testCases = {{{{100ms, 100}}, mStaleTimeout, true}, - {{{100ms + (mAllowedDeviation / 2), 100}}, mStaleTimeout, true}, - {{{100ms, 100}}, mStaleTimeout / 2, false}}; - - for (const auto& test : testCases) { - // reset actual duration - sendActualWorkDurationGroup({base}, mStaleTimeout); - - auto raw = std::get<0>(test); - std::vector<WorkDuration> durations(raw.size()); - std::transform(raw.begin(), raw.end(), durations.begin(), - [](auto d) { return toWorkDuration(d); }); - EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations)) - .Times(std::get<2>(test) ? 1 : 0); - sendActualWorkDurationGroup(durations, std::get<1>(test)); + for (auto& duration : durations) { + EXPECT_CALL(*mMockSession.get(), + reportActualWorkDuration(std::vector<WorkDuration>{duration})) + .Times(test.second ? 1 : 0); + } + sendActualWorkDurationGroup(durations); verifyAndClearExpectations(); } } @@ -275,7 +233,7 @@ TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_shouldReconnectOnError) { duration.durationNanos = 1; EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_)) .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE))); - sendActualWorkDurationGroup({duration}, 0ms); + sendActualWorkDurationGroup({duration}); EXPECT_TRUE(mWrapper->shouldReconnectHAL()); } diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 004f31c562..4469df007a 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -109,6 +109,7 @@ cc_test { "SurfaceFlinger_SetDisplayStateTest.cpp", "SurfaceFlinger_SetPowerModeInternalTest.cpp", "SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp", + "SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp", "SchedulerTest.cpp", "SetFrameRateTest.cpp", "RefreshRateConfigsTest.cpp", @@ -135,15 +136,17 @@ cc_test { cc_defaults { name: "libsurfaceflinger_mocks_defaults", + defaults: [ + "android.hardware.graphics.common-ndk_static", + "android.hardware.graphics.composer3-ndk_static", + ], static_libs: [ "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", - "android.hardware.graphics.common-V3-ndk", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.graphics.composer3-V1-ndk", "android.hardware.power@1.0", "android.hardware.power@1.1", "android.hardware.power@1.2", diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp index 6f85498670..c1cbbfb4ef 100644 --- a/services/surfaceflinger/tests/unittests/CachingTest.cpp +++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp @@ -20,21 +20,24 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <gui/BufferQueue.h> -#include "BufferStateLayer.h" + +#include "HwcSlotGenerator.h" namespace android { class SlotGenerationTest : public testing::Test { protected: - sp<BufferStateLayer::HwcSlotGenerator> mHwcSlotGenerator = - sp<BufferStateLayer::HwcSlotGenerator>::make(); - sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - sp<GraphicBuffer> mBuffer3{new GraphicBuffer(10, 10, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + sp<HwcSlotGenerator> mHwcSlotGenerator = sp<HwcSlotGenerator>::make(); + sp<GraphicBuffer> mBuffer1 = + sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u); + sp<GraphicBuffer> mBuffer2 = + sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u); + sp<GraphicBuffer> mBuffer3 = + sp<GraphicBuffer>::make(10u, 10u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u); }; TEST_F(SlotGenerationTest, getHwcCacheSlot_Invalid) { - sp<IBinder> binder = new BBinder(); + sp<IBinder> binder = sp<BBinder>::make(); // test getting invalid client_cache_id client_cache_t id; int slot = mHwcSlotGenerator->getHwcCacheSlot(id); @@ -42,7 +45,7 @@ TEST_F(SlotGenerationTest, getHwcCacheSlot_Invalid) { } TEST_F(SlotGenerationTest, getHwcCacheSlot_Basic) { - sp<IBinder> binder = new BBinder(); + sp<IBinder> binder = sp<BBinder>::make(); client_cache_t id; id.token = binder; id.id = 0; @@ -63,7 +66,7 @@ TEST_F(SlotGenerationTest, getHwcCacheSlot_Basic) { } TEST_F(SlotGenerationTest, getHwcCacheSlot_Reuse) { - sp<IBinder> binder = new BBinder(); + sp<IBinder> binder = sp<BBinder>::make(); std::vector<client_cache_t> ids; uint32_t cacheId = 0; // fill up cache diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index bbfedc7685..7148c117c5 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -37,10 +37,7 @@ #include <system/window.h> #include <utils/String8.h> -#include "BufferQueueLayer.h" -#include "ContainerLayer.h" #include "DisplayRenderArea.h" -#include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -131,13 +128,15 @@ public: EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); @@ -179,11 +178,11 @@ public: sp<DisplayDevice> mDisplay; sp<DisplayDevice> mExternalDisplay; sp<compositionengine::mock::DisplaySurface> mDisplaySurface = - new compositionengine::mock::DisplaySurface(); - mock::NativeWindow* mNativeWindow = new mock::NativeWindow(); + sp<compositionengine::mock::DisplaySurface>::make(); + sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make(); std::vector<sp<Layer>> mAuxiliaryLayers; - sp<GraphicBuffer> mBuffer = new GraphicBuffer(); + sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make(); ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer(); Hwc2::mock::Composer* mComposer = nullptr; @@ -309,16 +308,20 @@ struct BaseDisplayVariant { compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), ceDisplayArgs); + constexpr auto kDisplayConnectionType = ui::DisplayConnectionType::Internal; + constexpr bool kIsPrimary = true; + test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - ui::DisplayConnectionType::Internal, HWC_DISPLAY, - true /* isPrimary */) + kDisplayConnectionType, HWC_DISPLAY, kIsPrimary) .setDisplaySurface(test->mDisplaySurface) .setNativeWindow(test->mNativeWindow) .setSecure(Derived::IS_SECURE) .setPowerMode(Derived::INIT_POWER_MODE) .inject(); - Mock::VerifyAndClear(test->mNativeWindow); - test->mDisplay->setLayerStack(LAYER_STACK); + Mock::VerifyAndClear(test->mNativeWindow.get()); + + constexpr bool kIsInternal = kDisplayConnectionType == ui::DisplayConnectionType::Internal; + test->mDisplay->setLayerFilter({LAYER_STACK, kIsInternal}); } template <typename Case> @@ -351,15 +354,13 @@ struct BaseDisplayVariant { .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings, const std::vector<renderengine::LayerSettings>&, const std::shared_ptr<renderengine::ExternalTexture>&, - const bool, base::unique_fd&&) - -> std::future<renderengine::RenderEngineResult> { + const bool, base::unique_fd&&) -> std::future<FenceResult> { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.clip); - return futureOf<renderengine::RenderEngineResult>( - {NO_ERROR, base::unique_fd()}); + return futureOf<FenceResult>(Fence::NO_FENCE); }); } @@ -404,16 +405,14 @@ struct BaseDisplayVariant { .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings, const std::vector<renderengine::LayerSettings>&, const std::shared_ptr<renderengine::ExternalTexture>&, - const bool, base::unique_fd&&) - -> std::future<renderengine::RenderEngineResult> { + const bool, base::unique_fd&&) -> std::future<FenceResult> { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.clip); EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace); - return futureOf<renderengine::RenderEngineResult>( - {NO_ERROR, base::unique_fd()}); + return futureOf<FenceResult>(Fence::NO_FENCE); }); } @@ -492,65 +491,31 @@ struct BaseLayerProperties { static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::PREMULTIPLIED; - static void enqueueBuffer(CompositionTest*, sp<BufferQueueLayer> layer) { - auto producer = layer->getProducer(); - - IGraphicBufferProducer::QueueBufferOutput qbo; - status_t result = producer->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &qbo); - if (result != NO_ERROR) { - ALOGE("Failed to connect() (%d)", result); - return; - } - - int slot; - sp<Fence> fence; - result = producer->dequeueBuffer(&slot, &fence, LayerProperties::WIDTH, - LayerProperties::HEIGHT, LayerProperties::FORMAT, - LayerProperties::USAGE, nullptr, nullptr); - if (result != IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { - ALOGE("Failed to dequeueBuffer() (%d)", result); - return; - } - - sp<GraphicBuffer> buffer; - result = producer->requestBuffer(slot, &buffer); - if (result != NO_ERROR) { - ALOGE("Failed to requestBuffer() (%d)", result); - return; - } - - IGraphicBufferProducer::QueueBufferInput qbi(systemTime(), false /* isAutoTimestamp */, - LayerProperties::DATASPACE, - Rect(LayerProperties::WIDTH, - LayerProperties::HEIGHT), - LayerProperties::SCALING_MODE, - LayerProperties::TRANSFORM, Fence::NO_FENCE); - result = producer->queueBuffer(slot, qbi, &qbo); - if (result != NO_ERROR) { - ALOGE("Failed to queueBuffer (%d)", result); - return; - } - } - - static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) { - // TODO: Eliminate the complexity of actually creating a buffer - layer->setSizeForTest(LayerProperties::WIDTH, LayerProperties::HEIGHT); - status_t err = - layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT, - LayerProperties::FORMAT); - ASSERT_EQ(NO_ERROR, err); + static void setupLatchedBuffer(CompositionTest* test, sp<Layer> layer) { Mock::VerifyAndClear(test->mRenderEngine); - EXPECT_CALL(*test->mFlinger.scheduler(), scheduleFrame()).Times(1); - enqueueBuffer(test, layer); - Mock::VerifyAndClearExpectations(test->mFlinger.scheduler()); + const auto buffer = std::make_shared< + renderengine::mock::FakeExternalTexture>(LayerProperties::WIDTH, + LayerProperties::HEIGHT, + DEFAULT_TEXTURE_ID, + LayerProperties::FORMAT, + LayerProperties::USAGE | + GraphicBuffer::USAGE_HW_TEXTURE); + + auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); + layerDrawingState.crop = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH); + layerDrawingState.buffer = buffer; + layerDrawingState.acquireFence = Fence::NO_FENCE; + layerDrawingState.dataspace = ui::Dataspace::UNKNOWN; + layer->setSurfaceDamageRegion( + Region(Rect(LayerProperties::HEIGHT, LayerProperties::WIDTH))); bool ignoredRecomputeVisibleRegions; - layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0); + layer->latchBuffer(ignoredRecomputeVisibleRegions, 0); Mock::VerifyAndClear(test->mRenderEngine); } - static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) { + static void setupLayerState(CompositionTest* test, sp<Layer> layer) { setupLatchedBuffer(test, layer); } @@ -640,7 +605,7 @@ struct BaseLayerProperties { .WillOnce([&](const renderengine::DisplaySettings& displaySettings, const std::vector<renderengine::LayerSettings>& layerSettings, const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + base::unique_fd&&) -> std::future<FenceResult> { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -648,9 +613,7 @@ struct BaseLayerProperties { displaySettings.clip); // screen capture adds an additional color layer as an alpha // prefill, so gtet the back layer. - std::future<renderengine::RenderEngineResult> resultFuture = - futureOf<renderengine::RenderEngineResult>( - {NO_ERROR, base::unique_fd()}); + std::future<FenceResult> resultFuture = futureOf<FenceResult>(Fence::NO_FENCE); if (layerSettings.empty()) { ADD_FAILURE() << "layerSettings was not expected to be empty in " "setupREBufferCompositionCommonCallExpectations " @@ -664,7 +627,8 @@ struct BaseLayerProperties { EXPECT_EQ(false, layer.source.buffer.isY410BT2020); EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha); EXPECT_EQ(false, layer.source.buffer.isOpaque); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y); EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); return resultFuture; @@ -692,7 +656,7 @@ struct BaseLayerProperties { .WillOnce([&](const renderengine::DisplaySettings& displaySettings, const std::vector<renderengine::LayerSettings>& layerSettings, const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + base::unique_fd&&) -> std::future<FenceResult> { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -700,9 +664,7 @@ struct BaseLayerProperties { displaySettings.clip); // screen capture adds an additional color layer as an alpha // prefill, so get the back layer. - std::future<renderengine::RenderEngineResult> resultFuture = - futureOf<renderengine::RenderEngineResult>( - {NO_ERROR, base::unique_fd()}); + std::future<FenceResult> resultFuture = futureOf<FenceResult>(Fence::NO_FENCE); if (layerSettings.empty()) { ADD_FAILURE() << "layerSettings was not expected to be empty in " @@ -714,7 +676,8 @@ struct BaseLayerProperties { EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1], LayerProperties::COLOR[2]), layer.source.solidColor); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y); EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); return resultFuture; @@ -736,7 +699,7 @@ struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerPropert using Base = BaseLayerProperties<SidebandLayerProperties>; static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE; - static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) { + static void setupLayerState(CompositionTest* test, sp<Layer> layer) { sp<NativeHandle> stream = NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM), false); @@ -772,7 +735,7 @@ struct CommonSecureLayerProperties : public BaseLayerProperties<LayerProperties> .WillOnce([&](const renderengine::DisplaySettings& displaySettings, const std::vector<renderengine::LayerSettings>& layerSettings, const std::shared_ptr<renderengine::ExternalTexture>&, const bool, - base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> { + base::unique_fd&&) -> std::future<FenceResult> { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -780,9 +743,7 @@ struct CommonSecureLayerProperties : public BaseLayerProperties<LayerProperties> displaySettings.clip); // screen capture adds an additional color layer as an alpha // prefill, so get the back layer. - std::future<renderengine::RenderEngineResult> resultFuture = - futureOf<renderengine::RenderEngineResult>( - {NO_ERROR, base::unique_fd()}); + std::future<FenceResult> resultFuture = futureOf<FenceResult>(Fence::NO_FENCE); if (layerSettings.empty()) { ADD_FAILURE() << "layerSettings was not expected to be empty in " "setupInsecureREBufferCompositionCommonCallExpectations " @@ -792,7 +753,8 @@ struct CommonSecureLayerProperties : public BaseLayerProperties<LayerProperties> const renderengine::LayerSettings layer = layerSettings.back(); EXPECT_THAT(layer.source.buffer.buffer, IsNull()); EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y); EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); EXPECT_EQ(1.0f, layer.alpha); return resultFuture; @@ -818,14 +780,14 @@ struct SecureLayerProperties : public CommonSecureLayerProperties<SecureLayerPro struct CursorLayerProperties : public BaseLayerProperties<CursorLayerProperties> { using Base = BaseLayerProperties<CursorLayerProperties>; - static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) { + static void setupLayerState(CompositionTest* test, sp<Layer> layer) { Base::setupLayerState(test, layer); test->mFlinger.setLayerPotentialCursor(layer, true); } }; struct NoLayerVariant { - using FlingerLayerType = sp<BufferQueueLayer>; + using FlingerLayerType = sp<Layer>; static FlingerLayerType createLayer(CompositionTest*) { return FlingerLayerType(); } static void injectLayer(CompositionTest*, FlingerLayerType) {} @@ -859,8 +821,6 @@ struct BaseLayerVariant { static void initLayerDrawingStateAndComputeBounds(CompositionTest* test, sp<L> layer) { auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); layerDrawingState.layerStack = LAYER_STACK; - layerDrawingState.width = 100; - layerDrawingState.height = 100; layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1], LayerProperties::COLOR[2], LayerProperties::COLOR[3]); layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform(), 0.f /* shadowRadius */); @@ -896,13 +856,13 @@ struct BaseLayerVariant { template <typename LayerProperties> struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> { using Base = BaseLayerVariant<LayerProperties>; - using FlingerLayerType = sp<EffectLayer>; + using FlingerLayerType = sp<Layer>; static FlingerLayerType createLayer(CompositionTest* test) { - FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() { - return new EffectLayer( - LayerCreationArgs(test->mFlinger.flinger(), sp<Client>(), "test-layer", - LayerProperties::LAYER_FLAGS, LayerMetadata())); + FlingerLayerType layer = Base::template createLayerWithFactory<Layer>(test, [test]() { + return sp<Layer>::make(LayerCreationArgs(test->mFlinger.flinger(), sp<Client>(), + "test-layer", LayerProperties::LAYER_FLAGS, + LayerMetadata())); }); auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); @@ -932,17 +892,17 @@ struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> { template <typename LayerProperties> struct BufferLayerVariant : public BaseLayerVariant<LayerProperties> { using Base = BaseLayerVariant<LayerProperties>; - using FlingerLayerType = sp<BufferQueueLayer>; + using FlingerLayerType = sp<Layer>; static FlingerLayerType createLayer(CompositionTest* test) { test->mFlinger.mutableTexturePool().push_back(DEFAULT_TEXTURE_ID); FlingerLayerType layer = - Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() { + Base::template createLayerWithFactory<Layer>(test, [test]() { LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-layer", LayerProperties::LAYER_FLAGS, LayerMetadata()); args.textureName = test->mFlinger.mutableTexturePool().back(); - return new BufferQueueLayer(args); + return sp<Layer>::make(args); }); LayerProperties::setupLayerState(test, layer); @@ -984,12 +944,12 @@ struct BufferLayerVariant : public BaseLayerVariant<LayerProperties> { template <typename LayerProperties> struct ContainerLayerVariant : public BaseLayerVariant<LayerProperties> { using Base = BaseLayerVariant<LayerProperties>; - using FlingerLayerType = sp<ContainerLayer>; + using FlingerLayerType = sp<Layer>; static FlingerLayerType createLayer(CompositionTest* test) { LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-container-layer", LayerProperties::LAYER_FLAGS, LayerMetadata()); - FlingerLayerType layer = new ContainerLayer(args); + FlingerLayerType layer = sp<Layer>::make(args); Base::template initLayerDrawingStateAndComputeBounds(test, layer); return layer; } diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp index 93af225b3e..982b9ff9ea 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -42,6 +42,7 @@ public: PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this); mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); + mFlinger.configureAndCommit(); mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) .setDisplayModes(makeModes(kMode60, kMode90, kMode120), kModeId60) diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index f04221cc21..31262b3623 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -66,13 +66,15 @@ DisplayTransactionTest::~DisplayTransactionTest() { void DisplayTransactionTest::injectMockScheduler() { EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*mEventThread, createEventConnection(_, _)) - .WillOnce(Return( - new EventThreadConnection(mEventThread, /*callingUid=*/0, ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(mEventThread, + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*mSFEventThread, createEventConnection(_, _)) - .WillOnce(Return( - new EventThreadConnection(mSFEventThread, /*callingUid=*/0, ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(mSFEventThread, + mock::EventThread::kCallingUid, + ResyncCallback()))); mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController), std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker), @@ -100,8 +102,8 @@ void DisplayTransactionTest::injectFakeBufferQueueFactory() { // This setup is only expected once per test. ASSERT_TRUE(mConsumer == nullptr && mProducer == nullptr); - mConsumer = new mock::GraphicBufferConsumer(); - mProducer = new mock::GraphicBufferProducer(); + mConsumer = sp<mock::GraphicBufferConsumer>::make(); + mProducer = sp<mock::GraphicBufferProducer>::make(); mFlinger.setCreateBufferQueueFunction([this](auto outProducer, auto outConsumer, bool) { *outProducer = mProducer; @@ -166,7 +168,12 @@ sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay( } bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) const { - return mFlinger.hwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1; + const auto& map = mFlinger.hwcPhysicalDisplayIdMap(); + + const auto it = map.find(hwcDisplayId); + if (it == map.end()) return false; + + return mFlinger.hwcDisplayData().count(it->second) == 1; } bool DisplayTransactionTest::hasTransactionFlagSet(int32_t flag) const { diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index f5235ce953..885d6cdd15 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -111,8 +111,8 @@ public: // Test instances TestableSurfaceFlinger mFlinger; - sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow(); - sp<GraphicBuffer> mBuffer = new GraphicBuffer(); + sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make(); + sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make(); Hwc2::mock::PowerAdvisor mPowerAdvisor; // These mocks are created by the test, but are destroyed by SurfaceFlinger @@ -120,7 +120,7 @@ public: // to keep a reference to them for use in setting up call expectations. renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); Hwc2::mock::Composer* mComposer = nullptr; - sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor; + sp<mock::SurfaceInterceptor> mSurfaceInterceptor = sp<mock::SurfaceInterceptor>::make(); mock::VsyncController* mVsyncController = new mock::VsyncController; mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker; @@ -434,14 +434,18 @@ struct HwcDisplayVariant { } } + template <bool kFailedHotplug = false> static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) { - constexpr auto CONNECTION_TYPE = - PhysicalDisplay::CONNECTION_TYPE == ui::DisplayConnectionType::Internal - ? IComposerClient::DisplayConnectionType::INTERNAL - : IComposerClient::DisplayConnectionType::EXTERNAL; - - EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _)) - .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(hal::V2_4::Error::NONE))); + if constexpr (!kFailedHotplug) { + constexpr auto CONNECTION_TYPE = + PhysicalDisplay::CONNECTION_TYPE == ui::DisplayConnectionType::Internal + ? IComposerClient::DisplayConnectionType::INTERNAL + : IComposerClient::DisplayConnectionType::EXTERNAL; + + EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _)) + .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE), + Return(hal::V2_4::Error::NONE))); + } EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)) .WillOnce(Return(hal::Error::NONE)); diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index c033af8645..978afc510a 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -72,7 +72,7 @@ protected: public: MockEventThreadConnection(impl::EventThread* eventThread, uid_t callingUid, ResyncCallback&& resyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration) + EventRegistrationFlags eventRegistration) : EventThreadConnection(eventThread, callingUid, std::move(resyncCallback), eventRegistration) {} MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event)); @@ -85,10 +85,9 @@ protected: ~EventThreadTest() override; void createThread(std::unique_ptr<VSyncSource>); - sp<MockEventThreadConnection> createConnection( - ConnectionEventRecorder& recorder, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}, - uid_t ownerUid = mConnectionUid); + sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder, + EventRegistrationFlags eventRegistration = {}, + uid_t ownerUid = mConnectionUid); void expectVSyncSetEnabledCallReceived(bool expectedState); void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration, @@ -149,11 +148,12 @@ EventThreadTest::EventThreadTest() { .WillRepeatedly(Invoke(mVSyncSetDurationCallRecorder.getInvocable())); createThread(std::move(vsyncSource)); - mConnection = createConnection(mConnectionEventCallRecorder, - ISurfaceComposer::EventRegistration::modeChanged | - ISurfaceComposer::EventRegistration::frameRateOverride); + mConnection = + createConnection(mConnectionEventCallRecorder, + gui::ISurfaceComposer::EventRegistration::modeChanged | + gui::ISurfaceComposer::EventRegistration::frameRateOverride); mThrottledConnection = createConnection(mThrottledConnectionEventCallRecorder, - ISurfaceComposer::EventRegistration::modeChanged, + gui::ISurfaceComposer::EventRegistration::modeChanged, mThrottledConnectionUid); // A display must be connected for VSYNC events to be delivered. @@ -190,11 +190,12 @@ void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) { } sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection( - ConnectionEventRecorder& recorder, - ISurfaceComposer::EventRegistrationFlags eventRegistration, uid_t ownerUid) { + ConnectionEventRecorder& recorder, EventRegistrationFlags eventRegistration, + uid_t ownerUid) { sp<MockEventThreadConnection> connection = - new MockEventThreadConnection(mThread.get(), ownerUid, - mResyncCallRecorder.getInvocable(), eventRegistration); + sp<MockEventThreadConnection>::make(mThread.get(), ownerUid, + mResyncCallRecorder.getInvocable(), + eventRegistration); EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable())); return connection; } diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index bb1f4328b5..1cd9e49051 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -24,9 +24,6 @@ #include <gtest/gtest.h> #include <gui/LayerMetadata.h> -#include "BufferQueueLayer.h" -#include "BufferStateLayer.h" -#include "EffectLayer.h" #include "FpsReporter.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" @@ -51,6 +48,7 @@ using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using gui::LayerMetadata; struct TestableFpsListener : public gui::BnFpsListener { TestableFpsListener() {} @@ -80,7 +78,7 @@ protected: static constexpr int32_t PRIORITY_UNSET = -1; void setupScheduler(); - sp<BufferStateLayer> createBufferStateLayer(LayerMetadata metadata); + sp<Layer> createBufferStateLayer(LayerMetadata metadata); TestableSurfaceFlinger mFlinger; mock::FrameTimeline mFrameTimeline = @@ -95,8 +93,8 @@ protected: sp<TestableFpsListener> mFpsListener; fake::FakeClock* mClock = new fake::FakeClock(); - sp<FpsReporter> mFpsReporter = - new FpsReporter(mFrameTimeline, *(mFlinger.flinger()), std::unique_ptr<Clock>(mClock)); + sp<FpsReporter> mFpsReporter = sp<FpsReporter>::make(mFrameTimeline, *(mFlinger.flinger()), + std::unique_ptr<Clock>(mClock)); }; FpsReporterTest::FpsReporterTest() { @@ -107,7 +105,7 @@ FpsReporterTest::FpsReporterTest() { setupScheduler(); mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); - mFpsListener = new TestableFpsListener(); + mFpsListener = sp<TestableFpsListener>::make(); } FpsReporterTest::~FpsReporterTest() { @@ -116,10 +114,10 @@ FpsReporterTest::~FpsReporterTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -sp<BufferStateLayer> FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) { +sp<Layer> FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) { sp<Client> client; LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata); - return new BufferStateLayer(args); + return sp<Layer>::make(args); } void FpsReporterTest::setupScheduler() { @@ -128,13 +126,15 @@ void FpsReporterTest::setupScheduler() { EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); @@ -153,7 +153,7 @@ TEST_F(FpsReporterTest, callsListeners) { mParent = createBufferStateLayer(); constexpr int32_t kTaskId = 12; LayerMetadata targetMetadata; - targetMetadata.setInt32(METADATA_TASK_ID, kTaskId); + targetMetadata.setInt32(gui::METADATA_TASK_ID, kTaskId); mTarget = createBufferStateLayer(targetMetadata); mChild = createBufferStateLayer(); mGrandChild = createBufferStateLayer(); @@ -188,7 +188,7 @@ TEST_F(FpsReporterTest, callsListeners) { TEST_F(FpsReporterTest, rateLimits) { const constexpr int32_t kTaskId = 12; LayerMetadata targetMetadata; - targetMetadata.setInt32(METADATA_TASK_ID, kTaskId); + targetMetadata.setInt32(gui::METADATA_TASK_ID, kTaskId); mTarget = createBufferStateLayer(targetMetadata); mFlinger.mutableCurrentState().layersSortedByZ.add(mTarget); diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index f1efa9286d..874fa7c766 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -217,9 +217,12 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); flushTokens(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired); @@ -227,9 +230,12 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid); @@ -239,9 +245,12 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); constexpr int32_t inputEventId = 1; + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = inputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId()); @@ -250,9 +259,12 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); // Set up the display frame @@ -278,14 +290,17 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdTwo, sLayerNameTwo, - sLayerNameTwo, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdTwo, + sLayerNameTwo, sLayerNameTwo, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -324,9 +339,11 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { {10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor}); int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, - sPidOne, sUidOne, sLayerIdOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); @@ -347,10 +364,13 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { {10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor}); int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -442,11 +462,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_invalidSignalTime) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -470,11 +493,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = -1; int64_t sfToken1 = -1; + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -495,11 +521,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -521,11 +550,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -546,11 +578,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setAcquireFenceTime(20); @@ -570,11 +605,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -596,11 +634,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -622,11 +663,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -648,11 +692,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate); @@ -676,11 +723,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -706,11 +756,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); // Trigger a prediction expiry flushTokens(); @@ -744,9 +797,12 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { auto tracingSession = getTracingSessionForTest(); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); // Set up the display frame @@ -771,9 +827,12 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { tracingSession->StartBlocking(); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); // Set up the display frame @@ -1133,14 +1192,18 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 25, 40}); int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({30, 35, 40}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = sInputEventId; + auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setActualQueueTime(10); surfaceFrame1->setDropTime(15); @@ -1293,10 +1356,13 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredIsAppMissedDeadline // Flush the token so that it would expire flushTokens(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = 0; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, - sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setActualQueueTime(appEndTime); surfaceFrame1->setAcquireFenceTime(appEndTime); @@ -1369,10 +1435,13 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced // Flush the token so that it would expire flushTokens(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = 0; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, - sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(22ms).count(); constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count(); @@ -1438,10 +1507,13 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -1608,7 +1680,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) EXPECT_EQ(displayFrame0->getActuals().presentTime, 52); EXPECT_EQ(displayFrame0->getFramePresentMetadata(), FramePresentMetadata::LatePresent); EXPECT_EQ(displayFrame0->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish); - EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed); + EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed); // case 3 - cpu time = 86 - 82 = 4, vsync period = 30 mFrameTimeline->setSfWakeUp(sfToken3, 106, Fps::fromPeriodNsecs(30)); @@ -1654,10 +1726,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1674,10 +1749,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1734,10 +1812,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1754,10 +1835,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1813,10 +1897,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 50, 50}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1857,10 +1944,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 50, 50}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(26); mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1877,10 +1967,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1932,10 +2025,13 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 120, 120}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1952,10 +2048,13 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(84); mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); @@ -2010,10 +2109,13 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -2030,10 +2132,13 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(80); mFrameTimeline->setSfWakeUp(sfToken2, 82, Fps::fromPeriodNsecs(30)); // Setting previous latch time to 54, adjusted deadline will be 54 + vsyncTime(30) = 84 @@ -2079,6 +2184,50 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::BufferStuffing); } +TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent_GpuAndCpuMiss) { + auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40}); + int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + + // Case 1: cpu time = 33 - 12 = 21, vsync period = 11 + mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1); + auto displayFrame = getDisplayFrame(0); + gpuFence1->signalForTest(36); + presentFence1->signalForTest(52); + + // Fences haven't been flushed yet, so it should be 0 + EXPECT_EQ(displayFrame->getActuals().presentTime, 0); + + addEmptyDisplayFrame(); + displayFrame = getDisplayFrame(0); + + // Fences have flushed, so the present timestamps should be updated + EXPECT_EQ(displayFrame->getActuals().presentTime, 52); + EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent); + EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish); + EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed); + + // Case 2: No GPU fence so it will not use GPU composition. + mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfPresent(66, presentFence2); + auto displayFrame2 = getDisplayFrame(2); // 2 because of previous empty frame + presentFence2->signalForTest(90); + + // Fences for the frame haven't been flushed yet, so it should be 0 + EXPECT_EQ(displayFrame2->getActuals().presentTime, 0); + + addEmptyDisplayFrame(); + + // Fences have flushed, so the present timestamps should be updated + EXPECT_EQ(displayFrame2->getActuals().presentTime, 90); + EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent); + EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish); + EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed); +} + TEST_F(FrameTimelineTest, computeFps_noLayerIds_returnsZero) { EXPECT_EQ(mFrameTimeline->computeFps({}), 0.0f); } @@ -2237,4 +2386,38 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { EXPECT_EQ(mFrameTimeline->computeFps({sLayerIdOne}), 5.0f); } +TEST_F(FrameTimelineTest, getMinTime) { + // Use SurfaceFrame::getBaseTime to test the getMinTime. + FrameTimelineInfo ftInfo; + + // Valid prediction state test. + ftInfo.vsyncId = 0L; + mTokenManager->generateTokenForPredictions({10}); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); + ASSERT_EQ(surfaceFrame->getBaseTime(), 10); + + // Test prediction state which is not valid. + ftInfo.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID; + surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); + // Start time test. + surfaceFrame->setActualStartTime(200); + ASSERT_EQ(surfaceFrame->getBaseTime(), 200); + + // End time test. + surfaceFrame->setAcquireFenceTime(100); + ASSERT_EQ(surfaceFrame->getBaseTime(), 100); + + // Present time test. + auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); + mFrameTimeline->addSurfaceFrame(surfaceFrame); + presentFence->signalForTest(std::chrono::nanoseconds(50ns).count()); + mFrameTimeline->setSfPresent(50, presentFence); + ASSERT_EQ(surfaceFrame->getBaseTime(), 50); +} } // namespace android::frametimeline diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp index 981ca1d227..29aa7171ba 100644 --- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp +++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp @@ -34,6 +34,8 @@ using testing::_; using testing::Mock; using testing::Return; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using gui::GameMode; +using gui::LayerMetadata; class GameModeTest : public testing::Test { public: @@ -51,11 +53,10 @@ public: ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } - sp<BufferStateLayer> createBufferStateLayer() { + sp<Layer> createLayer() { sp<Client> client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, - LayerMetadata()); - return new BufferStateLayer(args); + LayerCreationArgs args(mFlinger.flinger(), client, "layer", 0, LayerMetadata()); + return sp<Layer>::make(args); } void setupScheduler() { @@ -64,13 +65,15 @@ public: EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); @@ -92,7 +95,7 @@ public: // Mocks the behavior of applying a transaction from WMShell void setGameModeMetadata(sp<Layer> layer, GameMode gameMode) { - mLayerMetadata.setInt32(METADATA_GAME_MODE, static_cast<int32_t>(gameMode)); + mLayerMetadata.setInt32(gui::METADATA_GAME_MODE, static_cast<int32_t>(gameMode)); layer->setMetadata(mLayerMetadata); layer->setGameModeForTree(gameMode); } @@ -104,9 +107,9 @@ public: }; TEST_F(GameModeTest, SetGameModeSetsForAllCurrentChildren) { - sp<BufferStateLayer> rootLayer = createBufferStateLayer(); - sp<BufferStateLayer> childLayer1 = createBufferStateLayer(); - sp<BufferStateLayer> childLayer2 = createBufferStateLayer(); + sp<Layer> rootLayer = createLayer(); + sp<Layer> childLayer1 = createLayer(); + sp<Layer> childLayer2 = createLayer(); rootLayer->addChild(childLayer1); rootLayer->addChild(childLayer2); rootLayer->setGameModeForTree(GameMode::Performance); @@ -117,8 +120,8 @@ TEST_F(GameModeTest, SetGameModeSetsForAllCurrentChildren) { } TEST_F(GameModeTest, AddChildAppliesGameModeFromParent) { - sp<BufferStateLayer> rootLayer = createBufferStateLayer(); - sp<BufferStateLayer> childLayer = createBufferStateLayer(); + sp<Layer> rootLayer = createLayer(); + sp<Layer> childLayer = createLayer(); rootLayer->setGameModeForTree(GameMode::Performance); rootLayer->addChild(childLayer); @@ -127,8 +130,8 @@ TEST_F(GameModeTest, AddChildAppliesGameModeFromParent) { } TEST_F(GameModeTest, RemoveChildResetsGameMode) { - sp<BufferStateLayer> rootLayer = createBufferStateLayer(); - sp<BufferStateLayer> childLayer = createBufferStateLayer(); + sp<Layer> rootLayer = createLayer(); + sp<Layer> childLayer = createLayer(); rootLayer->setGameModeForTree(GameMode::Performance); rootLayer->addChild(childLayer); @@ -140,9 +143,9 @@ TEST_F(GameModeTest, RemoveChildResetsGameMode) { } TEST_F(GameModeTest, ReparentingDoesNotOverrideMetadata) { - sp<BufferStateLayer> rootLayer = createBufferStateLayer(); - sp<BufferStateLayer> childLayer1 = createBufferStateLayer(); - sp<BufferStateLayer> childLayer2 = createBufferStateLayer(); + sp<Layer> rootLayer = createLayer(); + sp<Layer> childLayer1 = createLayer(); + sp<Layer> childLayer2 = createLayer(); rootLayer->setGameModeForTree(GameMode::Standard); rootLayer->addChild(childLayer1); diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index 5241604cd0..9d8e0a25e6 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -59,27 +59,62 @@ using ::testing::Return; using ::testing::SetArgPointee; using ::testing::StrictMock; -TEST(HWComposerTest, isHeadless) { - Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>(); - impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)}; - ASSERT_TRUE(hwc.isHeadless()); +struct HWComposerTest : testing::Test { + using HalError = hardware::graphics::composer::V2_1::Error; - const hal::HWDisplayId hwcId = 1; + Hwc2::mock::Composer* const mHal = new StrictMock<Hwc2::mock::Composer>(); + impl::HWComposer mHwc{std::unique_ptr<Hwc2::Composer>(mHal)}; - EXPECT_CALL(*mHal, getDisplayIdentificationData(_, _, _)) - .WillOnce(DoAll(SetArgPointee<2>(getExternalEdid()), - Return(hardware::graphics::composer::V2_1::Error::NONE))); + void expectHotplugConnect(hal::HWDisplayId hwcDisplayId) { + constexpr uint8_t kPort = 255; + EXPECT_CALL(*mHal, getDisplayIdentificationData(hwcDisplayId, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(kPort), + SetArgPointee<2>(getExternalEdid()), Return(HalError::NONE))); - EXPECT_CALL(*mHal, setVsyncEnabled(_, _)); - EXPECT_CALL(*mHal, setClientTargetSlotCount(_)); + EXPECT_CALL(*mHal, setClientTargetSlotCount(_)); + EXPECT_CALL(*mHal, setVsyncEnabled(hwcDisplayId, Hwc2::IComposerClient::Vsync::DISABLE)); + } +}; + +TEST_F(HWComposerTest, isHeadless) { + ASSERT_TRUE(mHwc.isHeadless()); + + constexpr hal::HWDisplayId kHwcDisplayId = 1; + expectHotplugConnect(kHwcDisplayId); - auto info = hwc.onHotplug(hwcId, hal::Connection::CONNECTED); + const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); ASSERT_TRUE(info); - auto displayId = info->id; - ASSERT_FALSE(hwc.isHeadless()); - hwc.disconnectDisplay(displayId); - ASSERT_TRUE(hwc.isHeadless()); + ASSERT_FALSE(mHwc.isHeadless()); + + mHwc.disconnectDisplay(info->id); + ASSERT_TRUE(mHwc.isHeadless()); +} + +TEST_F(HWComposerTest, getActiveMode) { + // Unknown display. + EXPECT_EQ(mHwc.getActiveMode(PhysicalDisplayId::fromPort(0)), std::nullopt); + + constexpr hal::HWDisplayId kHwcDisplayId = 2; + expectHotplugConnect(kHwcDisplayId); + + const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); + ASSERT_TRUE(info); + + { + // Display is known to SF but not HWC, e.g. the hotplug disconnect is pending. + EXPECT_CALL(*mHal, getActiveConfig(kHwcDisplayId, _)) + .WillOnce(Return(HalError::BAD_DISPLAY)); + + EXPECT_EQ(mHwc.getActiveMode(info->id), std::nullopt); + } + { + constexpr hal::HWConfigId kConfigId = 42; + EXPECT_CALL(*mHal, getActiveConfig(kHwcDisplayId, _)) + .WillOnce(DoAll(SetArgPointee<1>(kConfigId), Return(HalError::NONE))); + + EXPECT_EQ(mHwc.getActiveMode(info->id), kConfigId); + } } struct MockHWC2ComposerCallback final : StrictMock<HWC2::ComposerCallback> { @@ -93,8 +128,7 @@ struct MockHWC2ComposerCallback final : StrictMock<HWC2::ComposerCallback> { MOCK_METHOD1(onComposerHalVsyncIdle, void(hal::HWDisplayId)); }; -struct HWComposerSetCallbackTest : testing::Test { - Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>(); +struct HWComposerSetCallbackTest : HWComposerTest { MockHWC2ComposerCallback mCallback; }; @@ -113,10 +147,9 @@ TEST_F(HWComposerSetCallbackTest, loadsLayerMetadataSupport) { Return(hardware::graphics::composer::V2_4::Error::NONE))); EXPECT_CALL(*mHal, registerCallback(_)); - impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)}; - hwc.setCallback(mCallback); + mHwc.setCallback(mCallback); - const auto& supported = hwc.getSupportedLayerGenericMetadata(); + const auto& supported = mHwc.getSupportedLayerGenericMetadata(); EXPECT_EQ(2u, supported.size()); EXPECT_EQ(1u, supported.count(kMetadata1Name)); EXPECT_EQ(kMetadata1Mandatory, supported.find(kMetadata1Name)->second); @@ -130,11 +163,10 @@ TEST_F(HWComposerSetCallbackTest, handlesUnsupportedCallToGetLayerGenericMetadat .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED)); EXPECT_CALL(*mHal, registerCallback(_)); - impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)}; - hwc.setCallback(mCallback); + mHwc.setCallback(mCallback); - const auto& supported = hwc.getSupportedLayerGenericMetadata(); - EXPECT_EQ(0u, supported.size()); + const auto& supported = mHwc.getSupportedLayerGenericMetadata(); + EXPECT_TRUE(supported.empty()); } struct HWComposerLayerTest : public testing::Test { diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 17511cd615..972198cbdb 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -141,6 +141,54 @@ protected: namespace { +TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) + .WillOnce(Return(LayerInfo::FrameRateCompatibility::NoVote)); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + + // No layers returned if no layers are active. + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */); + + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(1, activeLayerCount()); +} + +TEST_F(LayerHistoryTest, singleLayerMinVoteDefaultCompatibility) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) + .WillOnce(Return(LayerInfo::FrameRateCompatibility::Min)); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */); + + auto summary = summarizeLayerHistory(time); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); +} + TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); diff --git a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp index 373fd74020..e6e02c1806 100644 --- a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp @@ -27,6 +27,8 @@ #include <gui/LayerMetadata.h> #include <log/log.h> +using android::gui::LayerMetadata; + namespace android { namespace { @@ -113,4 +115,4 @@ TEST_F(LayerMetadataTest, merge) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/LayerTest.cpp b/services/surfaceflinger/tests/unittests/LayerTest.cpp index 4974f90383..95e54f655b 100644 --- a/services/surfaceflinger/tests/unittests/LayerTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerTest.cpp @@ -17,7 +17,6 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" -#include <EffectLayer.h> #include <gtest/gtest.h> #include <ui/FloatRect.h> #include <ui/Transform.h> diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp index 5a2c1479bb..ee42e19c34 100644 --- a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp +++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp @@ -29,13 +29,13 @@ sp<Layer> BufferStateLayerFactory::createLayer(TestableSurfaceFlinger& flinger) sp<Client> client; LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, LayerMetadata()); - return new BufferStateLayer(args); + return sp<Layer>::make(args); } sp<Layer> EffectLayerFactory::createLayer(TestableSurfaceFlinger& flinger) { sp<Client> client; LayerCreationArgs args(flinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata()); - return new EffectLayer(args); + return sp<Layer>::make(args); } std::string PrintToStringParamName( @@ -53,13 +53,15 @@ void BaseLayerTest::setupScheduler() { EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.h b/services/surfaceflinger/tests/unittests/LayerTestUtils.h index fc9b6a27aa..ab446fafeb 100644 --- a/services/surfaceflinger/tests/unittests/LayerTestUtils.h +++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.h @@ -23,8 +23,6 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" -#include "BufferStateLayer.h" -#include "EffectLayer.h" #include "Layer.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index e0aa0b1768..5e1042e91f 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -32,8 +32,9 @@ using namespace testing; using CallbackToken = scheduler::VSyncDispatch::CallbackToken; struct NoOpCompositor final : ICompositor { - bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } - void composite(nsecs_t, int64_t) override {} + void configure() override {} + bool commit(TimePoint, VsyncId, TimePoint) override { return false; } + void composite(TimePoint, VsyncId) override {} void sample() override {} } gNoOpCompositor; @@ -41,12 +42,15 @@ class TestableMessageQueue : public impl::MessageQueue { struct MockHandler : MessageQueue::Handler { using MessageQueue::Handler::Handler; - MOCK_METHOD(void, dispatchFrame, (int64_t, nsecs_t), (override)); + MOCK_METHOD(void, dispatchFrame, (VsyncId, TimePoint), (override)); }; explicit TestableMessageQueue(sp<MockHandler> handler) : impl::MessageQueue(gNoOpCompositor, handler), mHandler(std::move(handler)) {} + // impl::MessageQueue overrides: + void onFrameSignal(ICompositor&, VsyncId, TimePoint) override {} + public: TestableMessageQueue() : TestableMessageQueue(sp<MockHandler>::make(*this)) {} @@ -71,7 +75,7 @@ struct MockTokenManager : frametimeline::TokenManager { struct MessageQueueTest : testing::Test { void SetUp() override { EXPECT_CALL(mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, mDuration)); + EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, kDuration)); EXPECT_CALL(mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1); } @@ -80,16 +84,15 @@ struct MessageQueueTest : testing::Test { TestableMessageQueue mEventQueue; const CallbackToken mCallbackToken{5}; - constexpr static auto mDuration = std::chrono::nanoseconds(100ms); - constexpr static auto mDifferentDuration = std::chrono::nanoseconds(250ms); + + static constexpr Duration kDuration = 100ms; + static constexpr Duration kDifferentDuration = 250ms; }; namespace { -/* ------------------------------------------------------------------------ - * Test cases - */ + TEST_F(MessageQueueTest, commit) { - const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), + const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, .earliestVsync = 0}; EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); @@ -103,7 +106,7 @@ TEST_F(MessageQueueTest, commit) { TEST_F(MessageQueueTest, commitTwice) { InSequence s; - const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), + const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, .earliestVsync = 0}; @@ -122,7 +125,7 @@ TEST_F(MessageQueueTest, commitTwice) { TEST_F(MessageQueueTest, commitTwiceWithCallback) { InSequence s; - const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), + const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, .earliestVsync = 0}; @@ -132,33 +135,36 @@ TEST_F(MessageQueueTest, commitTwiceWithCallback) { ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); - const auto startTime = 100; - const auto endTime = startTime + mDuration.count(); - const auto presentTime = 500; - const auto vsyncId = 42; + constexpr TimePoint kStartTime = TimePoint::fromNs(100); + constexpr TimePoint kEndTime = kStartTime + kDuration; + constexpr TimePoint kPresentTime = TimePoint::fromNs(500); + constexpr VsyncId vsyncId{42}; + EXPECT_CALL(mTokenManager, - generateTokenForPredictions( - frametimeline::TimelineItem(startTime, endTime, presentTime))) - .WillOnce(Return(vsyncId)); - EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, presentTime)).Times(1); - EXPECT_NO_FATAL_FAILURE(mEventQueue.vsyncCallback(presentTime, startTime, endTime)); + generateTokenForPredictions(frametimeline::TimelineItem(kStartTime.ns(), + kEndTime.ns(), + kPresentTime.ns()))) + .WillOnce(Return(vsyncId.value)); + EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, kPresentTime)).Times(1); + EXPECT_NO_FATAL_FAILURE( + mEventQueue.vsyncCallback(kPresentTime.ns(), kStartTime.ns(), kEndTime.ns())); EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); const auto timingAfterCallback = - scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), + scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, - .earliestVsync = presentTime}; + .earliestVsync = kPresentTime.ns()}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); } TEST_F(MessageQueueTest, commitWithDurationChange) { - EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(mDifferentDuration)); + EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(kDifferentDuration)); const auto timing = - scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDifferentDuration.count(), + scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDifferentDuration.ns(), .readyDuration = 0, .earliestVsync = 0}; diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index 8711a42b2b..2d66d3cf92 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -39,15 +39,15 @@ class PowerAdvisorTest : public testing::Test { public: void SetUp() override; void startPowerHintSession(); - void fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod); - void setExpectedTiming(nsecs_t startTime, nsecs_t vsyncPeriod); - nsecs_t getFenceWaitDelayDuration(bool skipValidate); + void fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod); + void setExpectedTiming(Duration totalFrameTargetDuration, TimePoint expectedPresentTime); + Duration getFenceWaitDelayDuration(bool skipValidate); protected: TestableSurfaceFlinger mFlinger; std::unique_ptr<PowerAdvisor> mPowerAdvisor; NiceMock<MockAidlPowerHalWrapper>* mMockAidlWrapper; - nsecs_t kErrorMargin = std::chrono::nanoseconds(1ms).count(); + Duration kErrorMargin = 1ms; }; void PowerAdvisorTest::SetUp() FTL_FAKE_GUARD(mPowerAdvisor->mPowerHalMutex) { @@ -67,21 +67,21 @@ void PowerAdvisorTest::startPowerHintSession() { mPowerAdvisor->startPowerHintSession(threadIds); } -void PowerAdvisorTest::setExpectedTiming(nsecs_t totalFrameTarget, nsecs_t expectedPresentTime) { - mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTarget); +void PowerAdvisorTest::setExpectedTiming(Duration totalFrameTargetDuration, + TimePoint expectedPresentTime) { + mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTargetDuration); mPowerAdvisor->setExpectedPresentTime(expectedPresentTime); } -void PowerAdvisorTest::fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod) { +void PowerAdvisorTest::fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod) { mPowerAdvisor->setCommitStart(startTime); - mPowerAdvisor->setFrameDelay(0); + mPowerAdvisor->setFrameDelay(0ns); mPowerAdvisor->setTargetWorkDuration(vsyncPeriod); } -nsecs_t PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) { +Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) { return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate - : PowerAdvisor::kFenceWaitStartDelayValidated) - .count(); + : PowerAdvisor::kFenceWaitStartDelayValidated); } namespace { @@ -93,11 +93,11 @@ TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)}; // 60hz - const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60; - const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count(); - const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count(); + const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60}; + const Duration presentDuration = 5ms; + const Duration postCompDuration = 1ms; - nsecs_t startTime = 100; + TimePoint startTime{100ns}; // advisor only starts on frame 2 so do an initial no-op frame fakeBasicFrameTiming(startTime, vsyncPeriod); @@ -109,14 +109,14 @@ TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { // increment the frame startTime += vsyncPeriod; - const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration; + const Duration expectedDuration = kErrorMargin + presentDuration + postCompDuration; EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); mPowerAdvisor->setDisplays(displayIds); - mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000); - mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000); + mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us); + mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us); mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); mPowerAdvisor->sendActualWorkDuration(); } @@ -128,12 +128,12 @@ TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)}; // 60hz - const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60; - const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count(); - const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count(); - const nsecs_t hwcBlockedDuration = std::chrono::nanoseconds(500us).count(); + const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60}; + const Duration presentDuration = 5ms; + const Duration postCompDuration = 1ms; + const Duration hwcBlockedDuration = 500us; - nsecs_t startTime = 100; + TimePoint startTime{100ns}; // advisor only starts on frame 2 so do an initial no-op frame fakeBasicFrameTiming(startTime, vsyncPeriod); @@ -145,17 +145,17 @@ TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { // increment the frame startTime += vsyncPeriod; - const nsecs_t expectedDuration = kErrorMargin + presentDuration + + const Duration expectedDuration = kErrorMargin + presentDuration + getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration; EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); mPowerAdvisor->setDisplays(displayIds); - mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000); - mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 3000000); + mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us); + mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 3ms); // now report the fence as having fired during the display HWC time - mPowerAdvisor->setSfPresentTiming(startTime + 2000000 + hwcBlockedDuration, + mPowerAdvisor->setSfPresentTiming(startTime + 2ms + hwcBlockedDuration, startTime + presentDuration); mPowerAdvisor->sendActualWorkDuration(); } @@ -168,12 +168,12 @@ TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { GpuVirtualDisplayId(1)}; // 60hz - const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60; + const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60}; // make present duration much later than the hwc display by itself will account for - const nsecs_t presentDuration = std::chrono::nanoseconds(10ms).count(); - const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count(); + const Duration presentDuration{10ms}; + const Duration postCompDuration{1ms}; - nsecs_t startTime = 100; + TimePoint startTime{100ns}; // advisor only starts on frame 2 so do an initial no-op frame fakeBasicFrameTiming(startTime, vsyncPeriod); @@ -185,7 +185,7 @@ TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { // increment the frame startTime += vsyncPeriod; - const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration; + const Duration expectedDuration = kErrorMargin + presentDuration + postCompDuration; EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); fakeBasicFrameTiming(startTime, vsyncPeriod); @@ -193,8 +193,8 @@ TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { mPowerAdvisor->setDisplays(displayIds); // don't report timing for the gpu displays since they don't use hwc - mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000); - mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000); + mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us); + mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us); mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); mPowerAdvisor->sendActualWorkDuration(); } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 188fd58dea..a706c4b33b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "SchedulerUnittests" #include <ftl/enum.h> +#include <ftl/fake_guard.h> #include <gmock/gmock.h> #include <log/log.h> #include <ui/Size.h> @@ -40,6 +41,17 @@ using mock::createDisplayMode; struct TestableRefreshRateConfigs : RefreshRateConfigs { using RefreshRateConfigs::RefreshRateConfigs; + using RefreshRateConfigs::RefreshRateOrder; + + void setActiveModeId(DisplayModeId modeId) { + ftl::FakeGuard guard(kMainThreadContext); + return RefreshRateConfigs::setActiveModeId(modeId); + } + + const DisplayMode& getActiveMode() const { + ftl::FakeGuard guard(kMainThreadContext); + return RefreshRateConfigs::getActiveMode(); + } DisplayModePtr getMinSupportedRefreshRate() const { std::lock_guard lock(mLock); @@ -56,19 +68,30 @@ struct TestableRefreshRateConfigs : RefreshRateConfigs { return getMinRefreshRateByPolicyLocked(); } + DisplayModePtr getMaxRefreshRateByPolicy() const { + std::lock_guard lock(mLock); + return getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); + } + + std::vector<RefreshRateRanking> getRefreshRatesByPolicy( + std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const { + std::lock_guard lock(mLock); + return RefreshRateConfigs::getRefreshRatesByPolicyLocked(anchorGroupOpt, refreshRateOrder); + } + const std::vector<Fps>& knownFrameRates() const { return mKnownFrameRates; } - using RefreshRateConfigs::GetBestRefreshRateCache; - auto& mutableGetBestRefreshRateCache() { return mGetBestRefreshRateCache; } + using RefreshRateConfigs::GetRankedRefreshRatesCache; + auto& mutableGetRankedRefreshRatesCache() { return mGetRankedRefreshRatesCache; } - auto getBestRefreshRateAndSignals(const std::vector<LayerRequirement>& layers, - GlobalSignals signals) const { - return RefreshRateConfigs::getBestRefreshRate(layers, signals); + auto getRankedRefreshRatesAndSignals(const std::vector<LayerRequirement>& layers, + GlobalSignals signals) const { + return RefreshRateConfigs::getRankedRefreshRates(layers, signals); } DisplayModePtr getBestRefreshRate(const std::vector<LayerRequirement>& layers = {}, GlobalSignals signals = {}) const { - return getBestRefreshRateAndSignals(layers, signals).first; + return getRankedRefreshRatesAndSignals(layers, signals).first.front().displayModePtr; } }; @@ -243,20 +266,20 @@ TEST_F(RefreshRateConfigsTest, twoModes_policyChange) { TEST_F(RefreshRateConfigsTest, twoModes_getActiveMode) { TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); { - const auto mode = configs.getActiveMode(); - EXPECT_EQ(mode->getId(), kModeId60); + const auto& mode = configs.getActiveMode(); + EXPECT_EQ(mode.getId(), kModeId60); } configs.setActiveModeId(kModeId90); { - const auto mode = configs.getActiveMode(); - EXPECT_EQ(mode->getId(), kModeId90); + const auto& mode = configs.getActiveMode(); + EXPECT_EQ(mode.getId(), kModeId90); } EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0); { - const auto mode = configs.getActiveMode(); - EXPECT_EQ(mode->getId(), kModeId90); + const auto& mode = configs.getActiveMode(); + EXPECT_EQ(mode.getId(), kModeId90); } } @@ -966,13 +989,152 @@ TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); } +TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicy) { + // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the + // different group. + TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60); + const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode90}, + RefreshRateRanking{kMode60}, + RefreshRateRanking{kMode30}}; + + const std::vector<RefreshRateRanking>& refreshRates = + configs.getRefreshRatesByPolicy(configs.getActiveMode().getGroup(), + TestableRefreshRateConfigs::RefreshRateOrder:: + Descending); + + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) + << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicy) { + // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the + // different group. + TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60); + const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode30}, + RefreshRateRanking{kMode60}, + RefreshRateRanking{kMode90}}; + + const std::vector<RefreshRateRanking>& refreshRates = + configs.getRefreshRatesByPolicy(configs.getActiveMode().getGroup(), + TestableRefreshRateConfigs::RefreshRateOrder:: + Ascending); + + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) + << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicyOutsideTheGroup) { + // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the + // different group. + TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72); + const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode30}, + RefreshRateRanking{kMode60}, + RefreshRateRanking{kMode90}}; + + EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0); + + const std::vector<RefreshRateRanking>& refreshRates = + configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt, + TestableRefreshRateConfigs::RefreshRateOrder:: + Ascending); + + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) + << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicyOutsideTheGroup) { + // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the + // different group. + TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72); + const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode90}, + RefreshRateRanking{kMode60}, + RefreshRateRanking{kMode30}}; + + EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0); + + const std::vector<RefreshRateRanking>& refreshRates = + configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt, + TestableRefreshRateConfigs::RefreshRateOrder:: + Descending); + + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) + << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateConfigsTest, powerOnImminentConsidered) { + RefreshRateConfigs configs(kModes_60_90, kModeId60); + std::vector<RefreshRateRanking> expectedRefreshRates = {RefreshRateRanking{kMode90}, + RefreshRateRanking{kMode60}}; + + auto [refreshRates, signals] = configs.getRankedRefreshRates({}, {}); + EXPECT_FALSE(signals.powerOnImminent); + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) + << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + } + + std::tie(refreshRates, signals) = configs.getRankedRefreshRates({}, {.powerOnImminent = true}); + EXPECT_TRUE(signals.powerOnImminent); + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) + << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + } + + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + auto& lr1 = layers[0]; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + + std::tie(refreshRates, signals) = + configs.getRankedRefreshRates(layers, {.powerOnImminent = true}); + EXPECT_TRUE(signals.powerOnImminent); + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) + << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + } + + expectedRefreshRates = {RefreshRateRanking{kMode60}, RefreshRateRanking{kMode90}}; + std::tie(refreshRates, signals) = + configs.getRankedRefreshRates(layers, {.powerOnImminent = false}); + EXPECT_FALSE(signals.powerOnImminent); + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) + << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + } +} + TEST_F(RefreshRateConfigsTest, touchConsidered) { RefreshRateConfigs configs(kModes_60_90, kModeId60); - auto [_, signals] = configs.getBestRefreshRate({}, {}); + auto [_, signals] = configs.getRankedRefreshRates({}, {}); EXPECT_FALSE(signals.touch); - std::tie(std::ignore, signals) = configs.getBestRefreshRate({}, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRates({}, {.touch = true}); EXPECT_TRUE(signals.touch); std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}}; @@ -985,16 +1147,16 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true}); EXPECT_TRUE(signals.touch); lr1.vote = LayerVoteType::ExplicitDefault; lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; + lr1.name = "60Hz ExplicitDefault"; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true}); EXPECT_FALSE(signals.touch); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -1003,16 +1165,16 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true}); EXPECT_TRUE(signals.touch); lr1.vote = LayerVoteType::ExplicitDefault; lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; + lr1.name = "60Hz ExplicitDefault"; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true}); EXPECT_FALSE(signals.touch); } @@ -1150,9 +1312,10 @@ TEST_F(RefreshRateConfigsTest, lr.name = "60Hz ExplicitDefault"; lr.focused = true; - const auto [mode, signals] = configs.getBestRefreshRate(layers, {.touch = true, .idle = true}); + const auto [mode, signals] = + configs.getRankedRefreshRates(layers, {.touch = true, .idle = true}); - EXPECT_EQ(mode, kMode60); + EXPECT_EQ(mode.begin()->displayModePtr, kMode60); EXPECT_FALSE(signals.touch); } @@ -1172,14 +1335,147 @@ TEST_F(RefreshRateConfigsTest, EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.idle = true})); } +TEST_F(RefreshRateConfigsTest, testDisplayModeOrdering) { + TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60); + + std::vector<LayerRequirement> layers = {{.weight = 1.f}, + {.weight = 1.f}, + {.weight = 1.f}, + {.weight = 1.f}, + {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + auto& lr3 = layers[2]; + auto& lr4 = layers[3]; + auto& lr5 = layers[4]; + + lr1.desiredRefreshRate = 90_Hz; + lr1.name = "90Hz"; + lr1.focused = true; + + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz"; + lr2.focused = true; + + lr3.desiredRefreshRate = 72_Hz; + lr3.name = "72Hz"; + lr3.focused = true; + + lr4.desiredRefreshRate = 120_Hz; + lr4.name = "120Hz"; + lr4.focused = true; + + lr5.desiredRefreshRate = 30_Hz; + lr5.name = "30Hz"; + lr5.focused = true; + + std::vector<RefreshRateRanking> expectedRankings = { + RefreshRateRanking{kMode120}, RefreshRateRanking{kMode90}, RefreshRateRanking{kMode72}, + RefreshRateRanking{kMode60}, RefreshRateRanking{kMode30}, + }; + + std::vector<RefreshRateRanking> actualOrder = + configs.getRankedRefreshRatesAndSignals(layers, {}).first; + ASSERT_EQ(expectedRankings.size(), actualOrder.size()); + for (size_t i = 0; i < expectedRankings.size(); ++i) { + EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr) + << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue(); + } + + lr1.vote = LayerVoteType::Max; + lr1.name = "Max"; + + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz"; + + lr3.desiredRefreshRate = 72_Hz; + lr3.name = "72Hz"; + + lr4.desiredRefreshRate = 90_Hz; + lr4.name = "90Hz"; + + lr5.desiredRefreshRate = 120_Hz; + lr5.name = "120Hz"; + + expectedRankings = { + RefreshRateRanking{kMode120}, RefreshRateRanking{kMode90}, RefreshRateRanking{kMode72}, + RefreshRateRanking{kMode60}, RefreshRateRanking{kMode30}, + }; + + actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first; + + ASSERT_EQ(expectedRankings.size(), actualOrder.size()); + for (size_t i = 0; i < expectedRankings.size(); ++i) { + EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr) + << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue(); + } + + lr1.vote = LayerVoteType::Heuristic; + lr1.desiredRefreshRate = 30_Hz; + lr1.name = "30Hz"; + + lr2.desiredRefreshRate = 120_Hz; + lr2.name = "120Hz"; + + lr3.desiredRefreshRate = 60_Hz; + lr3.name = "60Hz"; + + lr5.desiredRefreshRate = 72_Hz; + lr5.name = "72Hz"; + + expectedRankings = { + RefreshRateRanking{kMode30}, RefreshRateRanking{kMode60}, RefreshRateRanking{kMode90}, + RefreshRateRanking{kMode120}, RefreshRateRanking{kMode72}, + }; + + actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first; + ASSERT_EQ(expectedRankings.size(), actualOrder.size()); + for (size_t i = 0; i < expectedRankings.size(); ++i) { + EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr) + << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue(); + } + + lr1.desiredRefreshRate = 120_Hz; + lr1.name = "120Hz"; + lr1.weight = 0.0f; + + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz"; + lr2.vote = LayerVoteType::NoVote; + + lr3.name = "60Hz-2"; + lr3.vote = LayerVoteType::Heuristic; + + lr4.vote = LayerVoteType::ExplicitExact; + + lr5.desiredRefreshRate = 120_Hz; + lr5.name = "120Hz-2"; + + expectedRankings = { + RefreshRateRanking{kMode90}, RefreshRateRanking{kMode60}, RefreshRateRanking{kMode120}, + RefreshRateRanking{kMode72}, RefreshRateRanking{kMode30}, + }; + + actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first; + ASSERT_EQ(expectedRankings.size(), actualOrder.size()); + for (size_t i = 0; i < expectedRankings.size(); ++i) { + EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr) + << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue() + << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue(); + } +} + TEST_F(RefreshRateConfigsTest, getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) { TestableRefreshRateConfigs configs(kModes_60_90, kModeId90); EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0); - const auto [mode, signals] = configs.getBestRefreshRateAndSignals({}, {}); - EXPECT_EQ(mode, kMode90); + const auto [mode, signals] = configs.getRankedRefreshRatesAndSignals({}, {}); + EXPECT_EQ(mode.front().displayModePtr, kMode90); EXPECT_FALSE(signals.touch); std::vector<LayerRequirement> layers = {{.weight = 1.f}}; @@ -1556,11 +1852,12 @@ TEST_F(RefreshRateConfigsTest, idle) { layers[0].desiredRefreshRate = 90_Hz; const auto [refreshRate, signals] = - configs.getBestRefreshRateAndSignals(layers, {.touch = touchActive, .idle = true}); + configs.getRankedRefreshRatesAndSignals(layers, + {.touch = touchActive, .idle = true}); // Refresh rate will be chosen by either touch state or idle state. EXPECT_EQ(!touchActive, signals.idle); - return refreshRate->getId(); + return refreshRate.front().displayModePtr->getId(); }; EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0); @@ -1719,24 +2016,26 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCache) { using GlobalSignals = RefreshRateConfigs::GlobalSignals; const auto args = std::make_pair(std::vector<LayerRequirement>{}, GlobalSignals{.touch = true, .idle = true}); - const auto result = std::make_pair(kMode90, GlobalSignals{.touch = true}); - configs.mutableGetBestRefreshRateCache() = {args, result}; + const auto result = std::make_pair(std::vector<RefreshRateRanking>{RefreshRateRanking{kMode90}}, + GlobalSignals{.touch = true}); + + configs.mutableGetRankedRefreshRatesCache() = {args, result}; - EXPECT_EQ(result, configs.getBestRefreshRateAndSignals(args.first, args.second)); + EXPECT_EQ(result, configs.getRankedRefreshRatesAndSignals(args.first, args.second)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_WritesCache) { TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60); - EXPECT_FALSE(configs.mutableGetBestRefreshRateCache()); + EXPECT_FALSE(configs.mutableGetRankedRefreshRatesCache()); std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}}; RefreshRateConfigs::GlobalSignals globalSignals{.touch = true, .idle = true}; - const auto result = configs.getBestRefreshRateAndSignals(layers, globalSignals); + const auto result = configs.getRankedRefreshRatesAndSignals(layers, globalSignals); - const auto& cache = configs.mutableGetBestRefreshRateCache(); + const auto& cache = configs.mutableGetRankedRefreshRatesCache(); ASSERT_TRUE(cache); EXPECT_EQ(cache->arguments, std::make_pair(layers, globalSignals)); @@ -1898,30 +2197,30 @@ TEST_F(RefreshRateConfigsTest, testKernelIdleTimerActionFor120Hz) { } TEST_F(RefreshRateConfigsTest, getFrameRateDivisor) { - RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30); + TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30); const auto frameRate = 30_Hz; - Fps displayRefreshRate = configs.getActiveMode()->getFps(); + Fps displayRefreshRate = configs.getActiveMode().getFps(); EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); configs.setActiveModeId(kModeId60); - displayRefreshRate = configs.getActiveMode()->getFps(); + displayRefreshRate = configs.getActiveMode().getFps(); EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); configs.setActiveModeId(kModeId72); - displayRefreshRate = configs.getActiveMode()->getFps(); + displayRefreshRate = configs.getActiveMode().getFps(); EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); configs.setActiveModeId(kModeId90); - displayRefreshRate = configs.getActiveMode()->getFps(); + displayRefreshRate = configs.getActiveMode().getFps(); EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); configs.setActiveModeId(kModeId120); - displayRefreshRate = configs.getActiveMode()->getFps(); + displayRefreshRate = configs.getActiveMode().getFps(); EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); configs.setActiveModeId(kModeId90); - displayRefreshRate = configs.getActiveMode()->getFps(); + displayRefreshRate = configs.getActiveMode().getFps(); EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, 22.5_Hz)); EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 25_Hz)); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index 1e6e3361b2..ac63a0edbd 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -21,8 +21,6 @@ #include <gtest/gtest.h> #include <gui/LayerMetadata.h> -#include "BufferStateLayer.h" -#include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -59,8 +57,8 @@ protected: static constexpr int32_t PRIORITY_UNSET = -1; void setupScheduler(); - sp<BufferStateLayer> createBufferStateLayer(); - sp<EffectLayer> createEffectLayer(); + sp<Layer> createBufferStateLayer(); + sp<Layer> createEffectLayer(); void setParent(Layer* child, Layer* parent); void commitTransaction(Layer* layer); @@ -88,22 +86,21 @@ RefreshRateSelectionTest::~RefreshRateSelectionTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } - -sp<BufferStateLayer> RefreshRateSelectionTest::createBufferStateLayer() { +sp<Layer> RefreshRateSelectionTest::createBufferStateLayer() { sp<Client> client; LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", LAYER_FLAGS, LayerMetadata()); - return new BufferStateLayer(args); + return sp<Layer>::make(args); } -sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() { +sp<Layer> RefreshRateSelectionTest::createEffectLayer() { sp<Client> client; LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata()); - return new EffectLayer(args); + return sp<Layer>::make(args); } void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) { - child->setParent(parent); + child->setParent(sp<Layer>::fromExisting(parent)); } void RefreshRateSelectionTest::commitTransaction(Layer* layer) { @@ -117,13 +114,15 @@ void RefreshRateSelectionTest::setupScheduler() { EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp index f19e55409c..409e1ef5d7 100644 --- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp +++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp @@ -106,40 +106,6 @@ TEST_F(RegionSamplingTest, bounds_checking) { testing::Eq(0.0)); } -// workaround for b/133849373 -TEST_F(RegionSamplingTest, orientation_90) { - std::generate(buffer.begin(), buffer.end(), - [n = 0]() mutable { return (n++ > (kStride * kHeight >> 1)) ? kBlack : kWhite; }); - - Rect tl_region{0, 0, 4, 4}; - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_0, - tl_region), - testing::Eq(1.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_180, - tl_region), - testing::Eq(1.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_90, - tl_region), - testing::Eq(0.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_270, - tl_region), - testing::Eq(0.0)); - - Rect br_region{kWidth - 4, kHeight - 4, kWidth, kHeight}; - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_0, - br_region), - testing::Eq(0.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_180, - br_region), - testing::Eq(0.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_90, - br_region), - testing::Eq(1.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_270, - br_region), - testing::Eq(1.0)); -} - } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 93c809e2fd..53e49eb0d4 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -48,7 +48,8 @@ protected: class MockEventThreadConnection : public android::EventThreadConnection { public: explicit MockEventThreadConnection(EventThread* eventThread) - : EventThreadConnection(eventThread, /*callingUid=*/0, ResyncCallback()) {} + : EventThreadConnection(eventThread, /*callingUid*/ static_cast<uid_t>(0), + ResyncCallback()) {} ~MockEventThreadConnection() = default; MOCK_METHOD1(stealReceiveChannel, binder::Status(gui::BitTube* outChannel)); @@ -79,7 +80,7 @@ SchedulerTest::SchedulerTest() { mEventThread = eventThread.get(); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); - mEventThreadConnection = new MockEventThreadConnection(mEventThread); + mEventThreadConnection = sp<MockEventThreadConnection>::make(mEventThread); // createConnection call to scheduler makes a createEventConnection call to EventThread. Make // sure that call gets executed and returns an EventThread::Connection object. diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index b9a5f36794..dfcfd912f9 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -24,8 +24,6 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" -#include "BufferStateLayer.h" -#include "EffectLayer.h" #include "Layer.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" @@ -78,11 +76,11 @@ SetFrameRateTest::SetFrameRateTest() { } void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) { - layer.get()->addChild(child.get()); + layer->addChild(child); } void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) { - layer.get()->removeChild(child.get()); + layer->removeChild(child); } void SetFrameRateTest::commitTransaction() { @@ -374,11 +372,6 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { const auto& layerFactory = GetParam(); auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); - if (!parent->isVisible()) { - // This is a hack as all the test layers except EffectLayer are not visible, - // but since the logic is unified in Layer, it should be fine. - return; - } auto child = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); addChild(parent, child); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp index c7e61c96d6..40ef949468 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp @@ -65,7 +65,7 @@ TEST_F(DestroyDisplayTest, destroyDisplayHandlesUnknownDisplay) { // -------------------------------------------------------------------- // Preconditions - sp<BBinder> displayToken = new BBinder(); + sp<BBinder> displayToken = sp<BBinder>::make(); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 5872a472cd..6b7e3533a5 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -20,6 +20,7 @@ #include "DisplayTransactionTestHelpers.h" +#include <ftl/fake_guard.h> #include <scheduler/Fps.h> namespace android { @@ -40,18 +41,17 @@ public: PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this); PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this); - mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); + DisplayModes modes = makeModes(kMode60, kMode90, kMode120, kMode90_4K); + auto configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60); - { - DisplayModes modes = makeModes(kMode60, kMode90, kMode120, kMode90_4K); - auto configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60); + setupScheduler(configs); - mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) - .setDisplayModes(std::move(modes), kModeId60, std::move(configs)) - .inject(); - } + mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); + mFlinger.configureAndCommit(); - setupScheduler(mDisplay->holdRefreshRateConfigs()); + mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) + .setDisplayModes(std::move(modes), kModeId60, std::move(configs)) + .inject(); // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy // will call setActiveConfig instead of setActiveConfigWithConstraints. @@ -87,13 +87,15 @@ void DisplayModeSwitchingTest::setupScheduler( EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); @@ -110,8 +112,10 @@ void DisplayModeSwitchingTest::setupScheduler( } TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) { + ftl::FakeGuard guard(kMainThreadContext); + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60); mFlinger.onActiveDisplayChanged(mDisplay); @@ -120,7 +124,7 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRe ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; @@ -133,7 +137,7 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRe Mock::VerifyAndClearExpectations(mComposer); ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60); // Verify that the next commit will complete the mode change and send // a onModeChanged event to the framework. @@ -143,10 +147,12 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRe Mock::VerifyAndClearExpectations(mAppEventThread); ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId90); } TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired) { + ftl::FakeGuard guard(kMainThreadContext); + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); mFlinger.onActiveDisplayChanged(mDisplay); @@ -156,7 +162,7 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefres ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC // and complete the mode change. @@ -171,15 +177,17 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefres mFlinger.commit(); ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId90); } TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { + ftl::FakeGuard guard(kMainThreadContext); + // Test that if we call setDesiredDisplayModeSpecs while a previous mode change // is still being processed the later call will be respected. ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60); mFlinger.onActiveDisplayChanged(mDisplay); @@ -213,12 +221,14 @@ TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { mFlinger.commit(); ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId120); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId120); } TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefreshRequired) { + ftl::FakeGuard guard(kMainThreadContext); + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60); mFlinger.onActiveDisplayChanged(mDisplay); @@ -227,7 +237,7 @@ TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefresh ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90_4K); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC // and complete the mode change. @@ -262,7 +272,7 @@ TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefresh mDisplay = mFlinger.getDisplay(displayToken); ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90_4K); + ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId90_4K); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp index 9ac29071b2..73f654ba87 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp @@ -118,9 +118,7 @@ void DisplayTransactionCommitTest::verifyDisplayIsConnected(const sp<IBinder>& d ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); - expectedPhysical = {.id = *displayId, - .type = *connectionType, - .hwcDisplayId = *hwcDisplayId}; + expectedPhysical = {.id = *displayId, .hwcDisplayId = *hwcDisplayId}; } // The display should have been set up in the current display state @@ -145,10 +143,13 @@ void DisplayTransactionCommitTest::verifyPhysicalDisplayIsConnected() { const auto displayId = Case::Display::DISPLAY_ID::get(); ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId); - ASSERT_TRUE(displayTokenOpt); + const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(displayId); + ASSERT_TRUE(displayOpt); - verifyDisplayIsConnected<Case>(displayTokenOpt->get()); + const auto& display = displayOpt->get(); + EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, display.snapshot().connectionType()); + + verifyDisplayIsConnected<Case>(display.token()); } void DisplayTransactionCommitTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) { @@ -175,7 +176,7 @@ void DisplayTransactionCommitTest::processesHotplugConnectCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + mFlinger.configureAndCommit(); // -------------------------------------------------------------------- // Postconditions @@ -204,7 +205,7 @@ void DisplayTransactionCommitTest::ignoresHotplugConnectCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + mFlinger.configureAndCommit(); // -------------------------------------------------------------------- // Postconditions @@ -239,7 +240,7 @@ void DisplayTransactionCommitTest::processesHotplugDisconnectCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + mFlinger.configureAndCommit(); // -------------------------------------------------------------------- // Postconditions @@ -247,10 +248,10 @@ void DisplayTransactionCommitTest::processesHotplugDisconnectCommon() { // HWComposer should not have an entry for the display EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); - // SF should not have a display token. + // SF should not have a PhysicalDisplay. const auto displayId = Case::Display::DISPLAY_ID::get(); ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId)); + ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(displayId)); // The existing token should have been removed. verifyDisplayIsNotConnected(existing.token()); @@ -321,7 +322,7 @@ TEST_F(DisplayTransactionCommitTest, processesHotplugConnectThenDisconnectPrimar // -------------------------------------------------------------------- // Invocation - mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + mFlinger.configureAndCommit(); // -------------------------------------------------------------------- // Postconditions @@ -329,10 +330,10 @@ TEST_F(DisplayTransactionCommitTest, processesHotplugConnectThenDisconnectPrimar // HWComposer should not have an entry for the display EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); - // SF should not have a display token. + // SF should not have a PhysicalDisplay. const auto displayId = Case::Display::DISPLAY_ID::get(); ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId)); + ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(displayId)); }(), testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); } @@ -366,7 +367,7 @@ TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectThenConnectPrimar // -------------------------------------------------------------------- // Invocation - mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + mFlinger.configureAndCommit(); // -------------------------------------------------------------------- // Postconditions @@ -376,9 +377,9 @@ TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectThenConnectPrimar const auto displayId = Case::Display::DISPLAY_ID::get(); ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId); - ASSERT_TRUE(displayTokenOpt); - EXPECT_NE(existing.token(), displayTokenOpt->get()); + const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(displayId); + ASSERT_TRUE(displayOpt); + EXPECT_NE(existing.token(), displayOpt->get().token()); // A new display should be connected in its place. verifyPhysicalDisplayIsConnected<Case>(); @@ -408,12 +409,12 @@ TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAdded) { // A virtual display was added to the current state, and it has a // surface(producer) - sp<BBinder> displayToken = new BBinder(); + sp<BBinder> displayToken = sp<BBinder>::make(); DisplayDeviceState state; state.isSecure = static_cast<bool>(Case::Display::SECURE); - sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()}; + sp<mock::GraphicBufferProducer> surface{sp<mock::GraphicBufferProducer>::make()}; state.surface = surface; mFlinger.mutableCurrentState().displays.add(displayToken, state); @@ -479,7 +480,7 @@ TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAddedWithNoSurface) // A virtual display was added to the current state, but it does not have a // surface. - sp<BBinder> displayToken = new BBinder(); + sp<BBinder> displayToken = sp<BBinder>::make(); DisplayDeviceState state; state.isSecure = static_cast<bool>(Case::Display::SECURE); @@ -656,9 +657,11 @@ TEST_F(DisplayTransactionCommitTest, processesDisplayWidthChanges) { // Preconditions // A display is set up - auto nativeWindow = new mock::NativeWindow(); - auto displaySurface = new compositionengine::mock::DisplaySurface(); - sp<GraphicBuffer> buf = new GraphicBuffer(); + auto nativeWindow = sp<mock::NativeWindow>::make(); + auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make(); + sp<GraphicBuffer> buf = + + sp<GraphicBuffer>::make(); auto display = Case::Display::makeFakeExistingDisplayInjector(this); display.setNativeWindow(nativeWindow); display.setDisplaySurface(displaySurface); @@ -701,9 +704,9 @@ TEST_F(DisplayTransactionCommitTest, processesDisplayHeightChanges) { // Preconditions // A display is set up - auto nativeWindow = new mock::NativeWindow(); - auto displaySurface = new compositionengine::mock::DisplaySurface(); - sp<GraphicBuffer> buf = new GraphicBuffer(); + auto nativeWindow = sp<mock::NativeWindow>::make(); + auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make(); + sp<GraphicBuffer> buf = sp<GraphicBuffer>::make(); auto display = Case::Display::makeFakeExistingDisplayInjector(this); display.setNativeWindow(nativeWindow); display.setDisplaySurface(displaySurface); @@ -750,9 +753,9 @@ TEST_F(DisplayTransactionCommitTest, processesDisplaySizeDisplayRectAndLayerStac // Preconditions // A display is set up - auto nativeWindow = new mock::NativeWindow(); - auto displaySurface = new compositionengine::mock::DisplaySurface(); - sp<GraphicBuffer> buf = new GraphicBuffer(); + auto nativeWindow = sp<mock::NativeWindow>::make(); + auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make(); + sp<GraphicBuffer> buf = sp<GraphicBuffer>::make(); auto display = Case::Display::makeFakeExistingDisplayInjector(this); display.setNativeWindow(nativeWindow); display.setDisplaySurface(displaySurface); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp index 0171f1b41d..5951c9893f 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp @@ -95,7 +95,7 @@ TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) { } TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) { - sp<BBinder> notInternalDisplayToken = new BBinder(); + sp<BBinder> notInternalDisplayToken = sp<BBinder>::make(); ui::DisplayPrimaries primaries; populateDummyDisplayNativePrimaries(primaries); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp index c9a2b00fa3..1210d0b472 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp @@ -20,41 +20,18 @@ #include "DisplayTransactionTestHelpers.h" namespace android { -namespace { class HotplugTest : public DisplayTransactionTest {}; -TEST_F(HotplugTest, enqueuesEventsForDisplayTransaction) { - constexpr HWDisplayId hwcDisplayId1 = 456; - constexpr HWDisplayId hwcDisplayId2 = 654; - - // -------------------------------------------------------------------- - // Preconditions - - // Set the main thread id so that the current thread does not appear to be - // the main thread. - mFlinger.mutableMainThreadId() = std::thread::id(); - - // -------------------------------------------------------------------- - // Call Expectations +TEST_F(HotplugTest, schedulesConfigureToProcessHotplugEvents) { + EXPECT_CALL(*mFlinger.scheduler(), scheduleConfigure()).Times(2); - // We expect a scheduled commit for the display transaction. - EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); - - // -------------------------------------------------------------------- - // Invocation - - // Simulate two hotplug events (a connect and a disconnect) + constexpr HWDisplayId hwcDisplayId1 = 456; mFlinger.onComposerHalHotplug(hwcDisplayId1, Connection::CONNECTED); - mFlinger.onComposerHalHotplug(hwcDisplayId2, Connection::DISCONNECTED); - - // -------------------------------------------------------------------- - // Postconditions - // The display transaction needed flag should be set. - EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); + constexpr HWDisplayId hwcDisplayId2 = 654; + mFlinger.onComposerHalHotplug(hwcDisplayId2, Connection::DISCONNECTED); - // All events should be in the pending event queue. const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents(); ASSERT_EQ(2u, pendingEvents.size()); EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId); @@ -63,49 +40,83 @@ TEST_F(HotplugTest, enqueuesEventsForDisplayTransaction) { EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection); } -TEST_F(HotplugTest, processesEnqueuedEventsIfCalledOnMainThread) { +TEST_F(HotplugTest, schedulesFrameToCommitDisplayTransaction) { + EXPECT_CALL(*mFlinger.scheduler(), scheduleConfigure()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); + constexpr HWDisplayId displayId1 = 456; + mFlinger.onComposerHalHotplug(displayId1, Connection::DISCONNECTED); + mFlinger.configure(); - // -------------------------------------------------------------------- - // Note: - // -------------------------------------------------------------------- - // This test case is a bit tricky. We want to verify that - // onComposerHalHotplug() calls processDisplayHotplugEventsLocked(), but we - // don't really want to provide coverage for everything the later function - // does as there are specific tests for it. - // -------------------------------------------------------------------- + // The configure stage should consume the hotplug queue and produce a display transaction. + EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty()); + EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); +} - // -------------------------------------------------------------------- - // Preconditions +TEST_F(HotplugTest, ignoresDuplicateDisconnection) { + // Inject a primary display. + PrimaryDisplayVariant::injectHwcDisplay(this); - // Set the main thread id so that the current thread does appear to be the - // main thread. - mFlinger.mutableMainThreadId() = std::this_thread::get_id(); + using ExternalDisplay = ExternalDisplayVariant; + ExternalDisplay::setupHwcHotplugCallExpectations(this); + ExternalDisplay::setupHwcGetActiveConfigCallExpectations(this); - // -------------------------------------------------------------------- - // Call Expectations + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); - // We expect a scheduled commit for the display transaction. + // A single commit should be scheduled for both configure calls. EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); - // -------------------------------------------------------------------- - // Invocation + ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + mFlinger.configure(); - // Simulate a disconnect on a display id that is not connected. This should - // be enqueued by onComposerHalHotplug(), and dequeued by - // processDisplayHotplugEventsLocked(), but then ignored as invalid. - mFlinger.onComposerHalHotplug(displayId1, Connection::DISCONNECTED); + EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); - // -------------------------------------------------------------------- - // Postconditions + // Disconnecting a display that was already disconnected should be a no-op. + ExternalDisplay::injectPendingHotplugEvent(this, Connection::DISCONNECTED); + ExternalDisplay::injectPendingHotplugEvent(this, Connection::DISCONNECTED); + ExternalDisplay::injectPendingHotplugEvent(this, Connection::DISCONNECTED); + mFlinger.configure(); - // The display transaction needed flag should be set. - EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); + // The display should be scheduled for removal during the next commit. At this point, it should + // still exist but be marked as disconnected. + EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); + EXPECT_FALSE(mFlinger.getHwComposer().isConnected(ExternalDisplay::DISPLAY_ID::get())); +} - // There should be no event queued on return, as it should have been - // processed. - EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty()); +TEST_F(HotplugTest, rejectsHotplugIfFailedToLoadDisplayModes) { + // Inject a primary display. + PrimaryDisplayVariant::injectHwcDisplay(this); + + using ExternalDisplay = ExternalDisplayVariant; + constexpr bool kFailedHotplug = true; + ExternalDisplay::setupHwcHotplugCallExpectations<kFailedHotplug>(this); + + // Simulate a connect event that fails to load display modes due to HWC already having + // disconnected the display but SF yet having to process the queued disconnect event. + EXPECT_CALL(*mComposer, getActiveConfig(ExternalDisplay::HWC_DISPLAY_ID, _)) + .WillRepeatedly(Return(Error::BAD_DISPLAY)); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); + + ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + mFlinger.configure(); + + // The hotplug should be rejected, so no HWComposer::DisplayData should be created. + EXPECT_FALSE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); + + // Disconnecting a display that does not exist should be a no-op. + ExternalDisplay::injectPendingHotplugEvent(this, Connection::DISCONNECTED); + mFlinger.configure(); + + EXPECT_FALSE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); } -} // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp index 37cf05ef64..98249bf104 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp @@ -78,19 +78,8 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { auto displayDevice = primaryDisplay.mutableDisplayDevice(); EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode()); - // The display refresh period should be set in the orientedDisplaySpaceRect tracker. - FrameStats stats; - mFlinger.getAnimFrameTracker().getStats(&stats); - EXPECT_EQ(DEFAULT_VSYNC_PERIOD, stats.refreshPeriodNano); - // The display transaction needed flag should be set. EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); - - // The compositor timing should be set to default values - const auto& compositorTiming = mFlinger.getCompositorTiming(); - EXPECT_EQ(-DEFAULT_VSYNC_PERIOD, compositorTiming.deadline); - EXPECT_EQ(DEFAULT_VSYNC_PERIOD, compositorTiming.interval); - EXPECT_EQ(DEFAULT_VSYNC_PERIOD, compositorTiming.presentLatency); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp index 2c9888dd8e..e256d2c9a1 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp @@ -60,8 +60,8 @@ protected: renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); sp<DisplayDevice> mDisplay; sp<compositionengine::mock::DisplaySurface> mDisplaySurface = - new compositionengine::mock::DisplaySurface(); - mock::NativeWindow* mNativeWindow = new mock::NativeWindow(); + sp<compositionengine::mock::DisplaySurface>::make(); + sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make(); mock::TimeStats* mTimeStats = new mock::TimeStats(); Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr; Hwc2::mock::Composer* mComposer = nullptr; @@ -106,13 +106,15 @@ void SurfaceFlingerPowerHintTest::setupScheduler() { EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); @@ -131,22 +133,20 @@ void SurfaceFlingerPowerHintTest::setupScheduler() { TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) { ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true)); - const std::chrono::nanoseconds mockVsyncPeriod = 15ms; EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(1); - - const nsecs_t now = systemTime(); - const std::chrono::nanoseconds mockHwcRunTime = 20ms; EXPECT_CALL(*mDisplaySurface, prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc)) .Times(1); - EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _)) - .WillOnce([mockHwcRunTime] { - std::this_thread::sleep_for(mockHwcRunTime); - return hardware::graphics::composer::V2_1::Error::NONE; - }); + EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _)).WillOnce([] { + constexpr Duration kMockHwcRunTime = 20ms; + std::this_thread::sleep_for(kMockHwcRunTime); + return hardware::graphics::composer::V2_1::Error::NONE; + }); EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(1); - static constexpr bool kVsyncId = 123; // arbitrary - mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count()); + + const TimePoint frameTime = scheduler::SchedulerClock::now(); + constexpr Period kMockVsyncPeriod = 15ms; + mFlinger.commitAndComposite(frameTime, VsyncId{123}, frameTime + kMockVsyncPeriod); } TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) { @@ -154,22 +154,20 @@ TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) { mDisplay->setPowerMode(hal::PowerMode::DOZE); - const std::chrono::nanoseconds mockVsyncPeriod = 15ms; EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(0); - - const nsecs_t now = systemTime(); - const std::chrono::nanoseconds mockHwcRunTime = 20ms; EXPECT_CALL(*mDisplaySurface, prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc)) .Times(1); - EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _)) - .WillOnce([mockHwcRunTime] { - std::this_thread::sleep_for(mockHwcRunTime); - return hardware::graphics::composer::V2_1::Error::NONE; - }); + EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _)).WillOnce([] { + constexpr Duration kMockHwcRunTime = 20ms; + std::this_thread::sleep_for(kMockHwcRunTime); + return hardware::graphics::composer::V2_1::Error::NONE; + }); EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(0); - static constexpr bool kVsyncId = 123; // arbitrary - mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count()); + + const TimePoint frameTime = scheduler::SchedulerClock::now(); + constexpr Period kMockVsyncPeriod = 15ms; + mFlinger.commitAndComposite(frameTime, VsyncId{123}, frameTime + kMockVsyncPeriod); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp index 7d9e22b23e..9c7f55b733 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp @@ -34,7 +34,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDis // Preconditions // We have an unknown display token not associated with a known display - sp<BBinder> displayToken = new BBinder(); + sp<BBinder> displayToken = sp<BBinder>::make(); // The requested display state references the unknown display. DisplayState state; @@ -95,7 +95,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfSurfaceDidNo display.inject(); // There is a surface that can be set. - sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer(); + sp<mock::GraphicBufferProducer> surface = sp<mock::GraphicBufferProducer>::make(); // The current display state has the surface set display.mutableCurrentDisplayState().surface = surface; @@ -132,7 +132,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfSurfaceCh display.inject(); // There is a surface that can be set. - sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer(); + sp<mock::GraphicBufferProducer> surface = sp<mock::GraphicBufferProducer>::make(); // The current display state does not have a surface display.mutableCurrentDisplayState().surface = nullptr; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp index 583cf5f836..9e54083615 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp @@ -140,7 +140,6 @@ struct TransitionOffToOnVariant : public TransitionVariantCommon<PowerMode::OFF, static void verifyPostconditions(DisplayTransactionTest* test) { EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty()); - EXPECT_TRUE(test->mFlinger.getHasPoweredOff()); } }; @@ -155,7 +154,6 @@ struct TransitionOffToDozeSuspendVariant static void verifyPostconditions(DisplayTransactionTest* test) { EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty()); - EXPECT_TRUE(test->mFlinger.getHasPoweredOff()); } }; @@ -255,14 +253,16 @@ struct DisplayPowerCase { using DispSync = DispSyncVariant; using Transition = TransitionVariant; - static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) { + static sp<DisplayDevice> injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, + PowerMode mode) { Display::injectHwcDisplayWithNoDefaultCapabilities(test); - auto display = Display::makeFakeExistingDisplayInjector(test); - display.inject(); - display.mutableDisplayDevice()->setPowerMode(mode); - if (display.mutableDisplayDevice()->isInternal()) { - test->mFlinger.mutableActiveDisplayToken() = - display.mutableDisplayDevice()->getDisplayToken(); + auto injector = Display::makeFakeExistingDisplayInjector(test); + const auto display = injector.inject(); + display->setPowerMode(mode); + if (injector.physicalDisplay() + .transform(&display::PhysicalDisplay::isInternal) + .value_or(false)) { + test->mFlinger.mutableActiveDisplayToken() = display->getDisplayToken(); } return display; @@ -355,8 +355,7 @@ void SetPowerModeInternalTest::transitionDisplayCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), - Case::Transition::TARGET_POWER_MODE); + mFlinger.setPowerModeInternal(display, Case::Transition::TARGET_POWER_MODE); // -------------------------------------------------------------------- // Postconditions diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index a0e078bf5e..073c459ea3 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -17,6 +17,8 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" +#include <ftl/fake_guard.h> + #include "DisplayHardware/DisplayMode.h" #include "DisplayTransactionTestHelpers.h" @@ -197,10 +199,10 @@ public: template <typename Case> void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { - const sp<BBinder> displayToken = new BBinder(); + const sp<BBinder> displayToken = sp<BBinder>::make(); const sp<compositionengine::mock::DisplaySurface> displaySurface = - new compositionengine::mock::DisplaySurface(); - const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer(); + sp<compositionengine::mock::DisplaySurface>::make(); + const auto producer = sp<mock::GraphicBufferProducer>::make(); // -------------------------------------------------------------------- // Preconditions @@ -246,11 +248,14 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { .setDpiY(DEFAULT_DPI) .setGroup(0) .build(); + state.physical = {.id = *displayId, - .type = *connectionType, .hwcDisplayId = *hwcDisplayId, - .supportedModes = makeModes(activeMode), - .activeMode = std::move(activeMode)}; + .activeMode = activeMode}; + + mFlinger.mutablePhysicalDisplays().emplace_or_replace(*displayId, displayToken, *displayId, + *connectionType, + makeModes(activeMode), std::nullopt); } state.isSecure = static_cast<bool>(Case::Display::SECURE); @@ -262,9 +267,8 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { // -------------------------------------------------------------------- // Postconditions - ASSERT_TRUE(device != nullptr); + ASSERT_NE(nullptr, device); EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId()); - EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType()); EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual()); EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure()); EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary()); @@ -280,9 +284,8 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { device->receivesInput()); if constexpr (Case::Display::CONNECTION_TYPE::value) { - EXPECT_EQ(1, device->getSupportedModes().size()); - EXPECT_NE(nullptr, device->getActiveMode()); - EXPECT_EQ(Case::Display::HWC_ACTIVE_CONFIG_ID, device->getActiveMode()->getHwcId()); + ftl::FakeGuard guard(kMainThreadContext); + EXPECT_EQ(Case::Display::HWC_ACTIVE_CONFIG_ID, device->getActiveMode().getHwcId()); } } diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp new file mode 100644 index 0000000000..0cf3bdf0d5 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp @@ -0,0 +1,212 @@ +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <gui/LayerMetadata.h> + +#include "TestableSurfaceFlinger.h" +#include "mock/MockEventThread.h" +#include "mock/MockVsyncController.h" + +namespace android { + +using testing::_; +using testing::Return; +using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + +class SurfaceFlingerUpdateLayerMetadataSnapshotTest : public testing::Test { +public: + SurfaceFlingerUpdateLayerMetadataSnapshotTest() { setupScheduler(); } + +protected: + void setupScheduler() { + auto eventThread = std::make_unique<mock::EventThread>(); + auto sfEventThread = std::make_unique<mock::EventThread>(); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); + + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); + + auto vsyncController = std::make_unique<mock::VsyncController>(); + auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); + + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), + std::move(eventThread), std::move(sfEventThread)); + } + + sp<Layer> createLayer(const char* name, LayerMetadata layerMetadata) { + return sp<Layer>::make( + LayerCreationArgs{mFlinger.flinger(), nullptr, name, 0, layerMetadata}); + } + + TestableSurfaceFlinger mFlinger; +}; + +class LayerMetadataBuilder { +public: + LayerMetadataBuilder(LayerMetadata layerMetadata = {}) : mLayerMetadata(layerMetadata) {} + + LayerMetadataBuilder& setInt32(uint32_t key, int32_t value) { + mLayerMetadata.setInt32(key, value); + return *this; + } + + LayerMetadata build() { return mLayerMetadata; } + +private: + LayerMetadata mLayerMetadata; +}; + +bool operator==(const LayerMetadata& lhs, const LayerMetadata& rhs) { + return lhs.mMap == rhs.mMap; +} + +std::ostream& operator<<(std::ostream& stream, const LayerMetadata& layerMetadata) { + stream << "LayerMetadata{"; + for (auto it = layerMetadata.mMap.cbegin(); it != layerMetadata.mMap.cend(); it++) { + if (it != layerMetadata.mMap.cbegin()) { + stream << ", "; + } + stream << layerMetadata.itemToString(it->first, ":"); + } + return stream << "}"; +} + +// Test that the snapshot's layer metadata is set. +TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesSnapshotMetadata) { + auto layerMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 1).build(); + auto layer = createLayer("layer", layerMetadata); + mFlinger.mutableDrawingState().layersSortedByZ.add(layer); + + mFlinger.updateLayerMetadataSnapshot(); + + ASSERT_EQ(layer->getLayerSnapshot()->layerMetadata, layerMetadata); +} + +// Test that snapshot layer metadata is set by merging the child's metadata on top of its +// parent's metadata. +TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, mergesSnapshotMetadata) { + auto layerAMetadata = LayerMetadataBuilder() + .setInt32(METADATA_OWNER_UID, 1) + .setInt32(METADATA_TASK_ID, 2) + .build(); + auto layerA = createLayer("parent", layerAMetadata); + auto layerBMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 3).build(); + auto layerB = createLayer("child", layerBMetadata); + layerA->addChild(layerB); + layerA->commitChildList(); + mFlinger.mutableDrawingState().layersSortedByZ.add(layerA); + + mFlinger.updateLayerMetadataSnapshot(); + + ASSERT_EQ(layerA->getLayerSnapshot()->layerMetadata, layerAMetadata); + auto expectedChildMetadata = + LayerMetadataBuilder(layerAMetadata).setInt32(METADATA_TASK_ID, 3).build(); + ASSERT_EQ(layerB->getLayerSnapshot()->layerMetadata, expectedChildMetadata); +} + +// Test that snapshot relative layer metadata is set to the parent's layer metadata merged on top of +// that parent's relative layer metadata. +TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesRelativeMetadata) { + auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 1).build(); + auto layerA = createLayer("relative-parent", layerAMetadata); + auto layerAHandle = layerA->getHandle(); + auto layerBMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 2).build(); + auto layerB = createLayer("relative-child", layerBMetadata); + layerB->setRelativeLayer(layerAHandle, 1); + mFlinger.mutableDrawingState().layersSortedByZ.add(layerA); + mFlinger.mutableDrawingState().layersSortedByZ.add(layerB); + + mFlinger.updateLayerMetadataSnapshot(); + + ASSERT_EQ(layerA->getLayerSnapshot()->relativeLayerMetadata, LayerMetadata{}); + ASSERT_EQ(layerB->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata); +} + +// Test that snapshot relative layer metadata is set correctly when a layer is interleaved within +// two other layers. +// +// Layer +// A +// / \ +// B D +// / +// C +// +// Z-order Relatives +// B <- D <- C +TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesRelativeMetadataInterleaved) { + auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_OWNER_UID, 1).build(); + auto layerA = createLayer("layer-a", layerAMetadata); + auto layerBMetadata = LayerMetadataBuilder() + .setInt32(METADATA_TASK_ID, 2) + .setInt32(METADATA_OWNER_PID, 3) + .build(); + auto layerB = createLayer("layer-b", layerBMetadata); + auto layerBHandle = layerB->getHandle(); + auto layerC = createLayer("layer-c", {}); + auto layerDMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 4).build(); + auto layerD = createLayer("layer-d", layerDMetadata); + auto layerDHandle = layerD->getHandle(); + layerB->addChild(layerC); + layerA->addChild(layerB); + layerA->addChild(layerD); + layerC->setRelativeLayer(layerDHandle, 1); + layerD->setRelativeLayer(layerBHandle, 1); + layerA->commitChildList(); + mFlinger.mutableDrawingState().layersSortedByZ.add(layerA); + + mFlinger.updateLayerMetadataSnapshot(); + + auto expectedLayerDRelativeMetadata = LayerMetadataBuilder() + // From layer A, parent of relative parent + .setInt32(METADATA_OWNER_UID, 1) + // From layer B, relative parent + .setInt32(METADATA_TASK_ID, 2) + .setInt32(METADATA_OWNER_PID, 3) + .build(); + ASSERT_EQ(layerD->getLayerSnapshot()->relativeLayerMetadata, expectedLayerDRelativeMetadata); + auto expectedLayerCRelativeMetadata = + LayerMetadataBuilder() + // From layer A, parent of relative parent + .setInt32(METADATA_OWNER_UID, 1) + // From layer B, relative parent of relative parent + .setInt32(METADATA_OWNER_PID, 3) + // From layer D, relative parent + .setInt32(METADATA_TASK_ID, 4) + .build(); + ASSERT_EQ(layerC->getLayerSnapshot()->relativeLayerMetadata, expectedLayerCRelativeMetadata); +} + +TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, + updatesRelativeMetadataMultipleRelativeChildren) { + auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_OWNER_UID, 1).build(); + auto layerA = createLayer("layer-a", layerAMetadata); + auto layerAHandle = layerA->getHandle(); + auto layerB = createLayer("layer-b", {}); + auto layerC = createLayer("layer-c", {}); + layerB->setRelativeLayer(layerAHandle, 1); + layerC->setRelativeLayer(layerAHandle, 2); + layerA->commitChildList(); + mFlinger.mutableDrawingState().layersSortedByZ.add(layerA); + mFlinger.mutableDrawingState().layersSortedByZ.add(layerB); + mFlinger.mutableDrawingState().layersSortedByZ.add(layerC); + + mFlinger.updateLayerMetadataSnapshot(); + + ASSERT_EQ(layerA->getLayerSnapshot()->relativeLayerMetadata, LayerMetadata{}); + ASSERT_EQ(layerB->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata); + ASSERT_EQ(layerC->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 4708572dc4..93e305960c 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -50,6 +50,7 @@ public: }); } + MOCK_METHOD(void, scheduleConfigure, (), (override)); MOCK_METHOD(void, scheduleFrame, (), (override)); MOCK_METHOD(void, postMessage, (sp<MessageHandler>&&), (override)); @@ -109,8 +110,9 @@ public: private: // ICompositor overrides: - bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } - void composite(nsecs_t, int64_t) override {} + void configure() override {} + bool commit(TimePoint, VsyncId, TimePoint) override { return false; } + void composite(TimePoint, VsyncId) override {} void sample() override {} }; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 283f9ca77b..13389a1ad3 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -27,13 +27,10 @@ #include <compositionengine/impl/Display.h> #include <compositionengine/impl/OutputLayerCompositionState.h> #include <compositionengine/mock/DisplaySurface.h> +#include <ftl/fake_guard.h> #include <gui/ScreenCaptureResults.h> -#include "BufferQueueLayer.h" -#include "BufferStateLayer.h" -#include "ContainerLayer.h" #include "DisplayDevice.h" -#include "EffectLayer.h" #include "FakeVsyncConfiguration.h" #include "FrameTracer/FrameTracer.h" #include "Layer.h" @@ -85,21 +82,21 @@ public: } sp<SurfaceInterceptor> createSurfaceInterceptor() override { - return new android::impl::SurfaceInterceptor(); + return sp<android::impl::SurfaceInterceptor>::make(); } sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override { - return new StartPropertySetThread(timestampPropertyValue); + return sp<StartPropertySetThread>::make(timestampPropertyValue); } sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override { - return new DisplayDevice(creationArgs); + return sp<DisplayDevice>::make(creationArgs); } sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) override { - return new GraphicBuffer(width, height, format, layerCount, usage, requestorName); + return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName); } void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, @@ -112,18 +109,6 @@ public: mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger); } - sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>& producer, - const sp<SurfaceFlinger>& flinger, - const wp<Layer>& layer) override { - return new MonitoredProducer(producer, flinger, layer); - } - - sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>& consumer, - renderengine::RenderEngine& renderEngine, - uint32_t textureName, Layer* layer) override { - return new BufferLayerConsumer(consumer, renderEngine, textureName, layer); - } - std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer>& producer) override { if (!mCreateNativeWindowSurface) return nullptr; @@ -134,19 +119,9 @@ public: return compositionengine::impl::createCompositionEngine(); } - sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override { - return nullptr; - } - - sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override { - return nullptr; - } - - sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; } + sp<Layer> createBufferStateLayer(const LayerCreationArgs&) override { return nullptr; } - sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override { - return nullptr; - } + sp<Layer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; } std::unique_ptr<FrameTracer> createFrameTracer() override { return std::make_unique<mock::FrameTracer>(); @@ -244,7 +219,7 @@ public: configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60); } - const auto fps = configs->getActiveMode()->getFps(); + const auto fps = FTL_FAKE_GUARD(kMainThreadContext, configs->getActiveMode().getFps()); mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps); mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); @@ -310,7 +285,7 @@ public: const sp<NativeHandle>& sidebandStream) { layer->mDrawingState.sidebandStream = sidebandStream; layer->mSidebandStream = sidebandStream; - layer->editCompositionState()->sidebandStream = sidebandStream; + layer->editLayerSnapshot()->sidebandStream = sidebandStream; } void setLayerCompositionType(const sp<Layer>& layer, @@ -338,25 +313,29 @@ public: * Forwarding for functions being tested */ - nsecs_t commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVSyncTime) { - mFlinger->commit(frameTime, vsyncId, expectedVSyncTime); + void configure() { mFlinger->configure(); } + + void configureAndCommit() { + configure(); + commitTransactionsLocked(eDisplayTransactionNeeded); + } + + TimePoint commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) { + mFlinger->commit(frameTime, vsyncId, expectedVsyncTime); return frameTime; } - nsecs_t commit(nsecs_t frameTime, int64_t vsyncId) { - std::chrono::nanoseconds period = 10ms; - return commit(frameTime, vsyncId, frameTime + period.count()); + TimePoint commit(TimePoint frameTime, VsyncId vsyncId) { + return commit(frameTime, vsyncId, frameTime + Period(10ms)); } - nsecs_t commit() { - const nsecs_t now = systemTime(); - const nsecs_t expectedVsyncTime = now + 10'000'000; - return commit(now, kVsyncId, expectedVsyncTime); + TimePoint commit() { + const TimePoint frameTime = scheduler::SchedulerClock::now(); + return commit(frameTime, kVsyncId); } - void commitAndComposite(const nsecs_t frameTime, const int64_t vsyncId, - const nsecs_t expectedVsyncTime) { - mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), kVsyncId); + void commitAndComposite(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) { + mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), vsyncId); } void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); } @@ -386,9 +365,10 @@ public: dispSurface, producer); } - auto commitTransactionsLocked(uint32_t transactionFlags) { + void commitTransactionsLocked(uint32_t transactionFlags) { Mutex::Autolock lock(mFlinger->mStateLock); - return mFlinger->commitTransactionsLocked(transactionFlags); + ftl::FakeGuard guard(kMainThreadContext); + mFlinger->commitTransactionsLocked(transactionFlags); } void onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { @@ -438,7 +418,7 @@ public: return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } - auto& getTransactionQueue() { return mFlinger->mTransactionQueue; } + auto& getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; } auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; } @@ -454,13 +434,15 @@ public: listenerCallbacks, transactionId); } - auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); }; + auto flushTransactionQueues() { + return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId)); + } auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { return mFlinger->onTransact(code, data, reply, flags); } - auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); } + auto getGpuContextPriority() { return mFlinger->getGpuContextPriority(); } auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { @@ -479,6 +461,7 @@ public: void onActiveDisplayChanged(const sp<DisplayDevice>& activeDisplay) { Mutex::Autolock lock(mFlinger->mStateLock); + ftl::FakeGuard guard(kMainThreadContext); mFlinger->onActiveDisplayChangedLocked(activeDisplay); } @@ -494,20 +477,18 @@ public: return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId); } + void updateLayerMetadataSnapshot() { mFlinger->updateLayerMetadataSnapshot(); } + /* ------------------------------------------------------------------------ * Read-only access to private data to assert post-conditions. */ - const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; } - const auto& getHasPoweredOff() const { return mFlinger->mHasPoweredOff; } const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; } auto& getHwComposer() const { return static_cast<impl::HWComposer&>(mFlinger->getHwComposer()); } auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); } - const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; } - mock::FrameTracer* getFrameTracer() const { return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get()); } @@ -522,22 +503,25 @@ public: */ const auto& displays() const { return mFlinger->mDisplays; } + const auto& physicalDisplays() const { return mFlinger->mPhysicalDisplays; } const auto& currentState() const { return mFlinger->mCurrentState; } const auto& drawingState() const { return mFlinger->mDrawingState; } const auto& transactionFlags() const { return mFlinger->mTransactionFlags; } + const auto& hwcPhysicalDisplayIdMap() const { return getHwComposer().mPhysicalDisplayIdMap; } + const auto& hwcDisplayData() const { return getHwComposer().mDisplayData; } auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; } auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } auto& mutableDisplays() { return mFlinger->mDisplays; } + auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; } auto& mutableInterceptor() { return mFlinger->mInterceptor; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } - auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; } auto& mutableTexturePool() { return mFlinger->mTexturePool; } auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } @@ -740,16 +724,22 @@ public: std::optional<ui::DisplayConnectionType> connectionType, std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary) : mFlinger(flinger), - mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(), - mDisplayToken, display), + mCreationArgs(flinger.mFlinger, flinger.mFlinger->getHwComposer(), mDisplayToken, + display), + mConnectionType(connectionType), mHwcDisplayId(hwcDisplayId) { - mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; mCreationArgs.initialPowerMode = hal::PowerMode::ON; } sp<IBinder> token() const { return mDisplayToken; } + auto physicalDisplay() const { + return ftl::Optional(mCreationArgs.compositionDisplay->getDisplayId()) + .and_then(&PhysicalDisplayId::tryCast) + .and_then(display::getPhysicalDisplay(mFlinger.physicalDisplays())); + } + DisplayDeviceState& mutableDrawingDisplayState() { return mFlinger.mutableDrawingState().displays.editValueFor(mDisplayToken); } @@ -777,7 +767,7 @@ public: // the `configs` parameter in favor of an alternative setRefreshRateConfigs API. auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId, std::shared_ptr<scheduler::RefreshRateConfigs> configs = nullptr) { - mCreationArgs.supportedModes = std::move(modes); + mDisplayModes = std::move(modes); mCreationArgs.activeModeId = activeModeId; mCreationArgs.refreshRateConfigs = std::move(configs); return *this; @@ -823,7 +813,7 @@ public: sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS { const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); - auto& modes = mCreationArgs.supportedModes; + auto& modes = mDisplayModes; auto& activeModeId = mCreationArgs.activeModeId; if (displayId && !mCreationArgs.refreshRateConfigs) { @@ -851,8 +841,13 @@ public: } } + sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs); + mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display); + DisplayDeviceState state; - if (const auto type = mCreationArgs.connectionType) { + state.isSecure = mCreationArgs.isSecure; + + if (mConnectionType) { LOG_ALWAYS_FATAL_IF(!displayId); const auto physicalId = PhysicalDisplayId::tryCast(*displayId); LOG_ALWAYS_FATAL_IF(!physicalId); @@ -862,41 +857,35 @@ public: LOG_ALWAYS_FATAL_IF(!activeMode); state.physical = {.id = *physicalId, - .type = *type, .hwcDisplayId = *mHwcDisplayId, - .deviceProductInfo = {}, - .supportedModes = modes, .activeMode = activeMode->get()}; - } - state.isSecure = mCreationArgs.isSecure; + const auto it = mFlinger.mutablePhysicalDisplays() + .emplace_or_replace(*physicalId, mDisplayToken, *physicalId, + *mConnectionType, std::move(modes), + std::nullopt) + .first; - sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs); - if (!display->isVirtual()) { - display->setActiveMode(activeModeId); + display->setActiveMode(activeModeId, it->second.snapshot()); } - mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display); mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); - if (const auto& physical = state.physical) { - mFlinger.mutablePhysicalDisplayTokens().emplace_or_replace(physical->id, - mDisplayToken); - } - return display; } private: TestableSurfaceFlinger& mFlinger; - sp<BBinder> mDisplayToken = new BBinder(); + sp<BBinder> mDisplayToken = sp<BBinder>::make(); DisplayDeviceCreationArgs mCreationArgs; + DisplayModes mDisplayModes; + const std::optional<ui::DisplayConnectionType> mConnectionType; const std::optional<hal::HWDisplayId> mHwcDisplayId; }; private: - constexpr static int64_t kVsyncId = 123; + static constexpr VsyncId kVsyncId{123}; surfaceflinger::test::Factory mFactory; sp<SurfaceFlinger> mFlinger; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index ded75318ed..b493d113b7 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -60,13 +60,15 @@ public: EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); EXPECT_CALL(*mVSyncTracker, currentPeriod()) @@ -107,22 +109,20 @@ public: EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime); } - void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows, - int64_t desiredPresentTime, bool isAutoTimestamp, - const FrameTimelineInfo& frameTimelineInfo) { + void setupSingle(TransactionInfo& transaction, uint32_t flags, int64_t desiredPresentTime, + bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo) { mTransactionNumber++; transaction.flags |= flags; // ISurfaceComposer::eSynchronous; - transaction.inputWindowCommands.syncInputWindows = syncInputWindows; transaction.desiredPresentTime = desiredPresentTime; transaction.isAutoTimestamp = isAutoTimestamp; transaction.frameTimelineInfo = frameTimelineInfo; } - void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + void NotPlacedOnTransactionQueue(uint32_t flags) { + ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty()); EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); TransactionInfo transaction; - setupSingle(transaction, flags, syncInputWindows, + setupSingle(transaction, flags, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, FrameTimelineInfo{}); nsecs_t applicationTime = systemTime(); @@ -133,31 +133,29 @@ public: transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, transaction.id); - // If transaction is synchronous or syncs input windows, SF - // applyTransactionState should time out (5s) wating for SF to commit - // the transaction or to receive a signal that syncInputWindows has - // completed. If this is animation, it should not time out waiting. + // If transaction is synchronous, SF applyTransactionState should time out (5s) wating for + // SF to commit the transaction. If this is animation, it should not time out waiting. nsecs_t returnedTime = systemTime(); - if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout()); } else { EXPECT_LE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout()); } // Each transaction should have been placed on the transaction queue - auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(1u, transactionQueue.size()); + auto& transactionQueue = mFlinger.getTransactionQueue(); + EXPECT_FALSE(transactionQueue.isEmpty()); } - void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + void PlaceOnTransactionQueue(uint32_t flags) { + ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty()); EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); // first check will see desired present time has not passed, // but afterwards it will look like the desired present time has passed nsecs_t time = systemTime(); TransactionInfo transaction; - setupSingle(transaction, flags, syncInputWindows, - /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transaction, flags, /*desiredPresentTime*/ time + s2ns(1), false, + FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, @@ -167,7 +165,7 @@ public: transaction.id); nsecs_t returnedTime = systemTime(); - if ((flags & ISurfaceComposer::eSynchronous) || syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout()); } else { @@ -175,29 +173,25 @@ public: applicationSentTime + mFlinger.getAnimationTransactionTimeout()); } // This transaction should have been placed on the transaction queue - auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(1u, transactionQueue.size()); + auto& transactionQueue = mFlinger.getTransactionQueue(); + EXPECT_FALSE(transactionQueue.isEmpty()); } - void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + void BlockedByPriorTransaction(uint32_t flags) { + ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty()); nsecs_t time = systemTime(); - if (!syncInputWindows) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2); - } else { - EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); - } + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2); + // transaction that should go on the pending thread TransactionInfo transactionA; - setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ time + s2ns(1), false, + FrameTimelineInfo{}); // transaction that would not have gone on the pending thread if not // blocked TransactionInfo transactionB; - setupSingle(transactionB, flags, syncInputWindows, - /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - FrameTimelineInfo{}); + setupSingle(transactionB, flags, /*desiredPresentTime*/ systemTime(), + /*isAutoTimestamp*/ true, FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, @@ -226,8 +220,7 @@ public: // if this is an animation, this thread should be blocked for 5s // in setTransactionState waiting for transactionA to flush. Otherwise, // the transaction should be placed on the pending queue - if (flags & (ISurfaceComposer::eSynchronous) || - syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout()); } else { @@ -248,13 +241,13 @@ public: int mTransactionNumber = 0; }; -TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); +TEST_F(TransactionApplicationTest, AddToPendingQueue) { + ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty()); EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); TransactionInfo transactionA; // transaction to go on pending queue - setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false, + FrameTimelineInfo{}); mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, @@ -262,10 +255,27 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { mHasListenerCallbacks, mCallbacks, transactionA.id); auto& transactionQueue = mFlinger.getTransactionQueue(); - ASSERT_EQ(1u, transactionQueue.size()); + ASSERT_FALSE(transactionQueue.isEmpty()); - auto& transactionState = transactionQueue.front(); + auto transactionState = transactionQueue.pop().value(); checkEqual(transactionA, transactionState); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { + ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty()); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); + + TransactionInfo transactionA; // transaction to go on pending queue + setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false, + FrameTimelineInfo{}); + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, + transactionA.displays, transactionA.flags, transactionA.applyToken, + transactionA.inputWindowCommands, transactionA.desiredPresentTime, + transactionA.isAutoTimestamp, transactionA.uncacheBuffer, + mHasListenerCallbacks, mCallbacks, transactionA.id); + + auto& transactionQueue = mFlinger.getTransactionQueue(); + ASSERT_FALSE(transactionQueue.isEmpty()); // because flushing uses the cached expected present time, we send an empty // transaction here (sending a null applyToken to fake it as from a @@ -281,35 +291,27 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { // passed mFlinger.flushTransactionQueues(); - EXPECT_EQ(0u, transactionQueue.size()); + EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty()); } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) { - NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); + NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) { - NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true); + NotPlacedOnTransactionQueue(/*flags*/ 0); } TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) { - PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); + PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) { - PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true); + PlaceOnTransactionQueue(/*flags*/ 0); } TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) { - BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); -} - -TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) { - BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); -} - -TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) { - BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true); + BlockedByPriorTransaction(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, FromHandle) { @@ -323,7 +325,9 @@ public: void TearDown() override { // Clear all transaction queues to release all transactions we sent // in the tests. Otherwise, gmock complains about memory leaks. - mFlinger.getTransactionQueue().clear(); + while (!mFlinger.getTransactionQueue().isEmpty()) { + mFlinger.getTransactionQueue().pop(); + } mFlinger.getPendingTransactionQueue().clear(); mFlinger.getTransactionCommittedSignals().clear(); mFlinger.commitTransactionsLocked(eTransactionMask); @@ -343,8 +347,7 @@ public: state.state.bufferData->acquireFence = std::move(fence); state.state.layerId = layerId; state.state.surface = - sp<BufferStateLayer>::make( - LayerCreationArgs(mFlinger.flinger(), nullptr, "TestLayer", 0, {})) + sp<Layer>::make(LayerCreationArgs(mFlinger.flinger(), nullptr, "TestLayer", 0, {})) ->getHandle(); state.state.bufferData->flags = BufferData::BufferDataChange::fenceChanged; @@ -359,13 +362,11 @@ public: const std::vector<ComposerState>& states) { TransactionInfo transaction; const uint32_t kFlags = ISurfaceComposer::eSynchronous; - const bool kSyncInputWindows = false; const nsecs_t kDesiredPresentTime = systemTime(); const bool kIsAutoTimestamp = true; const auto kFrameTimelineInfo = FrameTimelineInfo{}; - setupSingle(transaction, kFlags, kSyncInputWindows, kDesiredPresentTime, kIsAutoTimestamp, - kFrameTimelineInfo); + setupSingle(transaction, kFlags, kDesiredPresentTime, kIsAutoTimestamp, kFrameTimelineInfo); transaction.applyToken = applyToken; for (const auto& state : states) { transaction.states.push_back(state); @@ -377,7 +378,7 @@ public: void setTransactionStates(const std::vector<TransactionInfo>& transactions, size_t expectedTransactionsApplied, size_t expectedTransactionsPending) { - EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty()); EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); for (const auto& transaction : transactions) { @@ -389,7 +390,7 @@ public: mHasListenerCallbacks, mCallbacks, transaction.id); } mFlinger.flushTransactionQueues(); - EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty()); EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size()); EXPECT_EQ(expectedTransactionsApplied, mFlinger.getTransactionCommittedSignals().size()); } diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index 5364630400..1173d1c876 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -56,11 +56,11 @@ public: ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } - sp<BufferStateLayer> createBufferStateLayer() { + sp<Layer> createLayer() { sp<Client> client; LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, LayerMetadata()); - return new BufferStateLayer(args); + return sp<Layer>::make(args); } void commitTransaction(Layer* layer) { @@ -74,13 +74,15 @@ public: EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); @@ -99,9 +101,9 @@ public: FenceToFenceTimeMap fenceFactory; void BLASTTransactionSendsFrameTracerEvents() { - sp<BufferStateLayer> layer = createBufferStateLayer(); + sp<Layer> layer = createLayer(); - sp<Fence> fence(new Fence()); + sp<Fence> fence(sp<Fence>::make()); int32_t layerId = layer->getSequence(); uint64_t bufferId = 42; uint64_t frameNumber = 5; @@ -127,7 +129,6 @@ public: dequeueTime, FrameTimelineInfo{}); commitTransaction(layer.get()); - bool computeVisisbleRegions; nsecs_t latchTime = 25; EXPECT_CALL(*mFlinger.getFrameTracer(), traceFence(layerId, bufferId, frameNumber, _, @@ -135,7 +136,7 @@ public: EXPECT_CALL(*mFlinger.getFrameTracer(), traceTimestamp(layerId, bufferId, frameNumber, latchTime, FrameTracer::FrameEvent::LATCH, /*duration*/ 0)); - layer->updateTexImage(computeVisisbleRegions, latchTime, /*expectedPresentTime*/ 0); + layer->updateTexImage(latchTime); auto glDoneFence = fenceFactory.createFenceTimeForTest(fence); auto presentFence = fenceFactory.createFenceTimeForTest(fence); diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp index f5e3b77ca6..1f011bee0d 100644 --- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp @@ -27,8 +27,8 @@ using namespace android::surfaceflinger; namespace android { TEST(TransactionProtoParserTest, parse) { - const sp<IBinder> layerHandle = new BBinder(); - const sp<IBinder> displayHandle = new BBinder(); + const sp<IBinder> layerHandle = sp<BBinder>::make(); + const sp<IBinder> displayHandle = sp<BBinder>::make(); TransactionState t1; t1.originPid = 1; t1.originUid = 2; @@ -49,8 +49,7 @@ TEST(TransactionProtoParserTest, parse) { ComposerState s; if (i == 1) { layer.parentSurfaceControlForChild = - new SurfaceControl(SurfaceComposerClient::getDefault(), layerHandle, nullptr, - 42); + sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), layerHandle, 42); } s.state = layer; t1.states.add(s); diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 5bb4c92a8e..ae03db43a7 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -56,11 +56,10 @@ public: ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } - sp<BufferStateLayer> createBufferStateLayer() { + sp<Layer> createLayer() { sp<Client> client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, - LayerMetadata()); - return new BufferStateLayer(args); + LayerCreationArgs args(mFlinger.flinger(), client, "layer", 0, LayerMetadata()); + return sp<Layer>::make(args); } void commitTransaction(Layer* layer) { @@ -74,13 +73,15 @@ public: EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); @@ -99,9 +100,11 @@ public: FenceToFenceTimeMap fenceFactory; void PresentedSurfaceFrameForBufferlessTransaction() { - sp<BufferStateLayer> layer = createBufferStateLayer(); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); + sp<Layer> layer = createLayer(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10); EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_TRUE(layer->mDrawingState.bufferSurfaceFrameTX == nullptr); const auto surfaceFrame = layer->mDrawingState.bufferlessSurfaceFramesTX.at(/*token*/ 1); @@ -112,8 +115,8 @@ public: } void PresentedSurfaceFrameForBufferTransaction() { - sp<BufferStateLayer> layer = createBufferStateLayer(); - sp<Fence> fence(new Fence()); + sp<Layer> layer = createLayer(); + sp<Fence> fence(sp<Fence>::make()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); BufferData bufferData; bufferData.acquireFence = fence; @@ -125,8 +128,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo); acquireFence->signalForTest(12); commitTransaction(layer.get()); @@ -136,8 +141,7 @@ public: // Buffers are presented only at latch time. EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState()); - bool computeVisisbleRegions; - layer->updateTexImage(computeVisisbleRegions, 15, 0); + layer->updateTexImage(15); EXPECT_EQ(1, surfaceFrame->getToken()); EXPECT_EQ(true, surfaceFrame->getIsBuffer()); @@ -145,9 +149,9 @@ public: } void DroppedSurfaceFrameForBufferTransaction() { - sp<BufferStateLayer> layer = createBufferStateLayer(); + sp<Layer> layer = createLayer(); - sp<Fence> fence1(new Fence()); + sp<Fence> fence1(sp<Fence>::make()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); BufferData bufferData; bufferData.acquireFence = fence1; @@ -159,13 +163,15 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; - sp<Fence> fence2(new Fence()); + sp<Fence> fence2(sp<Fence>::make()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); nsecs_t start = systemTime(); bufferData.acquireFence = fence2; @@ -177,8 +183,7 @@ public: 2ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo); nsecs_t end = systemTime(); acquireFence2->signalForTest(12); @@ -187,8 +192,7 @@ public: const auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; commitTransaction(layer.get()); - bool computeVisisbleRegions; - layer->updateTexImage(computeVisisbleRegions, 15, 0); + layer->updateTexImage(15); EXPECT_EQ(1, droppedSurfaceFrame->getToken()); EXPECT_EQ(true, droppedSurfaceFrame->getIsBuffer()); @@ -203,15 +207,17 @@ public: } void BufferlessSurfaceFramePromotedToBufferSurfaceFrame() { - sp<BufferStateLayer> layer = createBufferStateLayer(); + sp<Layer> layer = createLayer(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10); EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); - sp<Fence> fence(new Fence()); + sp<Fence> fence(sp<Fence>::make()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); BufferData bufferData; bufferData.acquireFence = fence; @@ -223,8 +229,7 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo); acquireFence->signalForTest(12); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); @@ -237,15 +242,14 @@ public: // Buffers are presented only at latch time. EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState()); - bool computeVisisbleRegions; - layer->updateTexImage(computeVisisbleRegions, 15, 0); + layer->updateTexImage(15); EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState()); } void BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists() { - sp<BufferStateLayer> layer = createBufferStateLayer(); - sp<Fence> fence(new Fence()); + sp<Layer> layer = createLayer(); + sp<Fence> fence(sp<Fence>::make()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); BufferData bufferData; bufferData.acquireFence = fence; @@ -257,33 +261,38 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); } void MultipleSurfaceFramesPresentedTogether() { - sp<BufferStateLayer> layer = createBufferStateLayer(); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); + sp<Layer> layer = createLayer(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10); EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto bufferlessSurfaceFrame1 = layer->mDrawingState.bufferlessSurfaceFramesTX.at(/*token*/ 1); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 4, /*inputEventId*/ 0}, - 10); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = 4; + ftInfo2.inputEventId = 0; + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo2, 10); EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto bufferlessSurfaceFrame2 = layer->mDrawingState.bufferlessSurfaceFramesTX[4]; - sp<Fence> fence(new Fence()); + sp<Fence> fence(sp<Fence>::make()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); BufferData bufferData; bufferData.acquireFence = fence; @@ -295,8 +304,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 3, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo3; + ftInfo3.vsyncId = 3; + ftInfo3.inputEventId = 0; + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo3); EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX; @@ -318,16 +329,15 @@ public: // Buffers are presented only at latch time. EXPECT_EQ(PresentState::Unknown, bufferSurfaceFrameTX->getPresentState()); - bool computeVisisbleRegions; - layer->updateTexImage(computeVisisbleRegions, 15, 0); + layer->updateTexImage(15); EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState()); } void PendingSurfaceFramesRemovedAfterClassification() { - sp<BufferStateLayer> layer = createBufferStateLayer(); + sp<Layer> layer = createLayer(); - sp<Fence> fence1(new Fence()); + sp<Fence> fence1(sp<Fence>::make()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); BufferData bufferData; bufferData.acquireFence = fence1; @@ -339,12 +349,14 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; - sp<Fence> fence2(new Fence()); + sp<Fence> fence2(sp<Fence>::make()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); bufferData.acquireFence = fence2; bufferData.frameNumber = 1; @@ -355,16 +367,14 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo); acquireFence2->signalForTest(12); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; commitTransaction(layer.get()); - bool computeVisisbleRegions; - layer->updateTexImage(computeVisisbleRegions, 15, 0); + layer->updateTexImage(15); // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in // pendingJankClassifications. @@ -377,9 +387,9 @@ public: } void BufferSurfaceFrame_ReplaceValidTokenBufferWithInvalidTokenBuffer() { - sp<BufferStateLayer> layer = createBufferStateLayer(); + sp<Layer> layer = createLayer(); - sp<Fence> fence1(new Fence()); + sp<Fence> fence1(sp<Fence>::make()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); BufferData bufferData; bufferData.acquireFence = fence1; @@ -391,13 +401,15 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX; - sp<Fence> fence2(new Fence()); + sp<Fence> fence2(sp<Fence>::make()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); auto dropStartTime1 = systemTime(); bufferData.acquireFence = fence2; @@ -409,14 +421,16 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfoInv; + ftInfoInv.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID; + ftInfoInv.inputEventId = 0; + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfoInv); auto dropEndTime1 = systemTime(); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame2 = layer->mDrawingState.bufferSurfaceFrameTX; - sp<Fence> fence3(new Fence()); + sp<Fence> fence3(sp<Fence>::make()); auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3); auto dropStartTime2 = systemTime(); bufferData.acquireFence = fence3; @@ -428,8 +442,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 2, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = 2; + ftInfo2.inputEventId = 0; + layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt, ftInfo2); auto dropEndTime2 = systemTime(); acquireFence3->signalForTest(12); @@ -438,8 +454,7 @@ public: const auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; commitTransaction(layer.get()); - bool computeVisisbleRegions; - layer->updateTexImage(computeVisisbleRegions, 15, 0); + layer->updateTexImage(15); EXPECT_EQ(1, droppedSurfaceFrame1->getToken()); EXPECT_EQ(true, droppedSurfaceFrame1->getIsBuffer()); @@ -461,11 +476,11 @@ public: } void MultipleCommitsBeforeLatch() { - sp<BufferStateLayer> layer = createBufferStateLayer(); + sp<Layer> layer = createLayer(); uint32_t surfaceFramesPendingClassification = 0; std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> bufferlessSurfaceFrames; for (int i = 0; i < 10; i += 2) { - sp<Fence> fence(new Fence()); + sp<Fence> fence(sp<Fence>::make()); BufferData bufferData; bufferData.acquireFence = fence; bufferData.frameNumber = 1; @@ -476,11 +491,14 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, - /*inputEventId*/ 0}, - 10); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = 2; + ftInfo2.inputEventId = 0; + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo2, 10); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); auto& bufferlessSurfaceFrame = @@ -494,8 +512,7 @@ public: } auto presentedBufferSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; - bool computeVisisbleRegions; - layer->updateTexImage(computeVisisbleRegions, 15, 0); + layer->updateTexImage(15); // BufferlessSurfaceFrames are immediately set to presented and added to the DisplayFrame. // Since we don't have access to DisplayFrame here, trigger an onPresent directly. for (auto& surfaceFrame : bufferlessSurfaceFrames) { diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp index 61b72a0b9b..2dbcfbdb18 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp @@ -101,10 +101,10 @@ protected: void SetUp() override { // add layers mTracing.setBufferSize(SMALL_BUFFER_SIZE); - const sp<IBinder> fakeLayerHandle = new BBinder(); + const sp<IBinder> fakeLayerHandle = sp<BBinder>::make(); mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent", 123 /* flags */, -1 /* parentId */); - const sp<IBinder> fakeChildLayerHandle = new BBinder(); + const sp<IBinder> fakeChildLayerHandle = sp<BBinder>::make(); mTracing.onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child", 456 /* flags */, mParentLayerId); @@ -127,6 +127,8 @@ protected: std::vector<TransactionState> transactions; transactions.emplace_back(transaction); VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId; + mTracing.onLayerAddedToDrawingState(mParentLayerId, VSYNC_ID_FIRST_LAYER_CHANGE); + mTracing.onLayerAddedToDrawingState(mChildLayerId, VSYNC_ID_FIRST_LAYER_CHANGE); mTracing.addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE); flush(VSYNC_ID_FIRST_LAYER_CHANGE); } @@ -232,12 +234,14 @@ protected: void SetUp() override { // add layers mTracing.setBufferSize(SMALL_BUFFER_SIZE); - const sp<IBinder> fakeLayerHandle = new BBinder(); + const sp<IBinder> fakeLayerHandle = sp<BBinder>::make(); mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer", 123 /* flags */, -1 /* parentId */); - const sp<IBinder> fakeMirrorLayerHandle = new BBinder(); + const sp<IBinder> fakeMirrorLayerHandle = sp<BBinder>::make(); mTracing.onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror", mLayerId); + mTracing.onLayerAddedToDrawingState(mLayerId, mVsyncId); + mTracing.onLayerAddedToDrawingState(mMirrorLayerId, mVsyncId); // add some layer transaction { @@ -257,7 +261,7 @@ protected: std::vector<TransactionState> transactions; transactions.emplace_back(transaction); - mTracing.addCommittedTransactions(transactions, ++mVsyncId); + mTracing.addCommittedTransactions(transactions, mVsyncId); flush(mVsyncId); } } diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp index 15fea9c6b2..da87f1db17 100644 --- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp @@ -22,7 +22,6 @@ #include <gtest/gtest.h> #include <gui/LayerMetadata.h> -#include "BufferStateLayer.h" #include "TestableSurfaceFlinger.h" #include "TunnelModeEnabledReporter.h" #include "mock/DisplayHardware/MockComposer.h" @@ -64,7 +63,7 @@ protected: void setupScheduler(); void setupComposer(uint32_t virtualDisplayCount); - sp<BufferStateLayer> createBufferStateLayer(LayerMetadata metadata); + sp<Layer> createBufferStateLayer(LayerMetadata metadata); TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; @@ -95,11 +94,10 @@ TunnelModeEnabledReporterTest::~TunnelModeEnabledReporterTest() { mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener); } -sp<BufferStateLayer> TunnelModeEnabledReporterTest::createBufferStateLayer( - LayerMetadata metadata = {}) { +sp<Layer> TunnelModeEnabledReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) { sp<Client> client; LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata); - return new BufferStateLayer(args); + return sp<Layer>::make(args); } void TunnelModeEnabledReporterTest::setupScheduler() { @@ -108,13 +106,15 @@ void TunnelModeEnabledReporterTest::setupScheduler() { EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, - ResyncCallback()))); + .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index b7f968dc17..f66075362e 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -44,6 +44,8 @@ public: ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_)) .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime)); ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true)); + ON_CALL(*this, currentPeriod()) + .WillByDefault(Invoke(this, &MockVSyncTracker::getCurrentPeriod)); } MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t)); @@ -62,6 +64,8 @@ public: return (timePoint - (timePoint % mPeriod) + mPeriod); } + nsecs_t getCurrentPeriod() const { return mPeriod; } + protected: nsecs_t const mPeriod; }; @@ -393,6 +397,43 @@ TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) { EXPECT_THAT(cb1.mCalls[0], Eq(1063)); } +TEST_F(VSyncDispatchTimerQueueTest, noCloseCallbacksAfterPeriodChange) { + EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_)) + .Times(4) + .WillOnce(Return(1000)) + .WillOnce(Return(2000)) + .WillOnce(Return(2500)) + .WillOnce(Return(4000)); + + Sequence seq; + EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq); + EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq); + EXPECT_CALL(mMockClock, alarmAt(_, 3900)).InSequence(seq); + + CountingCallback cb(mDispatch); + + mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 0}); + + advanceToNextCallback(); + + ASSERT_THAT(cb.mCalls.size(), Eq(1)); + EXPECT_THAT(cb.mCalls[0], Eq(1000)); + + mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + + advanceToNextCallback(); + + ASSERT_THAT(cb.mCalls.size(), Eq(2)); + EXPECT_THAT(cb.mCalls[1], Eq(2000)); + + mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}); + + advanceToNextCallback(); + + ASSERT_THAT(cb.mCalls.size(), Eq(3)); + EXPECT_THAT(cb.mCalls[2], Eq(4000)); +} + TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) { EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_)) .Times(4) diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index 30a3f9a4a7..a35ff96815 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -77,12 +77,12 @@ struct MockVSyncDispatch : VSyncDispatch { }; std::shared_ptr<android::FenceTime> generateInvalidFence() { - sp<Fence> fence = new Fence(); + sp<Fence> fence = sp<Fence>::make(); return std::make_shared<android::FenceTime>(fence); } std::shared_ptr<android::FenceTime> generatePendingFence() { - sp<Fence> fence = new Fence(dup(fileno(tmpfile()))); + sp<Fence> fence = sp<Fence>::make(dup(fileno(tmpfile()))); return std::make_shared<android::FenceTime>(fence); } @@ -92,7 +92,7 @@ void signalFenceWithTime(std::shared_ptr<android::FenceTime> const& fence, nsecs } std::shared_ptr<android::FenceTime> generateSignalledFenceWithTime(nsecs_t time) { - sp<Fence> fence = new Fence(dup(fileno(tmpfile()))); + sp<Fence> fence = sp<Fence>::make(dup(fileno(tmpfile()))); std::shared_ptr<android::FenceTime> ft = std::make_shared<android::FenceTime>(fence); signalFenceWithTime(ft, time); return ft; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h index 657ced3d08..c2c3d77364 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h @@ -17,6 +17,7 @@ #pragma once #include <gmock/gmock.h> +#include <scheduler/Time.h> #include "DisplayHardware/PowerAdvisor.h" @@ -42,8 +43,8 @@ public: MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds), (override)); MOCK_METHOD(bool, startPowerHintSession, (), (override)); - MOCK_METHOD(void, setTargetWorkDuration, (nsecs_t targetDuration), (override)); - MOCK_METHOD(void, sendActualWorkDuration, (nsecs_t actualDuration, nsecs_t timestamp), + MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override)); + MOCK_METHOD(void, sendActualWorkDuration, (Duration actualDuration, TimePoint timestamp), (override)); MOCK_METHOD(bool, shouldReconnectHAL, (), (override)); }; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h index aede250db5..fb1b3946a4 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h @@ -36,7 +36,7 @@ public: MOCK_METHOD(bool, usePowerHintSession, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); - MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDuration), (override)); + MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override)); MOCK_METHOD(void, sendActualWorkDuration, (), (override)); MOCK_METHOD(void, sendPredictedWorkDuration, (), (override)); MOCK_METHOD(void, enablePowerHint, (bool enabled), (override)); @@ -44,25 +44,24 @@ public: MOCK_METHOD(void, setGpuFenceTime, (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override)); MOCK_METHOD(void, setHwcValidateTiming, - (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime), + (DisplayId displayId, TimePoint validateStartTime, TimePoint validateEndTime), (override)); MOCK_METHOD(void, setHwcPresentTiming, - (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime), + (DisplayId displayId, TimePoint presentStartTime, TimePoint presentEndTime), (override)); MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override)); MOCK_METHOD(void, setRequiresClientComposition, (DisplayId displayId, bool requiresClientComposition), (override)); - MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override)); - MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime), + MOCK_METHOD(void, setExpectedPresentTime, (TimePoint expectedPresentTime), (override)); + MOCK_METHOD(void, setSfPresentTiming, (TimePoint presentFenceTime, TimePoint presentEndTime), (override)); MOCK_METHOD(void, setHwcPresentDelayedTime, - (DisplayId displayId, - std::chrono::steady_clock::time_point earliestFrameStartTime)); - MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override)); - MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override)); - MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override)); + (DisplayId displayId, TimePoint earliestFrameStartTime)); + MOCK_METHOD(void, setFrameDelay, (Duration frameDelayDuration), (override)); + MOCK_METHOD(void, setCommitStart, (TimePoint commitStartTime), (override)); + MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override)); MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override)); - MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override)); + MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); }; } // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index c5ca86a651..ded68069cb 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -24,12 +24,13 @@ namespace android::mock { class EventThread : public android::EventThread { public: + static constexpr auto kCallingUid = static_cast<uid_t>(0); + EventThread(); ~EventThread() override; MOCK_CONST_METHOD2(createEventConnection, - sp<EventThreadConnection>(ResyncCallback, - ISurfaceComposer::EventRegistrationFlags)); + sp<EventThreadConnection>(ResyncCallback, EventRegistrationFlags)); MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index 0840a2f77c..0d94f4c644 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -18,14 +18,15 @@ #include <gmock/gmock.h> -#include "Layer.h" - namespace android::mock { class MockLayer : public Layer { public: MockLayer(SurfaceFlinger* flinger, std::string name) - : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {} + : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) { + EXPECT_CALL(*this, getDefaultFrameRateCompatibility()) + .WillOnce(testing::Return(scheduler::LayerInfo::FrameRateCompatibility::Default)); + } explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} MOCK_CONST_METHOD0(getType, const char*()); @@ -33,6 +34,8 @@ public: MOCK_CONST_METHOD0(isVisible, bool()); MOCK_METHOD0(createClone, sp<Layer>()); MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); + MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, + scheduler::LayerInfo::FrameRateCompatibility()); MOCK_CONST_METHOD0(getOwnerUid, uid_t()); MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace()); }; diff --git a/services/surfaceflinger/tests/utils/ColorUtils.h b/services/surfaceflinger/tests/utils/ColorUtils.h index 07916b60a7..38c422a26d 100644 --- a/services/surfaceflinger/tests/utils/ColorUtils.h +++ b/services/surfaceflinger/tests/utils/ColorUtils.h @@ -33,6 +33,10 @@ struct Color { static const Color WHITE; static const Color BLACK; static const Color TRANSPARENT; + + half3 toHalf3() { return half3{r / 255.0f, g / 255.0f, b / 255.0f}; } + + half4 toHalf4() { return half4{r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f}; } }; const Color Color::RED{255, 0, 0, 255}; @@ -81,6 +85,14 @@ public: } color = ret; } + + static half3 toHalf3(const Color& color) { + return half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}; + } + + static half4 toHalf4(const Color& color) { + return half4{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f}; + } }; } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index f879430db0..224868c014 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -15,8 +15,10 @@ */ #pragma once +#include <gui/AidlStatusUtil.h> #include <gui/SyncScreenCaptureListener.h> #include <private/gui/ComposerServiceAIDL.h> +#include <ui/FenceResult.h> #include <ui/Rect.h> #include <utils/String8.h> #include <functional> @@ -24,6 +26,8 @@ namespace android { +using gui::aidl_utils::statusTFromBinderStatus; + namespace { // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check @@ -36,14 +40,14 @@ public: SurfaceComposerClient::Transaction().apply(true); captureArgs.dataspace = ui::Dataspace::V0_SRGB; - const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); + const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make(); binder::Status status = sf->captureDisplay(captureArgs, captureListener); - - if (status.transactionError() != NO_ERROR) { - return status.transactionError(); + status_t err = statusTFromBinderStatus(status); + if (err != NO_ERROR) { + return err; } captureResults = captureListener->waitForResults(); - return captureResults.result; + return fenceStatus(captureResults.fenceResult); } static void captureScreen(std::unique_ptr<ScreenCapture>* sc) { @@ -70,13 +74,14 @@ public: SurfaceComposerClient::Transaction().apply(true); captureArgs.dataspace = ui::Dataspace::V0_SRGB; - const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); + const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make(); binder::Status status = sf->captureLayers(captureArgs, captureListener); - if (status.transactionError() != NO_ERROR) { - return status.transactionError(); + status_t err = statusTFromBinderStatus(status); + if (err != NO_ERROR) { + return err; } captureResults = captureListener->waitForResults(); - return captureResults.result; + return fenceStatus(captureResults.fenceResult); } static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) { diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp index 667dfb92d5..8b4a6be1bf 100644 --- a/services/surfaceflinger/tests/vsync/vsync.cpp +++ b/services/surfaceflinger/tests/vsync/vsync.cpp @@ -18,7 +18,13 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +// This file is included by modules that have host support but android/looper.h is not supported +// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled. +#ifndef __BIONIC__ +#define __REMOVED_IN(x) __attribute__((deprecated)) +#endif #include <android/looper.h> + #include <gui/DisplayEventReceiver.h> #include <utils/Looper.h> @@ -55,8 +61,7 @@ int main(int /*argc*/, char** /*argv*/) { DisplayEventReceiver myDisplayEvent; - - sp<Looper> loop = new Looper(false); + sp<Looper> loop = sp<Looper>::make(false); loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver, &myDisplayEvent); diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 1fe8800e09..9c6d19f5ec 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1882,6 +1882,11 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { if (swapchain_result != VK_SUCCESS) { OrphanSwapchain(device, &swapchain); } + // Android will only return VK_SUBOPTIMAL_KHR for vkQueuePresentKHR, + // and only when the window's transform/rotation changes. Extent + // changes will not cause VK_SUBOPTIMAL_KHR because of the + // application issues that were caused when the following transform + // change was added. int window_transform_hint; err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &window_transform_hint); |