Merge "Add new onUidProcAdjChanged callback to be consumed by the camera service." into tm-dev
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4b64203..260ee8d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -67,5 +67,66 @@
}
]
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "SurfaceFlinger_test",
+ "options": [
+ {
+ "include-filter": "*CredentialsTest.*"
+ },
+ {
+ "include-filter": "*SurfaceFlingerStress.*"
+ },
+ {
+ "include-filter": "*SurfaceInterceptorTest.*"
+ },
+ {
+ "include-filter": "*LayerTransactionTest.*"
+ },
+ {
+ "include-filter": "*LayerTypeTransactionTest.*"
+ },
+ {
+ "include-filter": "*LayerUpdateTest.*"
+ },
+ {
+ "include-filter": "*GeometryLatchingTest.*"
+ },
+ {
+ "include-filter": "*CropLatchingTest.*"
+ },
+ {
+ "include-filter": "*ChildLayerTest.*"
+ },
+ {
+ "include-filter": "*ScreenCaptureTest.*"
+ },
+ {
+ "include-filter": "*ScreenCaptureChildOnlyTest.*"
+ },
+ {
+ "include-filter": "*DereferenceSurfaceControlTest.*"
+ },
+ {
+ "include-filter": "*BoundlessLayerTest.*"
+ },
+ {
+ "include-filter": "*MultiDisplayLayerBoundsTest.*"
+ },
+ {
+ "include-filter": "*InvalidHandleTest.*"
+ },
+ {
+ "include-filter": "*VirtualDisplayTest.*"
+ },
+ {
+ "include-filter": "*RelativeZTest.*"
+ },
+ {
+ "include-filter": "*RefreshRateOverlayTest.*"
+ }
+ ]
+ }
]
}
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 08a3d9a..6fb9a4d 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -1225,10 +1225,7 @@
if (ret < 0) {
for (int i = optind; i < argc; i++) {
- if (!setCategoryEnable(argv[i])) {
- fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
- exit(1);
- }
+ setCategoryEnable(argv[i]);
}
break;
}
@@ -1344,10 +1341,10 @@
// contain entries from only one CPU can cause "begin" entries without a
// matching "end" entry to show up if a task gets migrated from one CPU to
// another.
- if (!onlyUserspace)
+ if (!onlyUserspace) {
ok = clearTrace();
-
- writeClockSyncMarker();
+ writeClockSyncMarker();
+ }
if (ok && !async && !traceStream) {
// Sleep to allow the trace to be captured.
struct timespec timeLeft;
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 77bed0e..c104fea 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -55,6 +55,7 @@
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
+#include <linux/quota.h>
#include <log/log.h> // TODO: Move everything to base/logging.
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
@@ -117,6 +118,12 @@
static std::atomic<bool> sAppDataIsolationEnabled(false);
+/**
+ * Flag to control if project ids are supported for internal storage
+ */
+static std::atomic<bool> sUsingProjectIdsFlag(false);
+static std::once_flag flag;
+
namespace {
constexpr const char* kDump = "android.permission.DUMP";
@@ -457,15 +464,40 @@
free(after);
return res;
}
+static bool internal_storage_has_project_id() {
+ // The following path is populated in setFirstBoot, so if this file is present
+ // then project ids can be used. Using call once to cache the result of this check
+ // to avoid having to check the file presence again and again.
+ std::call_once(flag, []() {
+ auto using_project_ids =
+ StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+ sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
+ });
+ return sUsingProjectIdsFlag;
+}
-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid) {
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
+ long project_id) {
if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
PLOG(ERROR) << "Failed to prepare " << path;
return -1;
}
+ if (internal_storage_has_project_id()) {
+ return set_quota_project_id(path, project_id, true);
+ }
return 0;
}
+static int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+ uid_t uid, gid_t gid, long project_id) {
+ auto path = StringPrintf("%s/%s", parent.c_str(), name);
+ int ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid);
+ if (ret == 0 && internal_storage_has_project_id()) {
+ return set_quota_project_id(path, project_id, true);
+ }
+ return ret;
+}
+
static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
return true;
@@ -625,9 +657,11 @@
}
// Prepare only the parent app directory
- if (prepare_app_dir(path, targetMode, uid, gid) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+ long project_id_app = get_project_id(uid, PROJECT_ID_APP_START);
+ long project_id_cache_app = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+ if (prepare_app_dir(path, targetMode, uid, gid, project_id_app) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, project_id_cache_app) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, project_id_cache_app)) {
return error("Failed to prepare " + path);
}
@@ -726,8 +760,7 @@
if (flags & FLAG_STORAGE_SDK) {
// Safe to ignore status since we can retry creating this by calling reconcileSdkData
- auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId,
- previousAppId, seInfo, flags);
+ auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
if (!ignore.isOk()) {
PLOG(WARNING) << "Failed to create sdk data package directory for " << packageName;
}
@@ -746,7 +779,7 @@
*/
binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
- int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) {
+ int32_t appId, int32_t flags) {
int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
if (sdkSandboxUid == -1) {
// There no valid sdk sandbox process for this app. Skip creation of data directory
@@ -765,37 +798,16 @@
// /data/misc_{ce,de}/<user-id>/sdksandbox directory gets created by vold
// during user creation
- // Prepare the app directory
+ // Prepare the package directory
auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
packageName.c_str());
#if SDK_DEBUG
LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
#endif
- if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM)) {
+ if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM, 0)) {
return error("Failed to prepare " + packagePath);
}
-
- // Now prepare the shared directory which will be accessible by all codes
- auto sharedPath = create_data_misc_sdk_sandbox_shared_path(uuid_, isCeData, userId,
- packageName.c_str());
-
- int32_t previousSdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
- int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
- if (cacheGid == -1) {
- return exception(binder::Status::EX_ILLEGAL_STATE,
- StringPrintf("cacheGid cannot be -1 for sdksandbox data"));
- }
- auto status = createAppDataDirs(sharedPath, sdkSandboxUid, AID_NOBODY,
- &previousSdkSandboxUid, cacheGid, seInfo, 0700);
- if (!status.isOk()) {
- return status;
- }
-
- // TODO(b/211763739): We also need to handle art profile creations
-
- // TODO(b/211763739): And return the CE inode of the sdksandbox root directory and
- // app directory under it so we can clear contents while CE storage is locked
}
return ok();
@@ -848,8 +860,8 @@
const android::os::ReconcileSdkDataArgs& args) {
// Locking is performed depeer in the callstack.
- return reconcileSdkData(args.uuid, args.packageName, args.sdkPackageNames, args.randomSuffixes,
- args.userId, args.appId, args.previousAppId, args.seInfo, args.flags);
+ return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
+ args.previousAppId, args.seInfo, args.flags);
}
/**
@@ -863,17 +875,14 @@
* is to avoid having same per-sdk directory with different suffix.
* - If a sdk level directory exist which is absent from sdkPackageNames, we remove it.
*/
-binder::Status InstalldNativeService::reconcileSdkData(
- const std::optional<std::string>& uuid, const std::string& packageName,
- const std::vector<std::string>& sdkPackageNames,
- const std::vector<std::string>& randomSuffixes, int userId, int appId, int previousAppId,
- const std::string& seInfo, int flags) {
+binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ const std::vector<std::string>& subDirNames,
+ int userId, int appId, int previousAppId,
+ const std::string& seInfo, int flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- for (const auto& sdkPackageName : sdkPackageNames) {
- CHECK_ARGUMENT_PACKAGE_NAME(sdkPackageName);
- }
LOCK_PACKAGE_USER();
#if SDK_DEBUG
@@ -882,16 +891,9 @@
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- // Validate we have enough randomSuffixStrings
- if (randomSuffixes.size() != sdkPackageNames.size()) {
- return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Not enough random suffix. Required %d, received %d.",
- (int)sdkPackageNames.size(), (int)randomSuffixes.size()));
- }
-
// Prepare the sdk package directory in case it's missing
- const auto status = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId,
- previousAppId, seInfo, flags);
+ const auto status =
+ createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
if (!status.isOk()) {
return status;
}
@@ -905,37 +907,22 @@
}
const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
- // Since random suffix provided will be random every time, we need to ensure we don't end up
- // creating multuple directories for same sdk package with different suffixes. This
- // is ensured by fetching all the existing sub directories and storing them so that we can
- // check for existence later. We also remove unconsumed sdk directories in this check.
const auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
packageName.c_str());
- const std::unordered_set<std::string> expectedSdkNames(sdkPackageNames.begin(),
- sdkPackageNames.end());
- // Store paths of per-sdk directory for sdk that already exists
- std::unordered_map<std::string, std::string> sdkNamesThatExist;
- const auto subDirHandler = [&packagePath, &expectedSdkNames, &sdkNamesThatExist,
- &res](const std::string& filename) {
- auto filepath = packagePath + "/" + filename;
- auto tokens = Split(filename, "@");
- if (tokens.size() != 2) {
- // Not a per-sdk directory with random suffix
- return;
- }
- auto sdkName = tokens[0];
-
+ // Remove existing sub-directories not referred in subDirNames
+ const std::unordered_set<std::string> expectedSubDirNames(subDirNames.begin(),
+ subDirNames.end());
+ const auto subDirHandler = [&packagePath, &expectedSubDirNames,
+ &res](const std::string& subDirName) {
// Remove the per-sdk directory if it is not referred in
- // expectedSdkNames
- if (expectedSdkNames.find(sdkName) == expectedSdkNames.end()) {
- if (delete_dir_contents_and_dir(filepath) != 0) {
- res = error("Failed to delete " + filepath);
+ // expectedSubDirNames
+ if (expectedSubDirNames.find(subDirName) == expectedSubDirNames.end()) {
+ auto path = packagePath + "/" + subDirName;
+ if (delete_dir_contents_and_dir(path) != 0) {
+ res = error("Failed to delete " + path);
return;
}
- } else {
- // Otherwise, store it as existing sdk level directory
- sdkNamesThatExist[sdkName] = filepath;
}
};
const int ec = foreach_subdir(packagePath, subDirHandler);
@@ -944,19 +931,11 @@
continue;
}
- // Create sdksandbox data directory for each sdksandbox package
- for (int i = 0, size = sdkPackageNames.size(); i < size; i++) {
- const std::string& sdkName = sdkPackageNames[i];
- const std::string& randomSuffix = randomSuffixes[i];
- std::string path;
- if (const auto& it = sdkNamesThatExist.find(sdkName); it != sdkNamesThatExist.end()) {
- // Already exists. Use existing path instead of creating a new one
- path = it->second;
- } else {
- path = create_data_misc_sdk_sandbox_sdk_path(uuid_, isCeData, userId,
- packageName.c_str(), sdkName.c_str(),
- randomSuffix.c_str());
- }
+ // Now create the subDirNames
+ for (const auto& subDirName : subDirNames) {
+ const std::string path =
+ create_data_misc_sdk_sandbox_sdk_path(uuid_, isCeData, userId,
+ packageName.c_str(), subDirName.c_str());
// Create the directory along with cache and code_cache
const int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
@@ -967,7 +946,7 @@
const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
auto status = createAppDataDirs(path, sandboxUid, AID_NOBODY, &previousSandboxUid,
- cacheGid, seInfo, 0700);
+ cacheGid, seInfo, 0700 | S_ISGID);
if (!status.isOk()) {
res = status;
continue;
@@ -2143,19 +2122,70 @@
}
#endif
+// On devices without sdcardfs, if internal and external are on
+// the same volume, a uid such as u0_a123 is used for both
+// internal and external storage; therefore, subtract that
+// amount from internal to make sure we don't count it double.
+// This needs to happen for data, cache and OBB
+static void deductDoubleSpaceIfNeeded(stats* stats, int64_t doubleSpaceToBeDeleted, uid_t uid,
+ const std::string& uuid) {
+ if (!supports_sdcardfs()) {
+ stats->dataSize -= doubleSpaceToBeDeleted;
+ long obbProjectId = get_project_id(uid, PROJECT_ID_EXT_OBB_START);
+ int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
+ stats->dataSize -= appObbSize;
+ }
+}
+
static void collectQuotaStats(const std::string& uuid, int32_t userId,
int32_t appId, struct stats* stats, struct stats* extStats) {
- int64_t space;
+ int64_t space, doubleSpaceToBeDeleted = 0;
uid_t uid = multiuser_get_uid(userId, appId);
- if (stats != nullptr) {
- if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
- stats->dataSize += space;
+ static const bool supportsProjectId = internal_storage_has_project_id();
+
+ if (extStats != nullptr) {
+ space = get_occupied_app_space_external(uuid, userId, appId);
+
+ if (space != -1) {
+ extStats->dataSize += space;
+ doubleSpaceToBeDeleted += space;
}
- int cacheGid = multiuser_get_cache_gid(userId, appId);
- if (cacheGid != -1) {
- if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+ space = get_occupied_app_cache_space_external(uuid, userId, appId);
+ if (space != -1) {
+ extStats->dataSize += space; // cache counts for "data"
+ extStats->cacheSize += space;
+ doubleSpaceToBeDeleted += space;
+ }
+ }
+
+ if (stats != nullptr) {
+ if (!supportsProjectId) {
+ if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+ stats->dataSize += space;
+ }
+ deductDoubleSpaceIfNeeded(stats, doubleSpaceToBeDeleted, uid, uuid);
+ int sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ if (sdkSandboxUid != -1) {
+ if ((space = GetOccupiedSpaceForUid(uuid, sdkSandboxUid)) != -1) {
+ stats->dataSize += space;
+ }
+ }
+ int cacheGid = multiuser_get_cache_gid(userId, appId);
+ if (cacheGid != -1) {
+ if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+ stats->cacheSize += space;
+ }
+ }
+ } else {
+ long projectId = get_project_id(uid, PROJECT_ID_APP_START);
+ if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
+ stats->dataSize += space;
+ }
+ projectId = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+ if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
stats->cacheSize += space;
+ stats->dataSize += space;
}
}
@@ -2166,47 +2196,6 @@
}
}
}
-
- if (extStats != nullptr) {
- static const bool supportsSdCardFs = supports_sdcardfs();
- space = get_occupied_app_space_external(uuid, userId, appId);
-
- if (space != -1) {
- extStats->dataSize += space;
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, if internal and external are on
- // the same volume, a uid such as u0_a123 is used for
- // application dirs on both internal and external storage;
- // therefore, substract that amount from internal to make sure
- // we don't count it double.
- stats->dataSize -= space;
- }
- }
-
- space = get_occupied_app_cache_space_external(uuid, userId, appId);
- if (space != -1) {
- extStats->dataSize += space; // cache counts for "data"
- extStats->cacheSize += space;
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, if internal and external are on
- // the same volume, a uid such as u0_a123 is used for both
- // internal and external storage; therefore, substract that
- // amount from internal to make sure we don't count it double.
- stats->dataSize -= space;
- }
- }
-
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, the UID of OBBs on external storage
- // matches the regular app UID (eg u0_a123); therefore, to avoid
- // OBBs being include in stats->dataSize, compute the OBB size for
- // this app, and substract it from the size reported on internal
- // storage
- long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START;
- int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
- stats->dataSize -= appObbSize;
- }
- }
}
static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -2259,8 +2248,17 @@
closedir(d);
}
+void collectManualStatsForSubDirectories(const std::string& path, struct stats* stats) {
+ const auto subDirHandler = [&path, &stats](const std::string& subDir) {
+ auto fullpath = path + "/" + subDir;
+ collectManualStats(fullpath, stats);
+ };
+ foreach_subdir(path, subDirHandler);
+}
+
static void collectManualStatsForUser(const std::string& path, struct stats* stats,
- bool exclude_apps = false) {
+ bool exclude_apps = false,
+ bool is_sdk_sandbox_storage = false) {
DIR *d;
int dfd;
struct dirent *de;
@@ -2285,6 +2283,11 @@
continue;
} else if (exclude_apps && (user_uid >= AID_APP_START && user_uid <= AID_APP_END)) {
continue;
+ } else if (is_sdk_sandbox_storage) {
+ // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+ // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+ collectManualStatsForSubDirectories(StringPrintf("%s/%s", path.c_str(), name),
+ stats);
} else {
collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
}
@@ -2327,6 +2330,12 @@
fts_close(fts);
}
static bool ownsExternalStorage(int32_t appId) {
+ // if project id calculation is supported then, there is no need to
+ // calculate in a different way and project_id based calculation can work
+ if (internal_storage_has_project_id()) {
+ return false;
+ }
+
// Fetch external storage owner appid and check if it is the same as the
// current appId whose size is calculated
struct stat s;
@@ -2427,6 +2436,19 @@
collectManualStats(dePath, &stats);
ATRACE_END();
+ // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+ // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+ if (appId >= AID_APP_START && appId <= AID_APP_END) {
+ ATRACE_BEGIN("sdksandbox");
+ auto sdkSandboxCePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, true, userId, pkgname);
+ collectManualStatsForSubDirectories(sdkSandboxCePath, &stats);
+ auto sdkSandboxDePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, false, userId, pkgname);
+ collectManualStatsForSubDirectories(sdkSandboxDePath, &stats);
+ ATRACE_END();
+ }
+
if (!uuid) {
ATRACE_BEGIN("profiles");
calculate_tree_size(
@@ -2663,6 +2685,13 @@
collectManualStatsForUser(dePath, &stats);
ATRACE_END();
+ ATRACE_BEGIN("sdksandbox");
+ auto sdkSandboxCePath = create_data_misc_sdk_sandbox_path(uuid_, true, userId);
+ collectManualStatsForUser(sdkSandboxCePath, &stats, false, true);
+ auto sdkSandboxDePath = create_data_misc_sdk_sandbox_path(uuid_, false, userId);
+ collectManualStatsForUser(sdkSandboxDePath, &stats, false, true);
+ ATRACE_END();
+
if (!uuid) {
ATRACE_BEGIN("profile");
auto userProfilePath = create_primary_cur_profile_dir_path(userId);
@@ -3370,6 +3399,38 @@
dexPath, packageName, uid, volumeUuid, storageFlag, _aidl_return);
return result ? ok() : error();
}
+/**
+ * Returns true if ioctl feature (F2FS_IOC_FS{GET,SET}XATTR) is supported as
+ * these were introduced in Linux 4.14, so kernel versions before that will fail
+ * while setting project id attributes. Only when these features are enabled,
+ * storage calculation using project_id is enabled
+ */
+bool check_if_ioctl_feature_is_supported() {
+ bool result = false;
+ auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
+ if (access(temp_path.c_str(), F_OK) != 0) {
+ int fd = open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+ result = set_quota_project_id(temp_path, 0, true) == 0;
+ close(fd);
+ // delete the temp file
+ remove(temp_path.c_str());
+ }
+ return result;
+}
+
+binder::Status InstalldNativeService::setFirstBoot() {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+ std::string uuid;
+ if (GetOccupiedSpaceForProjectId(uuid, 0) != -1 && check_if_ioctl_feature_is_supported()) {
+ auto first_boot_path =
+ StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+ if (access(first_boot_path.c_str(), F_OK) != 0) {
+ close(open(first_boot_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644));
+ }
+ }
+ return ok();
+}
binder::Status InstalldNativeService::invalidateMounts() {
ENFORCE_UID(AID_SYSTEM);
@@ -3590,5 +3651,23 @@
return ok();
}
+binder::Status InstalldNativeService::getOdexVisibility(
+ const std::string& packageName, const std::string& apkPath,
+ const std::string& instructionSet, const std::optional<std::string>& outputPath,
+ int32_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ CHECK_ARGUMENT_PATH(apkPath);
+ CHECK_ARGUMENT_PATH(outputPath);
+ LOCK_PACKAGE();
+
+ const char* apk_path = apkPath.c_str();
+ const char* instruction_set = instructionSet.c_str();
+ const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
+
+ *_aidl_return = get_odex_visibility(apk_path, instruction_set, oat_dir);
+ return *_aidl_return == -1 ? error() : ok();
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 1f0fc9c..87a9206 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -168,6 +168,7 @@
int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
binder::Status invalidateMounts();
+ binder::Status setFirstBoot();
binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
bool* _aidl_return);
binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
@@ -183,6 +184,11 @@
binder::Status cleanupInvalidPackageDirs(const std::optional<std::string>& uuid, int32_t userId,
int32_t flags);
+ binder::Status getOdexVisibility(const std::string& packageName, const std::string& apkPath,
+ const std::string& instructionSet,
+ const std::optional<std::string>& outputPath,
+ int32_t* _aidl_return);
+
private:
std::recursive_mutex mLock;
std::unordered_map<userid_t, std::weak_ptr<std::shared_mutex>> mUserIdLock;
@@ -211,8 +217,7 @@
binder::Status createSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
const std::string& packageName,
int32_t userId, int32_t appId,
- int32_t previousAppId,
- const std::string& seInfo, int32_t flags);
+ int32_t flags);
binder::Status clearSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
const std::string& packageName,
int32_t userId, int32_t flags);
@@ -221,8 +226,7 @@
int32_t userId, int32_t flags);
binder::Status reconcileSdkData(const std::optional<std::string>& uuid,
const std::string& packageName,
- const std::vector<std::string>& sdkPackageNames,
- const std::vector<std::string>& randomSuffixes, int32_t userId,
+ const std::vector<std::string>& subDirNames, int32_t userId,
int32_t appId, int32_t previousAppId, const std::string& seInfo,
int flags);
binder::Status restoreconSdkDataLocked(const std::optional<std::string>& uuid,
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3f0fb6d..8ccab4c 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -30,6 +30,9 @@
},
{
"name": "CtsCompilationTestCases"
+ },
+ {
+ "name": "SdkSandboxStorageHostTest"
}
]
}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index e08e9b6..79c02e8 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -20,7 +20,7 @@
interface IInstalld {
void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
-
+ void setFirstBoot();
android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);
@@ -130,6 +130,9 @@
void cleanupInvalidPackageDirs(@nullable @utf8InCpp String uuid, int userId, int flags);
+ int getOdexVisibility(@utf8InCpp String packageName, @utf8InCpp String apkPath,
+ @utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath);
+
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
const int FLAG_STORAGE_EXTERNAL = 0x4;
diff --git a/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
index 2f794b1..583a36d 100644
--- a/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
+++ b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
@@ -20,8 +20,7 @@
parcelable ReconcileSdkDataArgs {
@nullable @utf8InCpp String uuid;
@utf8InCpp String packageName;
- @utf8InCpp List<String> sdkPackageNames;
- @utf8InCpp List<String> randomSuffixes;
+ @utf8InCpp List<String> subDirNames;
int userId;
int appId;
int previousAppId;
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 9647865..894c7d3 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -2773,13 +2773,23 @@
const std::string& profile_name,
const std::string& code_path,
const std::optional<std::string>& dex_metadata) {
- // Prepare the current profile.
- std::string cur_profile = create_current_profile_path(user_id, package_name, profile_name,
- /*is_secondary_dex*/ false);
- uid_t uid = multiuser_get_uid(user_id, app_id);
- if (fs_prepare_file_strict(cur_profile.c_str(), 0600, uid, uid) != 0) {
- PLOG(ERROR) << "Failed to prepare " << cur_profile;
- return false;
+ if (user_id != USER_NULL) {
+ if (user_id < 0) {
+ LOG(ERROR) << "Unexpected user ID " << user_id;
+ return false;
+ }
+
+ // Prepare the current profile.
+ std::string cur_profile = create_current_profile_path(user_id, package_name, profile_name,
+ /*is_secondary_dex*/ false);
+ uid_t uid = multiuser_get_uid(user_id, app_id);
+ if (fs_prepare_file_strict(cur_profile.c_str(), 0600, uid, uid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << cur_profile;
+ return false;
+ }
+ } else {
+ // Prepare the reference profile as the system user.
+ user_id = USER_SYSTEM;
}
// Check if we need to install the profile from the dex metadata.
@@ -2788,8 +2798,9 @@
}
// We have a dex metdata. Merge the profile into the reference profile.
- unique_fd ref_profile_fd = open_reference_profile(uid, package_name, profile_name,
- /*read_write*/ true, /*is_secondary_dex*/ false);
+ unique_fd ref_profile_fd =
+ open_reference_profile(multiuser_get_uid(user_id, app_id), package_name, profile_name,
+ /*read_write*/ true, /*is_secondary_dex*/ false);
unique_fd dex_metadata_fd(TEMP_FAILURE_RETRY(
open(dex_metadata->c_str(), O_RDONLY | O_NOFOLLOW)));
unique_fd apk_fd(TEMP_FAILURE_RETRY(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW)));
@@ -2823,5 +2834,22 @@
return true;
}
+int get_odex_visibility(const char* apk_path, const char* instruction_set, const char* oat_dir) {
+ char oat_path[PKG_PATH_MAX];
+ if (!create_oat_out_path(apk_path, instruction_set, oat_dir, /*is_secondary_dex=*/false,
+ oat_path)) {
+ return -1;
+ }
+ struct stat st;
+ if (stat(oat_path, &st) == -1) {
+ if (errno == ENOENT) {
+ return ODEX_NOT_FOUND;
+ }
+ PLOG(ERROR) << "Could not stat " << oat_path;
+ return -1;
+ }
+ return (st.st_mode & S_IROTH) ? ODEX_IS_PUBLIC : ODEX_IS_PRIVATE;
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 12579b0..f7af929 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -98,10 +98,9 @@
const std::string& pkgname,
const std::string& profile_name);
-// Prepare the app profile for the given code path:
-// - create the current profile using profile_name
-// - merge the profile from the dex metadata file (if present) into
-// the reference profile.
+// Prepares the app profile for the package at the given path:
+// - Creates the current profile for the given user ID, unless the user ID is `USER_NULL`.
+// - Merges the profile from the dex metadata file (if present) into the reference profile.
bool prepare_app_profile(const std::string& package_name,
userid_t user_id,
appid_t app_id,
@@ -153,6 +152,12 @@
bool is_release,
bool is_debuggable_build);
+// Returns `ODEX_NOT_FOUND` if the optimized artifacts are not found, or `ODEX_IS_PUBLIC` if the
+// optimized artifacts are accessible by all apps, or `ODEX_IS_PRIVATE` if the optimized artifacts
+// are only accessible by this app, or -1 if failed to get the visibility of the optimized
+// artifacts.
+int get_odex_visibility(const char* apk_path, const char* instruction_set, const char* oat_dir);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 00d8441..3623f9b 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -18,6 +18,8 @@
#ifndef INSTALLD_CONSTANTS_H_
#define INSTALLD_CONSTANTS_H_
+#include "cutils/multiuser.h"
+
namespace android {
namespace installd {
@@ -83,6 +85,15 @@
constexpr int PROFILES_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA = 2;
constexpr int PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
+// NOTE: keep in sync with Installer.java
+constexpr int ODEX_NOT_FOUND = 0;
+constexpr int ODEX_IS_PUBLIC = 1;
+constexpr int ODEX_IS_PRIVATE = 2;
+
+// NOTE: keep in sync with UserHandle.java
+constexpr userid_t USER_NULL = -10000;
+constexpr userid_t USER_SYSTEM = 0;
+
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
} // namespace installd
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index f21a304..4eb30e2 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -650,6 +650,36 @@
ASSERT_EQ(expected_bytes_freed, bytes_freed);
}
+
+ void checkVisibility(bool in_dalvik_cache, int32_t expected_visibility) {
+ int32_t visibility;
+ ASSERT_BINDER_SUCCESS(service_->getOdexVisibility(package_name_, apk_path_, kRuntimeIsa,
+ in_dalvik_cache
+ ? std::nullopt
+ : std::make_optional<std::string>(
+ app_oat_dir_.c_str()),
+ &visibility));
+ EXPECT_EQ(visibility, expected_visibility);
+ }
+
+ void TestGetOdexVisibility(bool in_dalvik_cache) {
+ const char* oat_dir = in_dalvik_cache ? nullptr : app_oat_dir_.c_str();
+
+ checkVisibility(in_dalvik_cache, ODEX_NOT_FOUND);
+
+ CompilePrimaryDexOk("speed-profile",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_PUBLIC |
+ DEXOPT_GENERATE_APP_IMAGE,
+ oat_dir, kTestAppGid, DEX2OAT_FROM_SCRATCH,
+ /*binder_result=*/nullptr, empty_dm_file_.c_str());
+ checkVisibility(in_dalvik_cache, ODEX_IS_PUBLIC);
+
+ CompilePrimaryDexOk("speed-profile",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_GENERATE_APP_IMAGE,
+ oat_dir, kTestAppGid, DEX2OAT_FROM_SCRATCH,
+ /*binder_result=*/nullptr, empty_dm_file_.c_str());
+ checkVisibility(in_dalvik_cache, ODEX_IS_PRIVATE);
+ }
};
@@ -830,6 +860,16 @@
TestDeleteOdex(/*in_dalvik_cache=*/ true);
}
+TEST_F(DexoptTest, GetOdexVisibilityData) {
+ LOG(INFO) << "GetOdexVisibilityData";
+ TestGetOdexVisibility(/*in_dalvik_cache=*/false);
+}
+
+TEST_F(DexoptTest, GetOdexVisibilityDalvikCache) {
+ LOG(INFO) << "GetOdexVisibilityDalvikCache";
+ TestGetOdexVisibility(/*in_dalvik_cache=*/true);
+}
+
TEST_F(DexoptTest, ResolveStartupConstStrings) {
LOG(INFO) << "DexoptDex2oatResolveStartupStrings";
const std::string property = "persist.device_config.runtime.dex2oat_resolve_startup_strings";
@@ -1105,13 +1145,16 @@
ASSERT_TRUE(AreFilesEqual(ref_profile_content, ref_profile_));
}
- // TODO(calin): add dex metadata tests once the ART change is merged.
void preparePackageProfile(const std::string& package_name, const std::string& profile_name,
- bool expected_result) {
+ bool has_dex_metadata, bool has_user_id, bool expected_result) {
bool result;
- ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
- package_name, kTestUserId, kTestAppId, profile_name, apk_path_,
- /*dex_metadata*/ {}, &result));
+ ASSERT_BINDER_SUCCESS(
+ service_->prepareAppProfile(package_name, has_user_id ? kTestUserId : USER_NULL,
+ kTestAppId, profile_name, apk_path_,
+ has_dex_metadata ? std::make_optional<std::string>(
+ empty_dm_file_)
+ : std::nullopt,
+ &result));
ASSERT_EQ(expected_result, result);
if (!expected_result) {
@@ -1119,16 +1162,29 @@
return;
}
- std::string code_path_cur_prof = create_current_profile_path(
- kTestUserId, package_name, profile_name, /*is_secondary_dex*/ false);
- std::string code_path_ref_profile = create_reference_profile_path(package_name,
- profile_name, /*is_secondary_dex*/ false);
+ std::string code_path_cur_prof =
+ create_current_profile_path(kTestUserId, package_name, profile_name,
+ /*is_secondary_dex*/ false);
+ std::string code_path_ref_profile =
+ create_reference_profile_path(package_name, profile_name,
+ /*is_secondary_dex*/ false);
- // Check that we created the current profile.
- CheckFileAccess(code_path_cur_prof, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+ if (has_user_id) {
+ // Check that we created the current profile.
+ CheckFileAccess(code_path_cur_prof, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+ } else {
+ // Without a user ID, we don't generate a current profile.
+ ASSERT_EQ(-1, access(code_path_cur_prof.c_str(), R_OK));
+ }
- // Without dex metadata we don't generate a reference profile.
- ASSERT_EQ(-1, access(code_path_ref_profile.c_str(), R_OK));
+ if (has_dex_metadata) {
+ int32_t uid = has_user_id ? kTestAppUid : multiuser_get_uid(USER_SYSTEM, kTestAppId);
+ // Check that we created the reference profile.
+ CheckFileAccess(code_path_ref_profile, uid, uid, 0640 | S_IFREG);
+ } else {
+ // Without dex metadata, we don't generate a reference profile.
+ ASSERT_EQ(-1, access(code_path_ref_profile.c_str(), R_OK));
+ }
}
protected:
@@ -1273,12 +1329,32 @@
TEST_F(ProfileTest, ProfilePrepareOk) {
LOG(INFO) << "ProfilePrepareOk";
- preparePackageProfile(package_name_, "split.prof", /*expected_result*/ true);
+ preparePackageProfile(package_name_, "split.prof", /*has_dex_metadata*/ true,
+ /*has_user_id*/ true, /*expected_result*/ true);
+}
+
+TEST_F(ProfileTest, ProfilePrepareOkNoUser) {
+ LOG(INFO) << "ProfilePrepareOk";
+ preparePackageProfile(package_name_, "split.prof", /*has_dex_metadata*/ true,
+ /*has_user_id*/ false, /*expected_result*/ true);
+}
+
+TEST_F(ProfileTest, ProfilePrepareOkNoDm) {
+ LOG(INFO) << "ProfilePrepareOk";
+ preparePackageProfile(package_name_, "split.prof", /*has_dex_metadata*/ false,
+ /*has_user_id*/ true, /*expected_result*/ true);
+}
+
+TEST_F(ProfileTest, ProfilePrepareOkNoUserNoDm) {
+ LOG(INFO) << "ProfilePrepareOk";
+ preparePackageProfile(package_name_, "split.prof", /*has_dex_metadata*/ false,
+ /*has_user_id*/ false, /*expected_result*/ true);
}
TEST_F(ProfileTest, ProfilePrepareFailInvalidPackage) {
LOG(INFO) << "ProfilePrepareFailInvalidPackage";
- preparePackageProfile("not.there.package", "split.prof", /*expected_result*/ false);
+ preparePackageProfile("not.there.package", "split.prof", /*has_dex_metadata*/ true,
+ /*has_user_id*/ true, /*expected_result*/ false);
}
TEST_F(ProfileTest, ProfilePrepareFailProfileChangedUid) {
@@ -1286,7 +1362,8 @@
SetupProfiles(/*setup_ref*/ false);
// Change the uid on the profile to trigger a failure.
::chown(cur_profile_.c_str(), kTestAppUid + 1, kTestAppGid + 1);
- preparePackageProfile(package_name_, "primary.prof", /*expected_result*/ false);
+ preparePackageProfile(package_name_, "primary.prof", /*has_dex_metadata*/ true,
+ /*has_user_id*/ true, /*expected_result*/ false);
}
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 04558d5..38cb370 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -45,7 +45,7 @@
#include "utils.h"
using android::base::StringPrintf;
-namespace fs = std::filesystem;
+using std::filesystem::is_empty;
namespace android {
std::string get_package_name(uid_t uid) {
@@ -79,12 +79,15 @@
namespace installd {
static constexpr const char* kTestUuid = "TEST";
-static constexpr const char* kTestPath = "/data/local/tmp";
+static const std::string kTestPath = "/data/local/tmp";
static constexpr const uid_t kNobodyUid = 9999;
static constexpr const uid_t kSystemUid = 1000;
static constexpr const int32_t kTestUserId = 0;
static constexpr const uid_t kTestAppId = 19999;
static constexpr const int FLAG_STORAGE_SDK = InstalldNativeService::FLAG_STORAGE_SDK;
+static constexpr const int FLAG_CLEAR_CACHE_ONLY = InstalldNativeService::FLAG_CLEAR_CACHE_ONLY;
+static constexpr const int FLAG_CLEAR_CODE_CACHE_ONLY =
+ InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY;
const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
const gid_t kTestCacheGid = multiuser_get_cache_gid(kTestUserId, kTestAppId);
@@ -111,7 +114,7 @@
}
static std::string get_full_path(const std::string& path) {
- return StringPrintf("%s/%s", kTestPath, path.c_str());
+ return StringPrintf("%s/%s", kTestPath.c_str(), path.c_str());
}
static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
@@ -169,10 +172,9 @@
}
static bool exists_renamed_deleted_dir(const std::string& rootDirectory) {
- return find_file((std::string(kTestPath) + rootDirectory).c_str(),
- [](const std::string& name, bool is_dir) {
- return is_dir && is_renamed_deleted_dir(name);
- });
+ return find_file((kTestPath + rootDirectory).c_str(), [](const std::string& name, bool is_dir) {
+ return is_dir && is_renamed_deleted_dir(name);
+ });
}
class ServiceTest : public testing::Test {
@@ -992,16 +994,12 @@
}
android::os::ReconcileSdkDataArgs reconcileSdkDataArgs(
- std::string packageName, std::vector<std::string> codeNames,
- std::vector<std::string> randomSuffixes) {
+ const std::string& packageName, const std::vector<std::string>& subDirNames) {
android::os::ReconcileSdkDataArgs args;
args.uuid = kTestUuid;
args.packageName = packageName;
- for (const auto& codeName : codeNames) {
- args.sdkPackageNames.push_back(codeName);
- }
- for (const auto& randomSuffix : randomSuffixes) {
- args.randomSuffixes.push_back(randomSuffix);
+ for (const auto& subDirName : subDirNames) {
+ args.subDirNames.push_back(subDirName);
}
args.userId = kTestUserId;
args.appId = kTestAppId;
@@ -1051,22 +1049,12 @@
const std::string fooCePath = "misc_ce/0/sdksandbox/com.foo";
CheckFileAccess(fooCePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
- CheckFileAccess(fooCePath + "/shared", kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
- CheckFileAccess(fooCePath + "/shared/cache", kTestSdkSandboxUid, kTestCacheGid,
- S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(fooCePath + "/shared/code_cache", kTestSdkSandboxUid, kTestCacheGid,
- S_IFDIR | S_ISGID | 0771);
const std::string fooDePath = "misc_de/0/sdksandbox/com.foo";
CheckFileAccess(fooDePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
- CheckFileAccess(fooDePath + "/shared", kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
- CheckFileAccess(fooDePath + "/shared/cache", kTestSdkSandboxUid, kTestCacheGid,
- S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(fooDePath + "/shared/code_cache", kTestSdkSandboxUid, kTestCacheGid,
- S_IFDIR | S_ISGID | 0771);
}
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutSdkFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlag) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
@@ -1078,7 +1066,7 @@
ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
}
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutSdkFlagDeletesExisting) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlagDeletesExisting) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
// Create the app user data.
@@ -1092,7 +1080,7 @@
ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
}
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutDeFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutDeFlag) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_SDK;
@@ -1107,7 +1095,7 @@
ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
}
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutCeFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutCeFlag) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.flags = FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
@@ -1124,102 +1112,58 @@
TEST_F(SdkSandboxDataTest, ReconcileSdkData) {
android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar", "baz"}, {"random1", "random2"});
+ reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
// Create the sdk data.
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
const std::string barCePath = "misc_ce/0/sdksandbox/com.foo/bar@random1";
- CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
+ CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
CheckFileAccess(barCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
CheckFileAccess(barCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
const std::string bazCePath = "misc_ce/0/sdksandbox/com.foo/baz@random2";
- CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
+ CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
CheckFileAccess(bazCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
CheckFileAccess(bazCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
const std::string barDePath = "misc_de/0/sdksandbox/com.foo/bar@random1";
- CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
+ CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
CheckFileAccess(barDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
CheckFileAccess(barDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
const std::string bazDePath = "misc_de/0/sdksandbox/com.foo/baz@random2";
- CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
+ CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
CheckFileAccess(bazDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
CheckFileAccess(bazDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
}
-TEST_F(SdkSandboxDataTest, ReconcileSdkData_PackageNameCannotUseRandomSuffixSeparator) {
- android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar@illegal"}, {"random1"});
-
- // Create the sdksandbox data.
- auto status = service->reconcileSdkData(args);
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_ILLEGAL_ARGUMENT);
- ASSERT_EQ(status.exceptionMessage(), "Package name bar@illegal is malformed");
-}
-
-TEST_F(SdkSandboxDataTest, ReconcileSdkData_NotEnoughRandomSuffix) {
- android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar", "baz"}, {"random1"});
-
- // Create the sdksandbox data.
- auto status = service->reconcileSdkData(args);
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_ILLEGAL_ARGUMENT);
- ASSERT_EQ(status.exceptionMessage(), "Not enough random suffix. Required 2, received 1.");
-}
-
-TEST_F(SdkSandboxDataTest, ReconcileSdkData_DirectoryNotCreatedIfAlreadyExistsIgnoringSuffix) {
- android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar", "baz"}, {"random1", "random2"});
-
- // Create the sdksandbox data.
- ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
-
- // Retry with different random suffix
- args.randomSuffixes[0] = "r10";
- args.randomSuffixes[1] = "r20";
-
- // Create the sdksandbox data again
- ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
-
- // Previous directories from first attempt should exist
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar@random1", kTestSdkSandboxUid, kNobodyUid,
- S_IFDIR | 0700);
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
- S_IFDIR | 0700);
- // No new directories should be created on second attempt
- ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/bar@r10"));
- ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo/bar@r20"));
-}
-
TEST_F(SdkSandboxDataTest, ReconcileSdkData_ExtraCodeDirectoriesAreDeleted) {
android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar", "baz"}, {"random1", "random2"});
+ reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
// Create the sdksandbox data.
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
// Retry with different package name
- args.sdkPackageNames[0] = "bar.diff";
+ args.subDirNames[0] = "bar.diff@random1";
// Create the sdksandbox data again
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
// New directoris should exist
CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar.diff@random1", kTestSdkSandboxUid, kNobodyUid,
- S_IFDIR | 0700);
+ S_IFDIR | S_ISGID | 0700);
CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
- S_IFDIR | 0700);
+ S_IFDIR | S_ISGID | 0700);
// Directory for old unreferred sdksandbox package name should be removed
ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/bar@random1"));
}
@@ -1270,130 +1214,90 @@
void createTestSdkData(const std::string& packageName, std::vector<std::string> sdkNames) {
const auto& cePackagePath = "/data/local/tmp/misc_ce/0/sdksandbox/" + packageName;
const auto& dePackagePath = "/data/local/tmp/misc_de/0/sdksandbox/" + packageName;
- ASSERT_TRUE(mkdirs(cePackagePath + "/shared/cache", 0700));
- ASSERT_TRUE(mkdirs(cePackagePath + "shared/code_cache", 0700));
- ASSERT_TRUE(mkdirs(dePackagePath + "/shared/cache", 0700));
- ASSERT_TRUE(mkdirs(dePackagePath + "/shared/code_cache", 0700));
- std::ofstream{cePackagePath + "/shared/cache/cachedTestData.txt"};
- for (auto sdkName : sdkNames) {
- ASSERT_TRUE(mkdirs(cePackagePath + "/" + sdkName + "/cache", 0700));
- ASSERT_TRUE(mkdirs(dePackagePath + "/" + sdkName + "/cache", 0700));
- ASSERT_TRUE(mkdirs(cePackagePath + "/" + sdkName + "/code_cache", 0700));
- ASSERT_TRUE(mkdirs(dePackagePath + "/" + sdkName + "/code_cache", 0700));
- std::ofstream{cePackagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
- std::ofstream{cePackagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
- std::ofstream{dePackagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
- std::ofstream{dePackagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
+ ASSERT_TRUE(mkdirs(cePackagePath, 0700));
+ ASSERT_TRUE(mkdirs(dePackagePath, 0700));
+ const std::vector<std::string> packagePaths = {cePackagePath, dePackagePath};
+ for (const auto& packagePath : packagePaths) {
+ for (auto sdkName : sdkNames) {
+ ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/cache", 0700));
+ ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/code_cache", 0700));
+ std::ofstream{packagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
+ std::ofstream{packagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
+ }
}
}
};
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(
- service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_CE | (InstalldNativeService::FLAG_CLEAR_CACHE_ONLY),
- result.ceDataInode));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/shared/cache")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk1/cache")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk2/cache")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_CE | FLAG_CLEAR_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCodeCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(
- service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_CE |
- (InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY),
- result.ceDataInode));
- ASSERT_TRUE(fs::is_empty(
- fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/shared/code_cache")));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk1/code_cache")));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk2/code_cache")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_CE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data
ASSERT_BINDER_SUCCESS(
- service->clearAppData(args.uuid, args.packageName, args.userId,
+ service->clearAppData(kTestUuid, "com.foo", 0,
FLAG_STORAGE_DE | (InstalldNativeService::FLAG_CLEAR_CACHE_ONLY),
- result.ceDataInode));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/shared/cache")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk1/cache")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk2/cache")));
+ -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCodeCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(
- service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_DE |
- (InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY),
- result.ceDataInode));
- ASSERT_TRUE(fs::is_empty(
- fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/shared/code_cache")));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk1/code_cache")));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk2/code_cache")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_DE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndWithoutAnyCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_CE, result.ceDataInode));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/shared")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk1")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk2")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_CE, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndWithoutAnyCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_DE, result.ceDataInode));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/shared")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk1")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk2")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_DE, -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
}
class DestroyUserDataTest : public SdkSandboxDataTest {};
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 38c1c05..910cd63 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -690,11 +690,11 @@
create_data_misc_sdk_sandbox_package_path(nullptr, true, 10, "com.foo"));
EXPECT_EQ("/data/misc_ce/0/sdksandbox/com.foo/shared",
- create_data_misc_sdk_sandbox_shared_path(nullptr, true, 0, "com.foo"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 0, "com.foo", "shared"));
EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/shared",
- create_data_misc_sdk_sandbox_shared_path(nullptr, true, 10, "com.foo"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "shared"));
EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/bar@random",
- create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "bar", "random"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "bar@random"));
// De data paths
EXPECT_EQ("/data/misc_de/0/sdksandbox",
@@ -707,12 +707,11 @@
create_data_misc_sdk_sandbox_package_path(nullptr, false, 10, "com.foo"));
EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo/shared",
- create_data_misc_sdk_sandbox_shared_path(nullptr, false, 0, "com.foo"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 0, "com.foo", "shared"));
EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/shared",
- create_data_misc_sdk_sandbox_shared_path(nullptr, false, 10, "com.foo"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "shared"));
EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/bar@random",
- create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "bar",
- "random"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "bar@random"));
}
TEST_F(UtilsTest, WaitChild) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 8cfd123..45aeab6 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -37,6 +37,7 @@
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
+#include <linux/fs.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <private/android_projectid_config.h>
@@ -223,28 +224,17 @@
}
/**
- * Create the path name where shared code data for a particular app will be stored.
- * E.g. /data/misc_ce/0/sdksandbox/<package-name>/shared
- */
-std::string create_data_misc_sdk_sandbox_shared_path(const char* volume_uuid, bool isCeData,
- userid_t user, const char* package_name) {
- return StringPrintf("%s/shared",
- create_data_misc_sdk_sandbox_package_path(volume_uuid, isCeData, user,
- package_name)
- .c_str());
-}
-
-/**
- * Create the path name where per-code level data for a particular app will be stored.
- * E.g. /data/misc_ce/0/sdksandbox/<package-name>/<sdk-name>-<random-suffix>
+ * Create the path name where sdk data for a particular sdk will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>/com.foo@randomstrings
*/
std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
userid_t user, const char* package_name,
- const char* sdk_name, const char* randomSuffix) {
- check_package_name(sdk_name);
- auto package_path =
- create_data_misc_sdk_sandbox_package_path(volume_uuid, isCeData, user, package_name);
- return StringPrintf("%s/%s@%s", package_path.c_str(), sdk_name, randomSuffix);
+ const char* sub_dir_name) {
+ return StringPrintf("%s/%s",
+ create_data_misc_sdk_sandbox_package_path(volume_uuid, isCeData, user,
+ package_name)
+ .c_str(),
+ sub_dir_name);
}
std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
@@ -435,6 +425,45 @@
return users;
}
+long get_project_id(uid_t uid, long start_project_id_range) {
+ return uid - AID_APP_START + start_project_id_range;
+}
+
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit) {
+ struct fsxattr fsx;
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << path << " to set project id.";
+ return -1;
+ }
+
+ if (ioctl(fd, FS_IOC_FSGETXATTR, &fsx) == -1) {
+ PLOG(ERROR) << "Failed to get extended attributes for " << path << " to get project id.";
+ return -1;
+ }
+
+ fsx.fsx_projid = project_id;
+ if (ioctl(fd, FS_IOC_FSSETXATTR, &fsx) == -1) {
+ PLOG(ERROR) << "Failed to set project id on " << path;
+ return -1;
+ }
+ if (set_inherit) {
+ unsigned int flags;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
+ PLOG(ERROR) << "Failed to get flags for " << path << " to set project id inheritance.";
+ return -1;
+ }
+
+ flags |= FS_PROJINHERIT_FL;
+
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == -1) {
+ PLOG(ERROR) << "Failed to set flags for " << path << " to set project id inheritance.";
+ return -1;
+ }
+ }
+ return 0;
+}
+
int calculate_tree_size(const std::string& path, int64_t* size,
int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
FTS *fts;
@@ -678,16 +707,16 @@
auto temp_dir_path =
base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str());
- if (::rename(pathname.c_str(), temp_dir_path.c_str())) {
+ auto dir_to_delete = temp_dir_path.c_str();
+ if (::rename(pathname.c_str(), dir_to_delete)) {
if (ignore_if_missing && (errno == ENOENT)) {
return 0;
}
- ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), temp_dir_path.c_str(),
- strerror(errno));
- return -errno;
+ ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), dir_to_delete, strerror(errno));
+ dir_to_delete = pathname.c_str();
}
- return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing);
+ return delete_dir_contents(dir_to_delete, 1, exclusion_predicate, ignore_if_missing);
}
bool is_renamed_deleted_dir(const std::string& path) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 54d77f9..ecea1d2 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -65,11 +65,9 @@
userid_t userid);
std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
userid_t userid, const char* package_name);
-std::string create_data_misc_sdk_sandbox_shared_path(const char* volume_uuid, bool isCeData,
- userid_t userid, const char* package_name);
std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
userid_t userid, const char* package_name,
- const char* sdk_name, const char* randomSuffix);
+ const char* sub_dir_name);
std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
@@ -173,6 +171,8 @@
uid_t uid, gid_t gid);
bool supports_sdcardfs();
+long get_project_id(uid_t uid, long start_project_id_range);
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit);
int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId);
int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId);
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 555be1ed7..3cfe529 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -295,28 +295,27 @@
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
auto ctx = mAccess->getCallingContext();
- // apps cannot add services
if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
- return Status::fromExceptionCode(Status::EX_SECURITY);
+ return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services");
}
if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY);
+ return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial");
}
if (binder == nullptr) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Null binder");
}
if (!isValidServiceName(name)) {
LOG(ERROR) << "Invalid service name: " << name;
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");
}
#ifndef VENDORSERVICEMANAGER
if (!meetsDeclarationRequirements(binder, name)) {
// already logged
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "VINTF declaration error");
}
#endif // !VENDORSERVICEMANAGER
@@ -324,7 +323,7 @@
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
LOG(ERROR) << "Could not linkToDeath when adding " << name;
- return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
}
// Overwrite the old service if it exists
diff --git a/include/android/storage_manager.h b/include/android/storage_manager.h
index 7f2ee08..270570e 100644
--- a/include/android/storage_manager.h
+++ b/include/android/storage_manager.h
@@ -124,6 +124,12 @@
/**
* Attempts to mount an OBB file. This is an asynchronous operation.
+ *
+ * Since API level 33, this function can only be used to mount unencrypted OBBs,
+ * i.e. the {@code key} parameter must be {@code null} or an empty string. Note
+ * that even before API level 33, mounting encrypted OBBs didn't work on many
+ * Android device implementations. Applications should not assume any particular
+ * behavior when {@code key} is nonempty.
*/
void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key,
AStorageManager_obbCallbackFunc cb, void* data);
diff --git a/include/ftl/fake_guard.h b/include/ftl/fake_guard.h
new file mode 100644
index 0000000..bacd1b2
--- /dev/null
+++ b/include/ftl/fake_guard.h
@@ -0,0 +1,90 @@
+/*
+ * 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
+
+#define FTL_ATTRIBUTE(a) __attribute__((a))
+
+namespace android::ftl {
+
+// Granular alternative to [[clang::no_thread_safety_analysis]]. Given a std::mutex-like object,
+// FakeGuard suppresses enforcement of thread-safe access to guarded variables within its scope.
+// While FakeGuard is scoped to a block, there are macro shorthands for a single expression, as
+// well as function/lambda scope (though calls must be indirect, e.g. virtual or std::function):
+//
+// struct {
+// std::mutex mutex;
+// int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
+//
+// int f() {
+// {
+// ftl::FakeGuard guard(mutex);
+// x = 0;
+// }
+//
+// return FTL_FAKE_GUARD(mutex, x + 1);
+// }
+//
+// std::function<int()> g() const {
+// return [this]() FTL_FAKE_GUARD(mutex) { return x; };
+// }
+// } s;
+//
+// assert(s.f() == 1);
+// assert(s.g()() == 0);
+//
+// An example of a situation where FakeGuard helps is a mutex that guards writes on Thread 1, and
+// reads on Thread 2. Reads on Thread 1, which is the only writer, need not be under lock, so can
+// use FakeGuard to appease the thread safety analyzer. Another example is enforcing and documenting
+// exclusive access by a single thread. This is done by defining a global constant that represents a
+// thread context, and annotating guarded variables as if it were a mutex (though without any effect
+// at run time):
+//
+// constexpr class [[clang::capability("mutex")]] {
+// } kMainThreadContext;
+//
+template <typename Mutex>
+struct [[clang::scoped_lockable]] FakeGuard final {
+ explicit FakeGuard(const Mutex& mutex) FTL_ATTRIBUTE(acquire_capability(mutex)) {}
+ [[clang::release_capability()]] ~FakeGuard() {}
+
+ FakeGuard(const FakeGuard&) = delete;
+ FakeGuard& operator=(const FakeGuard&) = delete;
+};
+
+} // namespace android::ftl
+
+// TODO: Enable in C++23 once standard attributes can be used on lambdas.
+#if 0
+#define FTL_FAKE_GUARD1(mutex) [[using clang: acquire_capability(mutex), release_capability(mutex)]]
+#else
+#define FTL_FAKE_GUARD1(mutex) \
+ FTL_ATTRIBUTE(acquire_capability(mutex)) \
+ FTL_ATTRIBUTE(release_capability(mutex))
+#endif
+
+// The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
+#define FTL_FAKE_GUARD2(mutex, expr) \
+ [&]() -> decltype(auto) { \
+ const android::ftl::FakeGuard guard(mutex); \
+ return (expr); \
+ }()
+
+#define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard
+
+// The void argument suppresses a warning about zero variadic macro arguments.
+#define FTL_FAKE_GUARD(...) \
+ FTL_MAKE_FAKE_GUARD(__VA_ARGS__, FTL_FAKE_GUARD2, FTL_FAKE_GUARD1, void)(__VA_ARGS__)
diff --git a/libs/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
index fdd532a..57e03cb 100644
--- a/libs/binder/BufferedTextOutput.h
+++ b/libs/binder/BufferedTextOutput.h
@@ -18,8 +18,8 @@
#define ANDROID_BUFFEREDTEXTOUTPUT_H
#include <binder/TextOutput.h>
-#include <utils/threads.h>
#include <sys/uio.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 9c7ff97..c6b0cb7 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -31,7 +31,7 @@
#include <binder/Parcel.h>
#include <log/log.h>
-#include <utils/threads.h>
+#include <utils/Mutex.h>
#include <map>
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index f79075d..3c97dca 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -27,7 +27,6 @@
#include <utils/CallStack.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
-#include <utils/threads.h>
#include <atomic>
#include <errno.h>
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index c4475c7..03553f3 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -23,7 +23,6 @@
#include <utils/Log.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
-#include <utils/threads.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 504c6c2..be50a75 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -569,6 +569,47 @@
return mHasFds;
}
+std::vector<sp<IBinder>> Parcel::debugReadAllStrongBinders() const {
+ std::vector<sp<IBinder>> ret;
+
+ size_t initPosition = dataPosition();
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ binder_size_t offset = mObjects[i];
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + offset);
+ if (flat->hdr.type != BINDER_TYPE_BINDER) continue;
+
+ setDataPosition(offset);
+
+ sp<IBinder> binder = readStrongBinder();
+ if (binder != nullptr) ret.push_back(binder);
+ }
+
+ setDataPosition(initPosition);
+ return ret;
+}
+
+std::vector<int> Parcel::debugReadAllFileDescriptors() const {
+ std::vector<int> ret;
+
+ size_t initPosition = dataPosition();
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ binder_size_t offset = mObjects[i];
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + offset);
+ if (flat->hdr.type != BINDER_TYPE_FD) continue;
+
+ setDataPosition(offset);
+
+ int fd = readFileDescriptor();
+ LOG_ALWAYS_FATAL_IF(fd == -1);
+ ret.push_back(fd);
+ }
+
+ setDataPosition(initPosition);
+ return ret;
+}
+
status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool* result) const {
if (len > INT32_MAX || offset > INT32_MAX) {
// Don't accept size_t values which may have come from an inadvertent conversion from a
@@ -1862,6 +1903,7 @@
{
status_t status = readNullableStrongBinder(val);
if (status == OK && !val->get()) {
+ ALOGW("Expecting binder but got null!");
status = UNEXPECTED_NULL;
}
return status;
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
index 2e86b74..3cf94e3 100644
--- a/libs/binder/ParcelableHolder.cpp
+++ b/libs/binder/ParcelableHolder.cpp
@@ -52,7 +52,10 @@
}
status_t ParcelableHolder::readFromParcel(const Parcel* p) {
- this->mStability = static_cast<Stability>(p->readInt32());
+ int32_t wireStability;
+ if (status_t status = p->readInt32(&wireStability); status != OK) return status;
+ if (static_cast<int32_t>(this->mStability) != wireStability) return BAD_VALUE;
+
this->mParcelable = nullptr;
this->mParcelableName = std::nullopt;
int32_t rawDataSize;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index b14a838..4a01d81 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -25,9 +25,10 @@
#include <binder/IServiceManager.h>
#include <binder/Stability.h>
#include <cutils/atomic.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <utils/String8.h>
-#include <utils/threads.h>
+#include <utils/Thread.h>
#include "Static.h"
#include "binder_module.h"
diff --git a/libs/binder/Static.h b/libs/binder/Static.h
index 83524e8..8444fe7 100644
--- a/libs/binder/Static.h
+++ b/libs/binder/Static.h
@@ -17,8 +17,6 @@
// All static variables go here, to control initialization and
// destruction order in the library.
-#include <utils/threads.h>
-
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 8deb2fe..19ad5e6 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -18,7 +18,6 @@
#include <binder/IBinder.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
#include <map>
#include <unordered_map>
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 450e388..e2b2c51 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -95,6 +95,12 @@
bool hasFileDescriptors() const;
status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool* result) const;
+ // returns all binder objects in the Parcel
+ std::vector<sp<IBinder>> debugReadAllStrongBinders() const;
+ // returns all file descriptors in the Parcel
+ // does not dup
+ std::vector<int> debugReadAllFileDescriptors() const;
+
// Zeros data when reallocating. Other mitigations may be added
// in the future.
//
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 42c85f9..88790a8 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -86,7 +86,7 @@
*ret = nullptr;
return android::BAD_VALUE;
}
- *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ *ret = std::static_pointer_cast<T>(mParcelable);
return android::OK;
}
this->mParcelPtr->setDataPosition(0);
@@ -105,7 +105,7 @@
return status;
}
this->mParcelPtr = nullptr;
- *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ *ret = std::static_pointer_cast<T>(mParcelable);
return android::OK;
}
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
index e658574..6f9eb5e 100644
--- a/libs/binder/include/binder/PermissionController.h
+++ b/libs/binder/include/binder/PermissionController.h
@@ -19,8 +19,7 @@
#ifndef __ANDROID_VNDK__
#include <binder/IPermissionController.h>
-
-#include <utils/threads.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 0deee73..675585e 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -18,11 +18,10 @@
#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
#include <utils/String16.h>
#include <utils/String8.h>
-#include <utils/threads.h>
-
#include <pthread.h>
// ---------------------------------------------------------------------------
diff --git a/libs/binder/include_activitymanager/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
index 5788d41..5dfbd44 100644
--- a/libs/binder/include_activitymanager/binder/ActivityManager.h
+++ b/libs/binder/include_activitymanager/binder/ActivityManager.h
@@ -18,10 +18,9 @@
#ifndef __ANDROID_VNDK__
-#include <binder/IActivityManager.h>
#include <android/app/ProcessStateEnum.h>
-
-#include <utils/threads.h>
+#include <binder/IActivityManager.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 28819bb..f45aa76 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -101,7 +101,12 @@
return STATUS_INVALID_OPERATION;
}
- RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+ parcelable_stability_t wireStability;
+ RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability));
+ if (this->mStability != wireStability) {
+ return STATUS_BAD_VALUE;
+ }
+
int32_t dataSize;
binder_status_t status = AParcel_readInt32(parcel, &dataSize);
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 467e51e..5d6206d 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -1086,7 +1086,7 @@
{
$( #[$attr:meta] )*
$enum:ident : [$backing:ty; $size:expr] {
- $( $name:ident = $value:expr, )*
+ $( $( #[$value_attr:meta] )* $name:ident = $value:expr, )*
}
} => {
$( #[$attr] )*
@@ -1094,7 +1094,7 @@
#[allow(missing_docs)]
pub struct $enum(pub $backing);
impl $enum {
- $( #[allow(missing_docs)] pub const $name: Self = Self($value); )*
+ $( $( #[$value_attr] )* #[allow(missing_docs)] pub const $name: Self = Self($value); )*
#[inline(always)]
#[allow(missing_docs)]
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index d58e839..432da5d 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -233,7 +233,9 @@
}
fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
- self.stability = parcel.read()?;
+ if self.stability != parcel.read()? {
+ return Err(StatusCode::BAD_VALUE);
+ }
let data_size: i32 = parcel.read()?;
if data_size < 0 {
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index aee15d8..359c783 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -20,9 +20,12 @@
#include <cutils/ashmem.h>
#include <gtest/gtest.h>
+using android::BBinder;
+using android::IBinder;
using android::IPCThreadState;
using android::OK;
using android::Parcel;
+using android::sp;
using android::status_t;
using android::String16;
using android::String8;
@@ -75,6 +78,40 @@
EXPECT_EQ(p.enforceNoDataAvail().exceptionCode(), Status::Exception::EX_NONE);
}
+TEST(Parcel, DebugReadAllBinders) {
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ Parcel p;
+ p.writeInt32(4);
+ p.writeStrongBinder(binder1);
+ p.writeStrongBinder(nullptr);
+ p.writeInt32(4);
+ p.writeStrongBinder(binder2);
+ p.writeInt32(4);
+
+ auto ret = p.debugReadAllStrongBinders();
+
+ ASSERT_EQ(ret.size(), 2);
+ EXPECT_EQ(ret[0], binder1);
+ EXPECT_EQ(ret[1], binder2);
+}
+
+TEST(Parcel, DebugReadAllFds) {
+ Parcel p;
+ p.writeInt32(4);
+ p.writeFileDescriptor(STDOUT_FILENO, false /*takeOwnership*/);
+ p.writeInt32(4);
+ p.writeFileDescriptor(STDIN_FILENO, false /*takeOwnership*/);
+ p.writeInt32(4);
+
+ auto ret = p.debugReadAllFileDescriptors();
+
+ ASSERT_EQ(ret.size(), 2);
+ EXPECT_EQ(ret[0], STDOUT_FILENO);
+ EXPECT_EQ(ret[1], STDIN_FILENO);
+}
+
// Tests a second operation results in a parcel at the same location as it
// started.
void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 38bde3a..57d496d 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -66,10 +66,13 @@
srcs: [
"random_fd.cpp",
"random_parcel.cpp",
+ "libbinder_driver.cpp",
+ "libbinder_ndk_driver.cpp",
],
shared_libs: [
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libutils",
],
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 13f7195..47ec776 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -109,6 +109,8 @@
},
PARCEL_READ_NO_STATUS(size_t, allowFds),
PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
+ PARCEL_READ_NO_STATUS(std::vector<android::sp<android::IBinder>>, debugReadAllStrongBinders),
+ PARCEL_READ_NO_STATUS(std::vector<int>, debugReadAllFileDescriptors),
[] (const ::android::Parcel& p, uint8_t len) {
std::string interface(len, 'a');
FUZZ_LOG() << "about to enforceInterface: " << interface;
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
new file mode 100644
index 0000000..a9a6197
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
@@ -0,0 +1,37 @@
+/*
+ * 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/IBinder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+/**
+ * Based on the random data in provider, construct an arbitrary number of
+ * Parcel objects and send them to the service in serial.
+ *
+ * Usage:
+ *
+ * extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ * FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+ * // can use provider here to create a service with different options
+ * sp<IFoo> myService = sp<IFoo>::make(...);
+ * fuzzService(myService, std::move(provider));
+ * }
+ */
+void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
new file mode 100644
index 0000000..f2b7823
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
@@ -0,0 +1,37 @@
+/*
+ * 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/binder_parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+/**
+ * Based on the random data in provider, construct an arbitrary number of
+ * Parcel objects and send them to the service in serial.
+ *
+ * Usage:
+ *
+ * extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ * FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+ * // can use provider here to create a service with different options
+ * std::shared_ptr<IFoo> myService = ndk::SharedRefBase<IFoo>::make(...);
+ * fuzzService(myService->asBinder().get(), std::move(provider));
+ * }
+ */
+void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 0a083d7..843b6e3 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -16,12 +16,13 @@
#pragma once
+#include <android-base/unique_fd.h>
#include <fuzzer/FuzzedDataProvider.h>
namespace android {
-// ownership to callee, always valid or aborts
+// always valid or aborts
// get a random FD for use in fuzzing, of a few different specific types
-int getRandomFd(FuzzedDataProvider* provider);
+base::unique_fd getRandomFd(FuzzedDataProvider* provider);
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 749bf21..459fb12 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -19,13 +19,24 @@
#include <binder/Parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
+#include <functional>
+#include <vector>
+
namespace android {
+
+struct RandomParcelOptions {
+ std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader;
+ std::vector<sp<IBinder>> extraBinders;
+ std::vector<base::unique_fd> extraFds;
+};
+
/**
* Fill parcel data, including some random binder objects and FDs
+ *
+ * p - the Parcel to fill
+ * provider - takes ownership and completely consumes provider
+ * writeHeader - optional function to write a specific header once the format of the parcel is
+ * picked (for instance, to write an interface header)
*/
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-/**
- * Fill parcel data, but don't fill any objects.
- */
-void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider);
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {});
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
new file mode 100644
index 0000000..d5aa353
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 <fuzzbinder/libbinder_driver.h>
+
+#include <fuzzbinder/random_parcel.h>
+
+namespace android {
+
+void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
+ sp<IBinder> target;
+
+ RandomParcelOptions options{
+ .extraBinders = {binder},
+ .extraFds = {},
+ };
+
+ while (provider.remaining_bytes() > 0) {
+ uint32_t code = provider.ConsumeIntegral<uint32_t>();
+ uint32_t flags = provider.ConsumeIntegral<uint32_t>();
+ Parcel data;
+
+ sp<IBinder> target = options.extraBinders.at(
+ provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
+ options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) {
+ // most code will be behind checks that the head of the Parcel
+ // is exactly this, so make it easier for fuzzers to reach this
+ if (provider.ConsumeBool()) {
+ p->writeInterfaceToken(target->getInterfaceDescriptor());
+ }
+ };
+
+ std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
+ provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+ fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options);
+
+ Parcel reply;
+ (void)target->transact(code, data, &reply, flags);
+
+ // feed back in binders and fds that are returned from the service, so that
+ // we can fuzz those binders, and use the fds and binders to feed back into
+ // the binders
+ auto retBinders = reply.debugReadAllStrongBinders();
+ options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(),
+ retBinders.end());
+ auto retFds = reply.debugReadAllFileDescriptors();
+ for (size_t i = 0; i < retFds.size(); i++) {
+ options.extraFds.push_back(base::unique_fd(dup(retFds[i])));
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
new file mode 100644
index 0000000..462ef9a
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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 <fuzzbinder/libbinder_ndk_driver.h>
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzbinder/random_parcel.h>
+
+// libbinder_ndk doesn't export this header which breaks down its API for NDK
+// and APEX users, but we need access to it to fuzz.
+#include "../../ndk/ibinder_internal.h"
+
+namespace android {
+
+void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) {
+ fuzzService(binder->getBinder(), std::move(provider));
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index cef6adb..ab0b7e3 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -23,13 +23,13 @@
namespace android {
-int getRandomFd(FuzzedDataProvider* provider) {
+base::unique_fd getRandomFd(FuzzedDataProvider* provider) {
int fd = provider->PickValueInArray<std::function<int()>>({
[]() { return ashmem_create_region("binder test region", 1024); },
[]() { return open("/dev/null", O_RDWR); },
})();
CHECK(fd >= 0);
- return fd;
+ return base::unique_fd(fd);
}
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 8bf04cc..0204f5e 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -34,15 +34,30 @@
String16 mDescriptor;
};
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
+static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) {
+ std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes());
+ CHECK(OK == p->write(data.data(), data.size()));
+}
+
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider,
+ const RandomParcelOptions& options) {
if (provider.ConsumeBool()) {
auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
CHECK_EQ(OK, session->addNullDebuggingClient());
p->markForRpc(session);
+
+ if (options.writeHeader) {
+ options.writeHeader(p, provider);
+ }
+
fillRandomParcelData(p, std::move(provider));
return;
}
+ if (options.writeHeader) {
+ options.writeHeader(p, provider);
+ }
+
while (provider.remaining_bytes() > 0) {
auto fillFunc = provider.PickValueInArray<const std::function<void()>>({
// write data
@@ -54,8 +69,16 @@
},
// write FD
[&]() {
- int fd = getRandomFd(&provider);
- CHECK(OK == p->writeFileDescriptor(fd, true /*takeOwnership*/));
+ if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
+ const base::unique_fd& fd = options.extraFds.at(
+ provider.ConsumeIntegralInRange<size_t>(0,
+ options.extraFds.size() -
+ 1));
+ CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
+ } else {
+ base::unique_fd fd = getRandomFd(&provider);
+ CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/));
+ }
},
// write binder
[&]() {
@@ -74,7 +97,15 @@
// candidate for checking usage of an actual BpBinder
return IInterface::asBinder(defaultServiceManager());
},
- []() { return nullptr; },
+ [&]() -> sp<IBinder> {
+ if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
+ return options.extraBinders.at(
+ provider.ConsumeIntegralInRange<
+ size_t>(0, options.extraBinders.size() - 1));
+ } else {
+ return nullptr;
+ }
+ },
});
sp<IBinder> binder = makeFunc();
CHECK(OK == p->writeStrongBinder(binder));
@@ -85,9 +116,4 @@
}
}
-void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) {
- std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes());
- CHECK(OK == p->write(data.data(), data.size()));
-}
-
} // namespace android
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
index 741987f..5079431 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
@@ -30,7 +30,6 @@
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
#include <stdio.h>
diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
index 4a0aeba..bf7c613 100644
--- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
@@ -27,7 +27,6 @@
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
namespace android {
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index bc2eb23..97b522a 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -18,6 +18,7 @@
"cast_test.cpp",
"concat_test.cpp",
"enum_test.cpp",
+ "fake_guard_test.cpp",
"future_test.cpp",
"small_map_test.cpp",
"small_vector_test.cpp",
@@ -29,6 +30,7 @@
"-Werror",
"-Wextra",
"-Wpedantic",
+ "-Wthread-safety",
],
header_libs: [
diff --git a/libs/ftl/fake_guard_test.cpp b/libs/ftl/fake_guard_test.cpp
new file mode 100644
index 0000000..9d36e69
--- /dev/null
+++ b/libs/ftl/fake_guard_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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/fake_guard.h>
+#include <gtest/gtest.h>
+
+#include <functional>
+#include <mutex>
+
+namespace android::test {
+
+// Keep in sync with example usage in header file.
+TEST(FakeGuard, Example) {
+ struct {
+ std::mutex mutex;
+ int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
+
+ int f() {
+ {
+ ftl::FakeGuard guard(mutex);
+ x = 0;
+ }
+
+ return FTL_FAKE_GUARD(mutex, x + 1);
+ }
+
+ std::function<int()> g() const {
+ return [this]() FTL_FAKE_GUARD(mutex) { return x; };
+ }
+ } s;
+
+ EXPECT_EQ(s.f(), 1);
+ EXPECT_EQ(s.g()(), 0);
+}
+
+} // namespace android::test
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index ec4c7c1..c2793ac 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -184,6 +184,10 @@
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);
+
+ if (mTransactionReadyCallback) {
+ mTransactionReadyCallback(mSyncTransaction);
+ }
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
@@ -702,14 +706,31 @@
std::function<void(SurfaceComposerClient::Transaction*)> callback,
bool acquireSingleBuffer) {
BBQ_TRACE();
- std::lock_guard _lock{mMutex};
- mTransactionReadyCallback = callback;
- if (callback) {
- mSyncTransaction = new SurfaceComposerClient::Transaction();
- } else {
- mSyncTransaction = nullptr;
+
+ std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr;
+ SurfaceComposerClient::Transaction* prevTransaction = nullptr;
+
+ {
+ std::lock_guard _lock{mMutex};
+ // We're about to overwrite the previous call so we should invoke that callback
+ // immediately.
+ if (mTransactionReadyCallback) {
+ prevCallback = mTransactionReadyCallback;
+ prevTransaction = mSyncTransaction;
+ }
+
+ mTransactionReadyCallback = callback;
+ if (callback) {
+ mSyncTransaction = new SurfaceComposerClient::Transaction();
+ } else {
+ mSyncTransaction = nullptr;
+ }
+ mAcquireSingleBuffer = mTransactionReadyCallback ? acquireSingleBuffer : true;
}
- mAcquireSingleBuffer = mTransactionReadyCallback ? acquireSingleBuffer : true;
+
+ if (prevCallback) {
+ prevCallback(prevTransaction);
+ }
}
void BLASTBufferQueue::stopContinuousSyncTransaction() {
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 39d380d..dfdce20 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -197,4 +197,9 @@
return gotVsync;
}
+status_t DisplayEventDispatcher::getLatestVsyncEventData(
+ ParcelableVsyncEventData* outVsyncEventData) const {
+ return mReceiver.getLatestVsyncEventData(outVsyncEventData);
+}
+
} // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 338ff11..34db5b1 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -594,6 +594,10 @@
what |= eColorChanged;
color = other.color;
}
+ if (other.what & eColorSpaceAgnosticChanged) {
+ what |= eColorSpaceAgnosticChanged;
+ colorSpaceAgnostic = other.colorSpaceAgnostic;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64,
@@ -770,7 +774,13 @@
}; // namespace gui
ReleaseCallbackId BufferData::generateReleaseCallbackId() const {
- return {buffer->getId(), frameNumber};
+ uint64_t bufferId;
+ if (buffer) {
+ bufferId = buffer->getId();
+ } else {
+ bufferId = cachedBuffer.id;
+ }
+ return {bufferId, frameNumber};
}
status_t BufferData::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 27856ce..52a22a7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1421,7 +1421,7 @@
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
- const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& frameNumber,
+ const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& optFrameNumber,
ReleaseBufferCallback callback) {
layer_state_t* s = getLayerState(sc);
if (!s) {
@@ -1433,10 +1433,9 @@
std::shared_ptr<BufferData> bufferData = std::make_shared<BufferData>();
bufferData->buffer = buffer;
- if (frameNumber) {
- bufferData->frameNumber = *frameNumber;
- bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged;
- }
+ uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber);
+ bufferData->frameNumber = frameNumber;
+ bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged;
if (fence) {
bufferData->acquireFence = *fence;
bufferData->flags |= BufferData::BufferDataChange::fenceChanged;
@@ -2320,9 +2319,11 @@
}
status_t SurfaceComposerClient::addWindowInfosListener(
- const sp<WindowInfosListener>& windowInfosListener) {
+ const sp<WindowInfosListener>& windowInfosListener,
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) {
return WindowInfosListenerReporter::getInstance()
- ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService());
+ ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService(),
+ outInitialInfo);
}
status_t SurfaceComposerClient::removeWindowInfosListener(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 6529a4e..654fb33 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -70,6 +70,7 @@
mLayerId = other->mLayerId;
mWidth = other->mWidth;
mHeight = other->mHeight;
+ mFormat = other->mFormat;
mCreateFlags = other->mCreateFlags;
}
@@ -280,5 +281,18 @@
return this;
}
+uint64_t SurfaceControl::resolveFrameNumber(const std::optional<uint64_t>& frameNumber) {
+ if (frameNumber.has_value()) {
+ auto ret = frameNumber.value();
+ // Set the fallback to something far enough ahead that in the unlikely event of mixed
+ // "real" frame numbers and fallback frame numbers, we still won't collide in any
+ // meaningful capacity
+ mFallbackFrameNumber = ret + 100;
+ return ret;
+ } else {
+ return mFallbackFrameNumber++;
+ }
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index 4112f74..cfc7dbc 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -31,7 +31,8 @@
status_t WindowInfosListenerReporter::addWindowInfosListener(
const sp<WindowInfosListener>& windowInfosListener,
- const sp<ISurfaceComposer>& surfaceComposer) {
+ const sp<ISurfaceComposer>& surfaceComposer,
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) {
status_t status = OK;
{
std::scoped_lock lock(mListenersMutex);
@@ -42,6 +43,11 @@
if (status == OK) {
mWindowInfosListeners.insert(windowInfosListener);
}
+
+ if (outInitialInfo != nullptr) {
+ outInitialInfo->first = mLastWindowInfos;
+ outInitialInfo->second = mLastDisplayInfos;
+ }
}
return status;
@@ -55,6 +61,10 @@
std::scoped_lock lock(mListenersMutex);
if (mWindowInfosListeners.size() == 1) {
status = surfaceComposer->removeWindowInfosListener(this);
+ // Clear the last stored state since we're disabling updates and don't want to hold
+ // stale values
+ mLastWindowInfos.clear();
+ mLastDisplayInfos.clear();
}
if (status == OK) {
@@ -75,6 +85,9 @@
for (auto listener : mWindowInfosListeners) {
windowInfosListeners.insert(listener);
}
+
+ mLastWindowInfos = windowInfos;
+ mLastDisplayInfos = displayInfos;
}
for (auto listener : windowInfosListeners) {
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 71968fa..a342539 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -34,6 +34,7 @@
void injectEvent(const DisplayEventReceiver::Event& event);
int getFd() const;
virtual int handleEvent(int receiveFd, int events, void* data);
+ status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const;
protected:
virtual ~DisplayEventDispatcher() = default;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index c8ac166..9d03f58 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -696,7 +696,10 @@
static status_t removeTunnelModeEnabledListener(
const sp<gui::ITunnelModeEnabledListener>& listener);
- status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
+ status_t addWindowInfosListener(
+ const sp<gui::WindowInfosListener>& windowInfosListener,
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo =
+ nullptr);
status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
protected:
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 9ee4636..b72cf83 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <optional>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -98,6 +99,8 @@
sp<SurfaceControl> getParentingLayer();
+ uint64_t resolveFrameNumber(const std::optional<uint64_t>& frameNumber);
+
private:
// can't be copied
SurfaceControl& operator = (SurfaceControl& rhs);
@@ -118,12 +121,13 @@
mutable sp<Surface> mSurfaceData;
mutable sp<BLASTBufferQueue> mBbq;
mutable sp<SurfaceControl> mBbqChild;
- int32_t mLayerId;
- uint32_t mTransformHint;
- uint32_t mWidth;
- uint32_t mHeight;
- PixelFormat mFormat;
- uint32_t mCreateFlags;
+ int32_t mLayerId = 0;
+ uint32_t mTransformHint = 0;
+ uint32_t mWidth = 0;
+ uint32_t mHeight = 0;
+ PixelFormat mFormat = PIXEL_FORMAT_NONE;
+ uint32_t mCreateFlags = 0;
+ uint64_t mFallbackFrameNumber = 100;
};
}; // namespace android
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 96bd0b1..3b4aed4 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -34,15 +34,19 @@
const std::vector<gui::DisplayInfo>&,
const sp<gui::IWindowInfosReportedListener>&) override;
- status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
- const sp<ISurfaceComposer>&);
+ status_t addWindowInfosListener(
+ const sp<gui::WindowInfosListener>& windowInfosListener, const sp<ISurfaceComposer>&,
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo);
status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
- const sp<ISurfaceComposer>&);
+ const sp<ISurfaceComposer>& surfaceComposer);
void reconnect(const sp<ISurfaceComposer>&);
private:
std::mutex mListenersMutex;
std::unordered_set<sp<gui::WindowInfosListener>, SpHash<gui::WindowInfosListener>>
mWindowInfosListeners GUARDED_BY(mListenersMutex);
+
+ std::vector<gui::WindowInfo> mLastWindowInfos GUARDED_BY(mListenersMutex);
+ std::vector<gui::DisplayInfo> mLastDisplayInfos GUARDED_BY(mListenersMutex);
};
} // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 0c3236c..cb7e94c 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -1083,6 +1083,34 @@
checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
+TEST_F(BLASTBufferQueueTest, SyncNextTransactionOverwrite) {
+ std::mutex mutex;
+ std::condition_variable callbackReceivedCv;
+ bool receivedCallback = false;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ ASSERT_EQ(nullptr, adapter.getTransactionReadyCallback());
+ auto callback = [&](Transaction*) {
+ std::unique_lock<std::mutex> lock(mutex);
+ receivedCallback = true;
+ callbackReceivedCv.notify_one();
+ };
+ adapter.syncNextTransaction(callback);
+ ASSERT_NE(nullptr, adapter.getTransactionReadyCallback());
+
+ auto callback2 = [](Transaction*) {};
+ adapter.syncNextTransaction(callback2);
+
+ std::unique_lock<std::mutex> lock(mutex);
+ if (!receivedCallback) {
+ ASSERT_NE(callbackReceivedCv.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive callback";
+ }
+
+ ASSERT_TRUE(receivedCallback);
+}
+
// This test will currently fail because the old surfacecontrol will steal the last presented buffer
// until the old surface control is destroyed. This is not necessarily a bug but to document a
// limitation with the update API and to test any changes to make the api more robust. The current
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index fcfe21b..262987f 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -76,16 +76,30 @@
class InputSurface {
public:
- InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
+ InputSurface(const sp<SurfaceControl> &sc, int width, int height, bool noInputChannel = false) {
mSurfaceControl = sc;
mInputFlinger = getInputFlinger();
- mClientChannel = std::make_shared<InputChannel>();
- mInputFlinger->createInputChannel("testchannels", mClientChannel.get());
+ if (noInputChannel) {
+ mInputInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, true);
+ } else {
+ mClientChannel = std::make_shared<InputChannel>();
+ mInputFlinger->createInputChannel("testchannels", mClientChannel.get());
+ mInputInfo.token = mClientChannel->getConnectionToken();
+ mInputConsumer = new InputConsumer(mClientChannel);
+ }
- populateInputInfo(width, height);
+ mInputInfo.name = "Test info";
+ mInputInfo.dispatchingTimeout = 5s;
+ mInputInfo.globalScaleFactor = 1.0;
+ mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
- mInputConsumer = new InputConsumer(mClientChannel);
+ InputApplicationInfo aInfo;
+ aInfo.token = new BBinder();
+ aInfo.name = "Test app info";
+ aInfo.dispatchingTimeoutMillis =
+ std::chrono::duration_cast<std::chrono::milliseconds>(DISPATCHING_TIMEOUT).count();
+ mInputInfo.applicationInfo = aInfo;
}
static std::unique_ptr<InputSurface> makeColorInputSurface(const sp<SurfaceComposerClient> &scc,
@@ -114,6 +128,16 @@
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
+ static std::unique_ptr<InputSurface> makeContainerInputSurfaceNoInputChannel(
+ const sp<SurfaceComposerClient> &scc, int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Container Surface"), 100 /* height */,
+ 100 /* width */, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceContainer);
+ return std::make_unique<InputSurface>(surfaceControl, width, height,
+ true /* noInputChannel */);
+ }
+
static std::unique_ptr<InputSurface> makeCursorInputSurface(
const sp<SurfaceComposerClient> &scc, int width, int height) {
sp<SurfaceControl> surfaceControl =
@@ -219,7 +243,9 @@
}
virtual ~InputSurface() {
- mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken());
+ if (mClientChannel) {
+ mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken());
+ }
}
virtual void doTransaction(
@@ -263,21 +289,6 @@
poll(&fd, 1, timeoutMs);
}
- void populateInputInfo(int width, int height) {
- mInputInfo.token = mClientChannel->getConnectionToken();
- mInputInfo.name = "Test info";
- mInputInfo.dispatchingTimeout = 5s;
- mInputInfo.globalScaleFactor = 1.0;
- mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
-
- InputApplicationInfo aInfo;
- aInfo.token = new BBinder();
- aInfo.name = "Test app info";
- aInfo.dispatchingTimeoutMillis =
- std::chrono::duration_cast<std::chrono::milliseconds>(DISPATCHING_TIMEOUT).count();
-
- mInputInfo.applicationInfo = aInfo;
- }
public:
sp<SurfaceControl> mSurfaceControl;
std::shared_ptr<InputChannel> mClientChannel;
@@ -984,21 +995,6 @@
EXPECT_EQ(surface->consumeEvent(100), nullptr);
}
-TEST_F(InputSurfacesTest, layer_with_empty_crop_cannot_be_focused) {
- std::unique_ptr<InputSurface> bufferSurface =
- InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
-
- bufferSurface->showAt(50, 50, Rect::EMPTY_RECT);
-
- bufferSurface->requestFocus();
- EXPECT_EQ(bufferSurface->consumeEvent(100), nullptr);
-
- bufferSurface->showAt(50, 50, Rect::INVALID_RECT);
-
- bufferSurface->requestFocus();
- EXPECT_EQ(bufferSurface->consumeEvent(100), nullptr);
-}
-
TEST_F(InputSurfacesTest, layer_with_valid_crop_can_be_focused) {
std::unique_ptr<InputSurface> bufferSurface =
InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
@@ -1085,6 +1081,23 @@
EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
}
+TEST_F(InputSurfacesTest, child_container_with_no_input_channel_blocks_parent) {
+ std::unique_ptr<InputSurface> parent = makeSurface(100, 100);
+
+ parent->showAt(100, 100);
+ injectTap(101, 101);
+ parent->expectTap(1, 1);
+
+ std::unique_ptr<InputSurface> childContainerSurface =
+ InputSurface::makeContainerInputSurfaceNoInputChannel(mComposerClient, 100, 100);
+ childContainerSurface->showAt(0, 0);
+ childContainerSurface->doTransaction(
+ [&](auto &t, auto &sc) { t.reparent(sc, parent->mSurfaceControl); });
+ injectTap(101, 101);
+
+ EXPECT_EQ(parent->consumeEvent(100), nullptr);
+}
+
class MultiDisplayTests : public InputSurfacesTest {
public:
MultiDisplayTests() : InputSurfacesTest() { ProcessState::self()->startThreadPool(); }
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 606fe2a..18fb7c1 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -112,7 +112,7 @@
"frameworks/native/libs/arect/include",
],
},
- linux_glibc: {
+ host_linux: {
srcs: [
"InputTransport.cpp",
"android/os/IInputConstants.aidl",
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 381900e..4a1784e 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -207,7 +207,11 @@
if (result == 0) {
outPlanes->planeCount = 3;
outPlanes->planes[0].data = yuvData.y;
- outPlanes->planes[0].pixelStride = 1;
+ if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+ outPlanes->planes[0].pixelStride = 2;
+ } else {
+ outPlanes->planes[0].pixelStride = 1;
+ }
outPlanes->planes[0].rowStride = yuvData.ystride;
outPlanes->planes[1].data = yuvData.cb;
outPlanes->planes[1].pixelStride = yuvData.chroma_step;
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index b467b35..1665550 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -654,10 +654,14 @@
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);
+ parameters.layer.source.buffer.maxLuminanceNits,
+ hardwareBuffer);
}
return parameters.shader;
}
@@ -868,18 +872,21 @@
// save a snapshot of the activeSurface to use as input to the blur shaders
blurInput = activeSurface->makeImageSnapshot();
- // TODO we could skip this step if we know the blur will cover the entire image
- // blit the offscreen framebuffer into the destination AHB
- 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);
+ // 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
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index a46329d..d479606 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -44,7 +44,8 @@
const shaders::LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
const mat4& colorTransform, float maxDisplayLuminance,
- float currentDisplayLuminanceNits, float maxLuminance) {
+ float currentDisplayLuminanceNits, float maxLuminance,
+ AHardwareBuffer* buffer) {
ATRACE_CALL();
SkRuntimeShaderBuilder effectBuilder(runtimeEffect);
@@ -52,7 +53,7 @@
const auto uniforms =
shaders::buildLinearEffectUniforms(linearEffect, colorTransform, maxDisplayLuminance,
- currentDisplayLuminanceNits, maxLuminance);
+ currentDisplayLuminanceNits, maxLuminance, buffer);
for (const auto& uniform : uniforms) {
effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
@@ -63,4 +64,4 @@
} // namespace skia
} // namespace renderengine
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h
index e0a556b..26bae3b 100644
--- a/libs/renderengine/skia/filters/LinearEffect.h
+++ b/libs/renderengine/skia/filters/LinearEffect.h
@@ -40,11 +40,14 @@
// * The current luminance of the physical display in nits
// * The max luminance is provided as the max luminance for the buffer, either from the SMPTE 2086
// or as the max light level from the CTA 861.3 standard.
+// * An AHardwareBuffer for implementations that support gralloc4 metadata for
+// communicating any HDR metadata.
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader,
const shaders::LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
const mat4& colorTransform, float maxDisplayLuminance,
- float currentDisplayLuminanceNits, float maxLuminance);
+ float currentDisplayLuminanceNits, float maxLuminance,
+ AHardwareBuffer* buffer);
} // namespace skia
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index add7a94..38ae2fd 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -1562,15 +1562,21 @@
const vec3 xyz = bt2020.getRGBtoXYZ() * linearRGB;
const vec3 scaledXYZ = scaleOotf(xyz, kCurrentLuminanceNits);
- const double gain =
+ const auto gains =
tonemap::getToneMapper()
->lookupTonemapGain(static_cast<aidl::android::hardware::graphics::common::
Dataspace>(sourceDataspace),
static_cast<aidl::android::hardware::graphics::common::
Dataspace>(
ui::Dataspace::DISPLAY_P3),
- scaleOotf(linearRGB, kCurrentLuminanceNits), scaledXYZ,
+ {tonemap::
+ Color{.linearRGB =
+ scaleOotf(linearRGB,
+ kCurrentLuminanceNits),
+ .xyz = scaledXYZ}},
metadata);
+ EXPECT_EQ(1, gains.size());
+ const double gain = gains.front();
const vec3 normalizedXYZ = scaledXYZ * gain / metadata.displayMaxLuminance;
const vec3 targetRGB = OETF_sRGB(displayP3.getXYZtoRGB() * normalizedXYZ) * 255;
@@ -2613,8 +2619,7 @@
[](vec3 color) { return EOTF_HLG(color); },
[](vec3 color, float currentLuminaceNits) {
static constexpr float kMaxHLGLuminance = 1000.f;
- static const float kHLGGamma = 1.2 + 0.42 * std::log10(currentLuminaceNits / 1000);
- return color * kMaxHLGLuminance * std::pow(color.y, kHLGGamma - 1);
+ return color * kMaxHLGLuminance;
});
}
diff --git a/libs/shaders/Android.bp b/libs/shaders/Android.bp
index 1cd143e..2f8bf49 100644
--- a/libs/shaders/Android.bp
+++ b/libs/shaders/Android.bp
@@ -30,9 +30,11 @@
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.common@1.2",
+ "libnativewindow",
],
static_libs: [
+ "libarect",
"libmath",
"libtonemap",
"libui-types",
diff --git a/libs/shaders/include/shaders/shaders.h b/libs/shaders/include/shaders/shaders.h
index 43828cc..4ec7594 100644
--- a/libs/shaders/include/shaders/shaders.h
+++ b/libs/shaders/include/shaders/shaders.h
@@ -101,6 +101,7 @@
const mat4& colorTransform,
float maxDisplayLuminance,
float currentDisplayLuminanceNits,
- float maxLuminance);
+ float maxLuminance,
+ AHardwareBuffer* buffer = nullptr);
} // namespace android::shaders
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index 03da3ec..5935589 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -185,9 +185,8 @@
break;
case HAL_DATASPACE_TRANSFER_HLG:
shader.append(R"(
- uniform float in_hlgGamma;
float3 ScaleLuminance(float3 xyz) {
- return xyz * 1000.0 * pow(xyz.y, in_hlgGamma - 1);
+ return xyz * 1000.0;
}
)");
break;
@@ -228,10 +227,8 @@
break;
case HAL_DATASPACE_TRANSFER_HLG:
shader.append(R"(
- uniform float in_hlgGamma;
float3 NormalizeLuminance(float3 xyz) {
- return xyz / 1000.0 *
- pow(xyz.y / 1000.0, (1 - in_hlgGamma) / (in_hlgGamma));
+ return xyz / 1000.0;
}
)");
break;
@@ -451,11 +448,6 @@
return result;
}
-// Refer to BT2100-2
-float computeHlgGamma(float currentDisplayBrightnessNits) {
- return 1.2 + 0.42 * std::log10(currentDisplayBrightnessNits / 1000);
-}
-
} // namespace
std::string buildLinearEffectSkSL(const LinearEffect& linearEffect) {
@@ -476,7 +468,8 @@
const mat4& colorTransform,
float maxDisplayLuminance,
float currentDisplayLuminanceNits,
- float maxLuminance) {
+ float maxLuminance,
+ AHardwareBuffer* buffer) {
std::vector<tonemap::ShaderUniform> uniforms;
if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
uniforms.push_back({.name = "in_rgbToXyz", .value = buildUniformValue<mat4>(mat4())});
@@ -492,19 +485,17 @@
colorTransform * mat4(outputColorSpace.getXYZtoRGB()))});
}
- if ((linearEffect.inputDataspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_HLG) {
- uniforms.push_back(
- {.name = "in_hlgGamma",
- .value = buildUniformValue<float>(computeHlgGamma(currentDisplayLuminanceNits))});
- }
-
tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance,
// If the input luminance is unknown, use display luminance (aka,
// no-op any luminance changes)
// This will be the case for eg screenshots in addition to
// uncalibrated displays
.contentMaxLuminance =
- maxLuminance > 0 ? maxLuminance : maxDisplayLuminance};
+ maxLuminance > 0 ? maxLuminance : maxDisplayLuminance,
+ .currentDisplayLuminance = currentDisplayLuminanceNits > 0
+ ? currentDisplayLuminanceNits
+ : maxDisplayLuminance,
+ .buffer = buffer};
for (const auto uniform : tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata)) {
uniforms.push_back(uniform);
@@ -513,4 +504,4 @@
return uniforms;
}
-} // namespace android::shaders
\ No newline at end of file
+} // namespace android::shaders
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
index 99d1b22..dc55586 100644
--- a/libs/tonemap/Android.bp
+++ b/libs/tonemap/Android.bp
@@ -30,9 +30,11 @@
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
"liblog",
+ "libnativewindow",
],
static_libs: [
+ "libarect",
"libmath",
],
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
index b9abf8c..c51016d 100644
--- a/libs/tonemap/include/tonemap/tonemap.h
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -17,6 +17,7 @@
#pragma once
#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <android/hardware_buffer.h>
#include <math/vec3.h>
#include <string>
@@ -44,8 +45,30 @@
struct Metadata {
// The maximum luminance of the display in nits
float displayMaxLuminance = 0.0;
+
// The maximum luminance of the content in nits
float contentMaxLuminance = 0.0;
+
+ // The current brightness of the display in nits
+ float currentDisplayLuminance = 0.0;
+
+ // Reference to an AHardwareBuffer.
+ // Devices that support gralloc 4.0 and higher may attach metadata onto a
+ // particular frame's buffer, including metadata used by HDR-standards like
+ // SMPTE 2086 or SMPTE 2094-40.
+ // Note that this parameter may be optional if there is no hardware buffer
+ // available, for instance if the source content is generated from a GL
+ // texture that does not have associated metadata. As such, implementations
+ // must support nullptr.
+ AHardwareBuffer* buffer = nullptr;
+};
+
+// Utility class containing pre-processed conversions for a particular color
+struct Color {
+ // RGB color in linear space
+ vec3 linearRGB;
+ // CIE 1931 XYZ representation of the color
+ vec3 xyz;
};
class ToneMapper {
@@ -108,14 +131,15 @@
// described by destinationDataspace. To compute the gain, the input colors are provided by
// linearRGB, which is the RGB colors in linear space. The colors in XYZ space are also
// provided. Metadata is also provided for helping to compute the tonemapping curve.
- virtual double lookupTonemapGain(
+ using Gain = double;
+ virtual std::vector<Gain> lookupTonemapGain(
aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
- vec3 linearRGB, vec3 xyz, const Metadata& metadata) = 0;
+ const std::vector<Color>& colors, const Metadata& metadata) = 0;
};
// Retrieves a tonemapper instance.
// This instance is globally constructed.
ToneMapper* getToneMapper();
-} // namespace android::tonemap
\ No newline at end of file
+} // namespace android::tonemap
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
index d519482..26a1d79 100644
--- a/libs/tonemap/tests/Android.bp
+++ b/libs/tonemap/tests/Android.bp
@@ -32,6 +32,7 @@
],
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
+ "libnativewindow",
],
static_libs: [
"libmath",
diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp
index bc0a884..19e1eea 100644
--- a/libs/tonemap/tonemap.cpp
+++ b/libs/tonemap/tonemap.cpp
@@ -48,6 +48,22 @@
return result;
}
+// Refer to BT2100-2
+float computeHlgGamma(float currentDisplayBrightnessNits) {
+ // BT 2100-2's recommendation for taking into account the nominal max
+ // brightness of the display does not work when the current brightness is
+ // very low. For instance, the gamma becomes negative when the current
+ // brightness is between 1 and 2 nits, which would be a bad experience in a
+ // dark environment. Furthermore, BT2100-2 recommends applying
+ // channel^(gamma - 1) as its OOTF, which means that when the current
+ // brightness is lower than 335 nits then channel * channel^(gamma - 1) >
+ // channel, which makes dark scenes very bright. As a workaround for those
+ // problems, lower-bound the brightness to 500 nits.
+ constexpr float minBrightnessNits = 500.f;
+ currentDisplayBrightnessNits = std::max(minBrightnessNits, currentDisplayBrightnessNits);
+ return 1.2 + 0.42 * std::log10(currentDisplayBrightnessNits / 1000);
+}
+
class ToneMapperO : public ToneMapper {
public:
std::string generateTonemapGainShaderSkSL(
@@ -79,11 +95,27 @@
// HLG output.
program.append(R"(
float libtonemap_ToneMapTargetNits(vec3 xyz) {
- return clamp(xyz.y, 0.0, 1000.0);
+ float nits = clamp(xyz.y, 0.0, 1000.0);
+ return nits * pow(nits / 1000.0, -0.2 / 1.2);
}
)");
break;
default:
+ // HLG follows BT2100, but this tonemapping version
+ // does not take into account current display brightness
+ if ((sourceDataspaceInt & kTransferMask) == kTransferHLG) {
+ program.append(R"(
+ float libtonemap_applyBaseOOTFGain(float nits) {
+ return pow(nits, 0.2);
+ }
+ )");
+ } else {
+ program.append(R"(
+ float libtonemap_applyBaseOOTFGain(float nits) {
+ return 1.0;
+ }
+ )");
+ }
// Here we're mapping from HDR to SDR content, so interpolate using a
// Hermitian polynomial onto the smaller luminance range.
program.append(R"(
@@ -91,6 +123,8 @@
float maxInLumi = in_libtonemap_inputMaxLuminance;
float maxOutLumi = in_libtonemap_displayMaxLuminance;
+ xyz = xyz * libtonemap_applyBaseOOTFGain(xyz.y);
+
float nits = xyz.y;
// if the max input luminance is less than what we can
@@ -153,6 +187,21 @@
switch (destinationDataspaceInt & kTransferMask) {
case kTransferST2084:
case kTransferHLG:
+ // HLG follows BT2100, but this tonemapping version
+ // does not take into account current display brightness
+ if ((destinationDataspaceInt & kTransferMask) == kTransferHLG) {
+ program.append(R"(
+ float libtonemap_applyBaseOOTFGain(float nits) {
+ return pow(nits / 1000.0, -0.2 / 1.2);
+ }
+ )");
+ } else {
+ program.append(R"(
+ float libtonemap_applyBaseOOTFGain(float nits) {
+ return 1.0;
+ }
+ )");
+ }
// Map from SDR onto an HDR output buffer
// Here we use a polynomial curve to map from [0, displayMaxLuminance] onto
// [0, maxOutLumi] which is hard-coded to be 3000 nits.
@@ -178,7 +227,7 @@
if (nits <= x0) {
// scale [0.0, x0] to [0.0, y0] linearly
float slope = y0 / x0;
- return nits * slope;
+ nits = nits * slope;
} else if (nits <= x1) {
// scale [x0, x1] to [y0, y1] using a curve
float t = (nits - x0) / (x1 - x0);
@@ -196,7 +245,7 @@
2.0 * (1.0 - t) * t * c3 + t * t * y3;
}
- return nits;
+ return nits * libtonemap_applyBaseOOTFGain(nits);
}
)");
break;
@@ -236,136 +285,152 @@
return uniforms;
}
- double lookupTonemapGain(
+ std::vector<Gain> lookupTonemapGain(
aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
- vec3 /* linearRGB */, vec3 xyz, const Metadata& metadata) override {
- if (xyz.y <= 0.0) {
- return 1.0;
- }
- const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
- const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
+ const std::vector<Color>& colors, const Metadata& metadata) override {
+ std::vector<Gain> gains;
+ gains.reserve(colors.size());
- double targetNits = 0.0;
- switch (sourceDataspaceInt & kTransferMask) {
- case kTransferST2084:
- case kTransferHLG:
- switch (destinationDataspaceInt & kTransferMask) {
- case kTransferST2084:
- targetNits = xyz.y;
- break;
- case kTransferHLG:
- // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
- // we'll clamp the luminance range in case we're mapping from PQ input to
- // HLG output.
- targetNits = std::clamp(xyz.y, 0.0f, 1000.0f);
- break;
- default:
- // Here we're mapping from HDR to SDR content, so interpolate using a
- // Hermitian polynomial onto the smaller luminance range.
+ for (const auto [_, xyz] : colors) {
+ if (xyz.y <= 0.0) {
+ gains.push_back(1.0);
+ continue;
+ }
+ const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
+ const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
- targetNits = xyz.y;
- // if the max input luminance is less than what we can output then
- // no tone mapping is needed as all color values will be in range.
- if (metadata.contentMaxLuminance > metadata.displayMaxLuminance) {
- // three control points
- const double x0 = 10.0;
- const double y0 = 17.0;
- double x1 = metadata.displayMaxLuminance * 0.75;
- double y1 = x1;
- double x2 = x1 + (metadata.contentMaxLuminance - x1) / 2.0;
- double y2 = y1 + (metadata.displayMaxLuminance - y1) * 0.75;
+ double targetNits = 0.0;
+ switch (sourceDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ case kTransferHLG:
+ switch (destinationDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ targetNits = xyz.y;
+ break;
+ case kTransferHLG:
+ // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG,
+ // so we'll clamp the luminance range in case we're mapping from PQ
+ // input to HLG output.
+ targetNits = std::clamp(xyz.y, 0.0f, 1000.0f);
+ targetNits *= std::pow(targetNits / 1000.f, -0.2 / 1.2);
+ break;
+ default:
+ // Here we're mapping from HDR to SDR content, so interpolate using a
+ // Hermitian polynomial onto the smaller luminance range.
- // horizontal distances between the last three control points
- double h12 = x2 - x1;
- double h23 = metadata.contentMaxLuminance - x2;
- // tangents at the last three control points
- double m1 = (y2 - y1) / h12;
- double m3 = (metadata.displayMaxLuminance - y2) / h23;
- double m2 = (m1 + m3) / 2.0;
+ targetNits = xyz.y;
- if (targetNits < x0) {
+ if ((sourceDataspaceInt & kTransferMask) == kTransferHLG) {
+ targetNits *= std::pow(targetNits, 0.2);
+ }
+ // if the max input luminance is less than what we can output then
+ // no tone mapping is needed as all color values will be in range.
+ if (metadata.contentMaxLuminance > metadata.displayMaxLuminance) {
+ // three control points
+ const double x0 = 10.0;
+ const double y0 = 17.0;
+ double x1 = metadata.displayMaxLuminance * 0.75;
+ double y1 = x1;
+ double x2 = x1 + (metadata.contentMaxLuminance - x1) / 2.0;
+ double y2 = y1 + (metadata.displayMaxLuminance - y1) * 0.75;
+
+ // horizontal distances between the last three control points
+ double h12 = x2 - x1;
+ double h23 = metadata.contentMaxLuminance - x2;
+ // tangents at the last three control points
+ double m1 = (y2 - y1) / h12;
+ double m3 = (metadata.displayMaxLuminance - y2) / h23;
+ double m2 = (m1 + m3) / 2.0;
+
+ if (targetNits < x0) {
+ // scale [0.0, x0] to [0.0, y0] linearly
+ double slope = y0 / x0;
+ targetNits *= slope;
+ } else if (targetNits < x1) {
+ // scale [x0, x1] to [y0, y1] linearly
+ double slope = (y1 - y0) / (x1 - x0);
+ targetNits = y0 + (targetNits - x0) * slope;
+ } else if (targetNits < x2) {
+ // scale [x1, x2] to [y1, y2] using Hermite interp
+ double t = (targetNits - x1) / h12;
+ targetNits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) *
+ (1.0 - t) +
+ (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
+ } else {
+ // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite
+ // interp
+ double t = (targetNits - x2) / h23;
+ targetNits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) *
+ (1.0 - t) +
+ (metadata.displayMaxLuminance * (3.0 - 2.0 * t) +
+ h23 * m3 * (t - 1.0)) *
+ t * t;
+ }
+ }
+ break;
+ }
+ break;
+ default:
+ // source is SDR
+ switch (destinationDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ case kTransferHLG: {
+ // Map from SDR onto an HDR output buffer
+ // Here we use a polynomial curve to map from [0, displayMaxLuminance]
+ // onto [0, maxOutLumi] which is hard-coded to be 3000 nits.
+ const double maxOutLumi = 3000.0;
+
+ double x0 = 5.0;
+ double y0 = 2.5;
+ double x1 = metadata.displayMaxLuminance * 0.7;
+ double y1 = maxOutLumi * 0.15;
+ double x2 = metadata.displayMaxLuminance * 0.9;
+ double y2 = maxOutLumi * 0.45;
+ double x3 = metadata.displayMaxLuminance;
+ double y3 = maxOutLumi;
+
+ double c1 = y1 / 3.0;
+ double c2 = y2 / 2.0;
+ double c3 = y3 / 1.5;
+
+ targetNits = xyz.y;
+
+ if (targetNits <= x0) {
// scale [0.0, x0] to [0.0, y0] linearly
double slope = y0 / x0;
targetNits *= slope;
- } else if (targetNits < x1) {
- // scale [x0, x1] to [y0, y1] linearly
- double slope = (y1 - y0) / (x1 - x0);
- targetNits = y0 + (targetNits - x0) * slope;
- } else if (targetNits < x2) {
- // scale [x1, x2] to [y1, y2] using Hermite interp
- double t = (targetNits - x1) / h12;
- targetNits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) *
- (1.0 - t) +
- (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
+ } else if (targetNits <= x1) {
+ // scale [x0, x1] to [y0, y1] using a curve
+ double t = (targetNits - x0) / (x1 - x0);
+ targetNits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 +
+ t * t * y1;
+ } else if (targetNits <= x2) {
+ // scale [x1, x2] to [y1, y2] using a curve
+ double t = (targetNits - x1) / (x2 - x1);
+ targetNits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 +
+ t * t * y2;
} else {
- // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
- double t = (targetNits - x2) / h23;
- targetNits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) *
- (1.0 - t) +
- (metadata.displayMaxLuminance * (3.0 - 2.0 * t) +
- h23 * m3 * (t - 1.0)) *
- t * t;
+ // scale [x2, x3] to [y2, y3] using a curve
+ double t = (targetNits - x2) / (x3 - x2);
+ targetNits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 +
+ t * t * y3;
}
- }
- break;
- }
- break;
- default:
- // source is SDR
- switch (destinationDataspaceInt & kTransferMask) {
- case kTransferST2084:
- case kTransferHLG: {
- // Map from SDR onto an HDR output buffer
- // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto
- // [0, maxOutLumi] which is hard-coded to be 3000 nits.
- const double maxOutLumi = 3000.0;
- double x0 = 5.0;
- double y0 = 2.5;
- double x1 = metadata.displayMaxLuminance * 0.7;
- double y1 = maxOutLumi * 0.15;
- double x2 = metadata.displayMaxLuminance * 0.9;
- double y2 = maxOutLumi * 0.45;
- double x3 = metadata.displayMaxLuminance;
- double y3 = maxOutLumi;
-
- double c1 = y1 / 3.0;
- double c2 = y2 / 2.0;
- double c3 = y3 / 1.5;
-
- targetNits = xyz.y;
-
- if (targetNits <= x0) {
- // scale [0.0, x0] to [0.0, y0] linearly
- double slope = y0 / x0;
- targetNits *= slope;
- } else if (targetNits <= x1) {
- // scale [x0, x1] to [y0, y1] using a curve
- double t = (targetNits - x0) / (x1 - x0);
- targetNits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 +
- t * t * y1;
- } else if (targetNits <= x2) {
- // scale [x1, x2] to [y1, y2] using a curve
- double t = (targetNits - x1) / (x2 - x1);
- targetNits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 +
- t * t * y2;
- } else {
- // scale [x2, x3] to [y2, y3] using a curve
- double t = (targetNits - x2) / (x3 - x2);
- targetNits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 +
- t * t * y3;
- }
- } break;
- default:
- // For completeness, this is tone-mapping from SDR to SDR, where this is
- // just a no-op.
- targetNits = xyz.y;
- break;
- }
+ if ((destinationDataspaceInt & kTransferMask) == kTransferHLG) {
+ targetNits *= std::pow(targetNits / 1000.0, -0.2 / 1.2);
+ }
+ } break;
+ default:
+ // For completeness, this is tone-mapping from SDR to SDR, where this is
+ // just a no-op.
+ targetNits = xyz.y;
+ break;
+ }
+ }
+ gains.push_back(targetNits / xyz.y);
}
-
- return targetNits / xyz.y;
+ return gains;
}
};
@@ -404,6 +469,7 @@
program.append(R"(
uniform float in_libtonemap_displayMaxLuminance;
uniform float in_libtonemap_inputMaxLuminance;
+ uniform float in_libtonemap_hlgGamma;
)");
switch (sourceDataspaceInt & kTransferMask) {
case kTransferST2084:
@@ -421,14 +487,15 @@
// HLG output.
program.append(R"(
float libtonemap_ToneMapTargetNits(float maxRGB) {
- return clamp(maxRGB, 0.0, 1000.0);
+ float nits = clamp(maxRGB, 0.0, 1000.0);
+ float gamma = (1 - in_libtonemap_hlgGamma)
+ / in_libtonemap_hlgGamma;
+ return nits * pow(nits / 1000.0, gamma);
}
)");
break;
default:
- // Here we're mapping from HDR to SDR content, so interpolate using a
- // Hermitian polynomial onto the smaller luminance range.
program.append(R"(
float libtonemap_OETFTone(float channel) {
channel = channel / 10000.0;
@@ -492,8 +559,15 @@
break;
case kTransferHLG:
switch (destinationDataspaceInt & kTransferMask) {
- // HLG -> HDR does not tone-map at all
+ // HLG uses the OOTF from BT 2100.
case kTransferST2084:
+ program.append(R"(
+ float libtonemap_ToneMapTargetNits(float maxRGB) {
+ return maxRGB
+ * pow(maxRGB / 1000.0, in_libtonemap_hlgGamma - 1);
+ }
+ )");
+ break;
case kTransferHLG:
program.append(R"(
float libtonemap_ToneMapTargetNits(float maxRGB) {
@@ -502,13 +576,14 @@
)");
break;
default:
- // libshaders follows BT2100 OOTF, but with a nominal peak display luminance
- // of 1000 nits. Renormalize to max display luminance if we're tone-mapping
- // down to SDR, as libshaders normalizes all SDR output from [0,
- // maxDisplayLumins] -> [0, 1]
+ // Follow BT 2100 and renormalize to max display luminance if we're
+ // tone-mapping down to SDR, as libshaders normalizes all SDR output from
+ // [0, maxDisplayLumins] -> [0, 1]
program.append(R"(
float libtonemap_ToneMapTargetNits(float maxRGB) {
- return maxRGB * in_libtonemap_displayMaxLuminance / 1000.0;
+ return maxRGB
+ * pow(maxRGB / 1000.0, in_libtonemap_hlgGamma - 1)
+ * in_libtonemap_displayMaxLuminance / 1000.0;
}
)");
break;
@@ -540,103 +615,116 @@
// Hardcode the max content luminance to a "reasonable" level
static const constexpr float kContentMaxLuminance = 4000.f;
std::vector<ShaderUniform> uniforms;
- uniforms.reserve(2);
+ uniforms.reserve(3);
uniforms.push_back({.name = "in_libtonemap_displayMaxLuminance",
.value = buildUniformValue<float>(metadata.displayMaxLuminance)});
uniforms.push_back({.name = "in_libtonemap_inputMaxLuminance",
.value = buildUniformValue<float>(kContentMaxLuminance)});
+ uniforms.push_back({.name = "in_libtonemap_hlgGamma",
+ .value = buildUniformValue<float>(
+ computeHlgGamma(metadata.currentDisplayLuminance))});
return uniforms;
}
- double lookupTonemapGain(
+ std::vector<Gain> lookupTonemapGain(
aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
- vec3 linearRGB, vec3 /* xyz */, const Metadata& metadata) override {
- double maxRGB = std::max({linearRGB.r, linearRGB.g, linearRGB.b});
+ const std::vector<Color>& colors, const Metadata& metadata) override {
+ std::vector<Gain> gains;
+ gains.reserve(colors.size());
- if (maxRGB <= 0.0) {
- return 1.0;
- }
+ // Precompute constants for HDR->SDR tonemapping parameters
+ constexpr double maxInLumi = 4000;
+ const double maxOutLumi = metadata.displayMaxLuminance;
- const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
- const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
+ const double x1 = maxOutLumi * 0.65;
+ const double y1 = x1;
- double targetNits = 0.0;
- switch (sourceDataspaceInt & kTransferMask) {
- case kTransferST2084:
- switch (destinationDataspaceInt & kTransferMask) {
- case kTransferST2084:
- targetNits = maxRGB;
- break;
- case kTransferHLG:
- // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
- // we'll clamp the luminance range in case we're mapping from PQ input to
- // HLG output.
- targetNits = std::clamp(maxRGB, 0.0, 1000.0);
- break;
- default:
- // Here we're mapping from HDR to SDR content, so interpolate using a
- // Hermitian polynomial onto the smaller luminance range.
+ const double x3 = maxInLumi;
+ const double y3 = maxOutLumi;
- double maxInLumi = 4000;
- double maxOutLumi = metadata.displayMaxLuminance;
+ const double x2 = x1 + (x3 - x1) * 4.0 / 17.0;
+ const double y2 = maxOutLumi * 0.9;
- targetNits = maxRGB;
+ const double greyNorm1 = OETF_ST2084(x1);
+ const double greyNorm2 = OETF_ST2084(x2);
+ const double greyNorm3 = OETF_ST2084(x3);
- double x1 = maxOutLumi * 0.65;
- double y1 = x1;
+ const double slope2 = (y2 - y1) / (greyNorm2 - greyNorm1);
+ const double slope3 = (y3 - y2) / (greyNorm3 - greyNorm2);
- double x3 = maxInLumi;
- double y3 = maxOutLumi;
+ const double hlgGamma = computeHlgGamma(metadata.currentDisplayLuminance);
- double x2 = x1 + (x3 - x1) * 4.0 / 17.0;
- double y2 = maxOutLumi * 0.9;
+ for (const auto [linearRGB, _] : colors) {
+ double maxRGB = std::max({linearRGB.r, linearRGB.g, linearRGB.b});
- const double greyNorm1 = OETF_ST2084(x1);
- const double greyNorm2 = OETF_ST2084(x2);
- const double greyNorm3 = OETF_ST2084(x3);
+ if (maxRGB <= 0.0) {
+ gains.push_back(1.0);
+ continue;
+ }
- double slope2 = (y2 - y1) / (greyNorm2 - greyNorm1);
- double slope3 = (y3 - y2) / (greyNorm3 - greyNorm2);
+ const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
+ const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
- if (targetNits < x1) {
+ double targetNits = 0.0;
+ switch (sourceDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ switch (destinationDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ targetNits = maxRGB;
break;
- }
-
- if (targetNits > maxInLumi) {
- targetNits = maxOutLumi;
+ case kTransferHLG:
+ // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG,
+ // so we'll clamp the luminance range in case we're mapping from PQ
+ // input to HLG output.
+ targetNits = std::clamp(maxRGB, 0.0, 1000.0);
+ targetNits *= pow(targetNits / 1000.0, (1 - hlgGamma) / (hlgGamma));
break;
- }
+ default:
+ targetNits = maxRGB;
+ if (targetNits < x1) {
+ break;
+ }
- const double greyNits = OETF_ST2084(targetNits);
+ if (targetNits > maxInLumi) {
+ targetNits = maxOutLumi;
+ break;
+ }
- if (greyNits <= greyNorm2) {
- targetNits = (greyNits - greyNorm2) * slope2 + y2;
- } else if (greyNits <= greyNorm3) {
- targetNits = (greyNits - greyNorm3) * slope3 + y3;
- } else {
- targetNits = maxOutLumi;
- }
- break;
- }
- break;
- case kTransferHLG:
- switch (destinationDataspaceInt & kTransferMask) {
- case kTransferST2084:
- case kTransferHLG:
- targetNits = maxRGB;
- break;
- default:
- targetNits = maxRGB * metadata.displayMaxLuminance / 1000.0;
- break;
- }
- break;
- default:
- targetNits = maxRGB;
- break;
+ const double greyNits = OETF_ST2084(targetNits);
+
+ if (greyNits <= greyNorm2) {
+ targetNits = (greyNits - greyNorm2) * slope2 + y2;
+ } else if (greyNits <= greyNorm3) {
+ targetNits = (greyNits - greyNorm3) * slope3 + y3;
+ } else {
+ targetNits = maxOutLumi;
+ }
+ break;
+ }
+ break;
+ case kTransferHLG:
+ switch (destinationDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ targetNits = maxRGB * pow(maxRGB / 1000.0, hlgGamma - 1);
+ break;
+ case kTransferHLG:
+ targetNits = maxRGB;
+ break;
+ default:
+ targetNits = maxRGB * pow(maxRGB / 1000.0, hlgGamma - 1) *
+ metadata.displayMaxLuminance / 1000.0;
+ break;
+ }
+ break;
+ default:
+ targetNits = maxRGB;
+ break;
+ }
+
+ gains.push_back(targetNits / maxRGB);
}
-
- return targetNits / maxRGB;
+ return gains;
}
};
@@ -658,4 +746,4 @@
return sToneMapper.get();
}
-} // namespace android::tonemap
\ No newline at end of file
+} // namespace android::tonemap
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 1a42642..c72ae1b 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -358,20 +358,19 @@
if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
continue;
}
- if (0 != planeLayoutComponent.offsetInBits % 8) {
- unlock(bufferHandle);
- return BAD_VALUE;
- }
- uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes +
- (planeLayoutComponent.offsetInBits / 8);
+ uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes;
+
+ // Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010)
+ // but we still want to point to the start of the first byte.
+ tmpData += (planeLayoutComponent.offsetInBits / 8);
+
uint64_t sampleIncrementInBytes;
auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
switch (type) {
case PlaneLayoutComponentType::Y:
- if ((ycbcr.y != nullptr) || (planeLayoutComponent.sizeInBits != 8) ||
- (planeLayout.sampleIncrementInBits != 8)) {
+ if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) {
unlock(bufferHandle);
return BAD_VALUE;
}
@@ -387,7 +386,8 @@
}
sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
- if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2)) {
+ if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
+ (sampleIncrementInBytes != 4)) {
unlock(bufferHandle);
return BAD_VALUE;
}
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 73b63e3..3a4b6c5 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -334,60 +334,50 @@
QueuedInputListener::QueuedInputListener(InputListenerInterface& innerListener)
: mInnerListener(innerListener) {}
-QueuedInputListener::~QueuedInputListener() {
- size_t count = mArgsQueue.size();
- for (size_t i = 0; i < count; i++) {
- delete mArgsQueue[i];
- }
-}
-
void QueuedInputListener::notifyConfigurationChanged(
const NotifyConfigurationChangedArgs* args) {
traceEvent(__func__, args->id);
- mArgsQueue.push_back(new NotifyConfigurationChangedArgs(*args));
+ mArgsQueue.emplace_back(std::make_unique<NotifyConfigurationChangedArgs>(*args));
}
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
traceEvent(__func__, args->id);
- mArgsQueue.push_back(new NotifyKeyArgs(*args));
+ mArgsQueue.emplace_back(std::make_unique<NotifyKeyArgs>(*args));
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
traceEvent(__func__, args->id);
- mArgsQueue.push_back(new NotifyMotionArgs(*args));
+ mArgsQueue.emplace_back(std::make_unique<NotifyMotionArgs>(*args));
}
void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
traceEvent(__func__, args->id);
- mArgsQueue.push_back(new NotifySwitchArgs(*args));
+ mArgsQueue.emplace_back(std::make_unique<NotifySwitchArgs>(*args));
}
void QueuedInputListener::notifySensor(const NotifySensorArgs* args) {
traceEvent(__func__, args->id);
- mArgsQueue.push_back(new NotifySensorArgs(*args));
+ mArgsQueue.emplace_back(std::make_unique<NotifySensorArgs>(*args));
}
void QueuedInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) {
traceEvent(__func__, args->id);
- mArgsQueue.push_back(new NotifyVibratorStateArgs(*args));
+ mArgsQueue.emplace_back(std::make_unique<NotifyVibratorStateArgs>(*args));
}
void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
traceEvent(__func__, args->id);
- mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
+ mArgsQueue.emplace_back(std::make_unique<NotifyDeviceResetArgs>(*args));
}
void QueuedInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
traceEvent(__func__, args->id);
- mArgsQueue.push_back(new NotifyPointerCaptureChangedArgs(*args));
+ mArgsQueue.emplace_back(std::make_unique<NotifyPointerCaptureChangedArgs>(*args));
}
void QueuedInputListener::flush() {
- size_t count = mArgsQueue.size();
- for (size_t i = 0; i < count; i++) {
- NotifyArgs* args = mArgsQueue[i];
+ for (const std::unique_ptr<NotifyArgs>& args : mArgsQueue) {
args->notify(mInnerListener);
- delete args;
}
mArgsQueue.clear();
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 06ad6a8..c8a3ccf 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -556,6 +556,17 @@
entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_ERASER);
}
+// Determines if the given window can be targeted as InputTarget::FLAG_FOREGROUND.
+// Foreground events are only sent to "foreground targetable" windows, but not all gestures sent to
+// such window are necessarily targeted with the flag. For example, an event with ACTION_OUTSIDE can
+// be sent to such a window, but it is not a foreground event and doesn't use
+// InputTarget::FLAG_FOREGROUND.
+bool canReceiveForegroundTouches(const WindowInfo& info) {
+ // A non-touchable window can still receive touch events (e.g. in the case of
+ // STYLUS_INTERCEPTOR), so prevent such windows from receiving foreground events for touches.
+ return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy();
+}
+
} // namespace
// --- InputDispatcher ---
@@ -1032,6 +1043,21 @@
}
}
}
+
+ // If a new up event comes in, and the pending event with same key code has been asked
+ // to try again later because of the policy. We have to reset the intercept key wake up
+ // time for it may have been handled in the policy and could be dropped.
+ if (keyEntry.action == AKEY_EVENT_ACTION_UP && mPendingEvent &&
+ mPendingEvent->type == EventEntry::Type::KEY) {
+ KeyEntry& pendingKey = static_cast<KeyEntry&>(*mPendingEvent);
+ if (pendingKey.keyCode == keyEntry.keyCode &&
+ pendingKey.interceptKeyResult ==
+ KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
+ pendingKey.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
+ pendingKey.interceptKeyWakeupTime = 0;
+ needWake = true;
+ }
+ }
break;
}
@@ -2188,8 +2214,8 @@
// Set target flags.
int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;
- if (!info.isSpy()) {
- // There should only be one new foreground (non-spy) window at this location.
+ if (canReceiveForegroundTouches(*windowHandle->getInfo())) {
+ // There should only be one touched window that can be "foreground" for the pointer.
targetFlags |= InputTarget::FLAG_FOREGROUND;
}
@@ -2262,8 +2288,10 @@
isSplit = !isFromMouse;
}
- int32_t targetFlags =
- InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
+ int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
+ if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) {
+ targetFlags |= InputTarget::FLAG_FOREGROUND;
+ }
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
}
@@ -2312,13 +2340,15 @@
}
}
- // Ensure that we have at least one foreground or spy window. It's possible that we dropped some
- // of the touched windows we previously found if they became paused or unresponsive or were
- // removed.
+ // Ensure that we have at least one foreground window or at least one window that cannot be a
+ // foreground target. If we only have windows that are not receiving foreground touches (e.g. we
+ // only have windows getting ACTION_OUTSIDE), then drop the event, because there is no window
+ // that is actually receiving the entire gesture.
if (std::none_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
[](const TouchedWindow& touchedWindow) {
- return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 ||
- touchedWindow.windowHandle->getInfo()->isSpy();
+ return !canReceiveForegroundTouches(
+ *touchedWindow.windowHandle->getInfo()) ||
+ (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0;
})) {
ALOGI("Dropping event because there is no touched window on display %d to receive it.",
displayId);
@@ -5057,9 +5087,11 @@
state->removeWindowByToken(fromToken);
// Add new window.
- int32_t newTargetFlags = oldTargetFlags &
- (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT |
- InputTarget::FLAG_DISPATCH_AS_IS);
+ 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);
// Store the dragging window.
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index dff5894..d9822ce 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -274,7 +274,6 @@
public:
explicit QueuedInputListener(InputListenerInterface& innerListener);
- virtual ~QueuedInputListener();
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
virtual void notifyKey(const NotifyKeyArgs* args) override;
@@ -289,7 +288,7 @@
private:
InputListenerInterface& mInnerListener;
- std::vector<NotifyArgs*> mArgsQueue;
+ std::vector<std::unique_ptr<NotifyArgs>> mArgsQueue;
};
} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 9633932..bf58705 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -289,6 +289,13 @@
ASSERT_EQ(token, *receivedToken);
}
+ /**
+ * Set policy timeout. A value of zero means next key will not be intercepted.
+ */
+ void setInterceptKeyTimeout(std::chrono::milliseconds timeout) {
+ mInterceptKeyTimeout = timeout;
+ }
+
private:
std::mutex mLock;
std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
@@ -311,6 +318,8 @@
sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;
+ std::chrono::milliseconds mInterceptKeyTimeout = 0ms;
+
// All three ANR-related callbacks behave the same way, so we use this generic function to wait
// for a specific container to become non-empty. When the container is non-empty, return the
// first entry from the container and erase it.
@@ -429,12 +438,20 @@
return true;
}
- void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {}
+ void interceptKeyBeforeQueueing(const KeyEvent* inputEvent, uint32_t&) override {
+ if (inputEvent->getAction() == AKEY_EVENT_ACTION_UP) {
+ // Clear intercept state when we handled the event.
+ mInterceptKeyTimeout = 0ms;
+ }
+ }
void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {}
nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*, uint32_t) override {
- return 0;
+ nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count();
+ // Clear intercept state so we could dispatch the event in next wake.
+ mInterceptKeyTimeout = 0ms;
+ return delay;
}
bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t, KeyEvent*) override {
@@ -2182,6 +2199,50 @@
0 /*expectedFlags*/);
}
+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);
+ window->setFocusable(true);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ const std::chrono::milliseconds interceptKeyTimeout = 50ms;
+ const nsecs_t injectTime = keyArgs.eventTime;
+ mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
+ mDispatcher->notifyKey(&keyArgs);
+ // The dispatching time should be always greater than or equal to intercept key timeout.
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+ ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
+ std::chrono::nanoseconds(interceptKeyTimeout).count());
+}
+
+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);
+ window->setFocusable(true);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mFakePolicy->setInterceptKeyTimeout(150ms);
+ mDispatcher->notifyKey(&keyDown);
+ mDispatcher->notifyKey(&keyUp);
+
+ // Window should receive key event immediately when same key up.
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+}
+
/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
@@ -6854,4 +6915,38 @@
window->assertNoEvents();
}
+/**
+ * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
+ * The scenario is as follows:
+ * - The stylus interceptor overlay is configured as a spy window.
+ * - The stylus interceptor spy receives the start of a new stylus gesture.
+ * - It pilfers pointers and then configures itself to no longer be a spy.
+ * - The stylus interceptor continues to receive the rest of the gesture.
+ */
+TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
+ auto [overlay, window] = setupStylusOverlayScenario();
+ overlay->setSpy(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
+
+ sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
+ overlay->consumeMotionDown();
+ window->consumeMotionDown();
+
+ // The interceptor pilfers the pointers.
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
+ window->consumeMotionCancel();
+
+ // The interceptor configures itself so that it is no longer a spy.
+ overlay->setSpy(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
+
+ // It continues to receive the rest of the stylus gesture.
+ sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
+ overlay->consumeMotionMove();
+ sendStylusEvent(AMOTION_EVENT_ACTION_UP);
+ overlay->consumeMotionUp();
+
+ window->assertNoEvents();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3c164aa..8b81d48 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -2030,7 +2030,9 @@
// Runtime permissions can't use the cache as they may change.
if (sensor.isRequiredPermissionRuntime()) {
hasPermission = checkPermission(String16(requiredPermission),
- IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid(),
+ /*logPermissionFailure=*/ false);
} else {
hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission));
}
@@ -2211,7 +2213,8 @@
int targetSdk = getTargetSdkVersion(opPackageName);
bool hasSamplingRatePermission = checkPermission(sAccessHighSensorSamplingRatePermission,
IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
+ IPCThreadState::self()->getCallingUid(),
+ /*logPermissionFailure=*/ false);
if (targetSdk < __ANDROID_API_S__ ||
(targetSdk >= __ANDROID_API_S__ && hasSamplingRatePermission)) {
return false;
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 0b23a5a..635b088 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -404,7 +404,7 @@
}
if (display) {
- const Fps refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
const std::optional<Fps> renderRate =
mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 6a3fcb7..16cb41b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -56,9 +56,6 @@
// similar requests if needed.
virtual void createClientCompositionCache(uint32_t cacheSize) = 0;
- // Returns the boot display mode preferred by HWC.
- virtual int32_t getPreferredBootHwcConfigId() const = 0;
-
protected:
~Display() = default;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 58d2530..e12d1b4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -62,7 +62,6 @@
bool isSecure() const override;
bool isVirtual() const override;
void disconnect() override;
- int32_t getPreferredBootHwcConfigId() const override;
void createDisplayColorProfile(
const compositionengine::DisplayColorProfileCreationArgs&) override;
void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override;
@@ -88,7 +87,6 @@
DisplayId mId;
bool mIsDisconnected = false;
Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
- int32_t mPreferredBootHwcConfigId = -1;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 6a75283..2165e1d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -58,16 +58,6 @@
editState().isSecure = args.isSecure;
editState().displaySpace.setBounds(args.pixels);
setName(args.name);
- bool isBootModeSupported = getCompositionEngine().getHwComposer().getBootDisplayModeSupport();
- const auto physicalId = PhysicalDisplayId::tryCast(mId);
- if (!physicalId || !isBootModeSupported) {
- return;
- }
- std::optional<hal::HWConfigId> preferredBootModeId =
- getCompositionEngine().getHwComposer().getPreferredBootDisplayMode(*physicalId);
- if (preferredBootModeId.has_value()) {
- mPreferredBootHwcConfigId = static_cast<int32_t>(preferredBootModeId.value());
- }
}
bool Display::isValid() const {
@@ -90,10 +80,6 @@
return mId;
}
-int32_t Display::getPreferredBootHwcConfigId() const {
- return mPreferredBootHwcConfigId;
-}
-
void Display::disconnect() {
if (mIsDisconnected) {
return;
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index aef55d4..4e67a63 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -684,8 +684,10 @@
visibleNonShadowRegion.intersect(outputState.layerStackSpace.getContent()));
outputLayerState.shadowRegion = shadowRegion;
outputLayerState.outputSpaceBlockingRegionHint =
- layerFEState->compositionType == Composition::DISPLAY_DECORATION ? transparentRegion
- : Region();
+ layerFEState->compositionType == Composition::DISPLAY_DECORATION
+ ? outputState.transform.transform(
+ transparentRegion.intersect(outputState.layerStackSpace.getContent()))
+ : Region();
}
void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 6749427..da1f7e4 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -61,6 +61,9 @@
dumpVal(out, "shadowRegion", shadowRegion);
out.append(" ");
+ dumpVal(out, "outputSpaceBlockingRegionHint", outputSpaceBlockingRegionHint);
+
+ out.append(" ");
dumpVal(out, "forceClientComposition", forceClientComposition);
dumpVal(out, "clearClientTarget", clearClientTarget);
dumpVal(out, "displayFrame", displayFrame);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index cd03235..5cc0f97 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -165,7 +165,6 @@
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mHwComposer, getBootDisplayModeSupport()).WillRepeatedly(Return(false));
}
DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 1f1dd1a..af013b0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -112,8 +112,8 @@
MOCK_METHOD1(getPreferredBootDisplayMode, std::optional<hal::HWConfigId>(PhysicalDisplayId));
MOCK_METHOD0(getBootDisplayModeSupport, bool());
MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool));
- MOCK_METHOD2(getSupportedContentTypes,
- status_t(PhysicalDisplayId, std::vector<hal::ContentType>*));
+ MOCK_METHOD(status_t, getSupportedContentTypes,
+ (PhysicalDisplayId, std::vector<hal::ContentType>*), (const, override));
MOCK_METHOD2(setContentType, status_t(PhysicalDisplayId, hal::ContentType));
MOCK_CONST_METHOD0(getSupportedLayerGenericMetadata,
const std::unordered_map<std::string, bool>&());
@@ -134,7 +134,9 @@
std::optional<aidl::android::hardware::graphics::common::
DisplayDecorationSupport>* support));
MOCK_METHOD2(setIdleTimerEnabled, status_t(PhysicalDisplayId, std::chrono::milliseconds));
- MOCK_METHOD1(hasDisplayIdleTimerCapability, bool(PhysicalDisplayId displayId));
+ MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (PhysicalDisplayId), (const, override));
+ MOCK_METHOD(Hwc2::AidlTransform, getPhysicalDisplayOrientation, (PhysicalDisplayId),
+ (const, override));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 54eb8f8..dd3858b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -1310,6 +1310,8 @@
static const Region kLowerHalfBoundsNoRotation;
static const Region kFullBounds90Rotation;
static const Region kTransparentRegionHint;
+ static const Region kTransparentRegionHintTwo;
+ static const Region kTransparentRegionHintTwo90Rotation;
StrictMock<OutputPartialMock> mOutput;
LayerFESet mGeomSnapshots;
@@ -1329,6 +1331,10 @@
Region(Rect(0, 0, 200, 100));
const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHint =
Region(Rect(0, 0, 100, 100));
+const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintTwo =
+ Region(Rect(25, 20, 50, 75));
+const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintTwo90Rotation =
+ Region(Rect(125, 25, 180, 50));
TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
@@ -1779,6 +1785,25 @@
EXPECT_THAT(mLayer.outputLayerState.outputSpaceBlockingRegionHint, RegionEq(Region()));
}
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, blockingRegionIsInOutputSpace) {
+ mLayer.layerFEState.isOpaque = false;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.compositionType =
+ aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
+ mLayer.layerFEState.transparentRegionHint = kTransparentRegionHintTwo;
+
+ mOutput.mState.layerStackSpace.setContent(Rect(0, 0, 300, 200));
+ mOutput.mState.transform = ui::Transform(TR_ROT_90, 200, 300);
+
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
+ ensureOutputLayerIfVisible();
+
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceBlockingRegionHint,
+ RegionEq(kTransparentRegionHintTwo90Rotation));
+}
+
/*
* Output::present()
*/
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 45b98bb..f5a4b3d 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -196,7 +196,7 @@
ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue());
mActiveMode = mode;
if (mRefreshRateConfigs) {
- mRefreshRateConfigs->setCurrentModeId(mActiveMode->getId());
+ mRefreshRateConfigs->setActiveModeId(mActiveMode->getId());
}
if (mRefreshRateOverlay) {
mRefreshRateOverlay->changeRefreshRate(mActiveMode->getFps());
@@ -227,21 +227,18 @@
}
DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const {
- const auto it = std::find_if(mSupportedModes.begin(), mSupportedModes.end(),
- [&](DisplayModePtr mode) { return mode->getId() == modeId; });
- if (it != mSupportedModes.end()) {
- return *it;
- }
- return nullptr;
+ const DisplayModePtr nullMode;
+ return mSupportedModes.get(modeId).value_or(std::cref(nullMode));
}
-DisplayModePtr DisplayDevice::getModefromHwcId(uint32_t hwcId) const {
- const auto it = std::find_if(mSupportedModes.begin(), mSupportedModes.end(),
- [&](DisplayModePtr mode) { return mode->getHwcId() == hwcId; });
+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;
+ return it->second->getId();
}
- return nullptr;
+ return {};
}
nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
@@ -364,12 +361,12 @@
activeMode ? to_string(*activeMode).c_str() : "none");
result.append(" supportedModes=\n");
-
- for (const auto& mode : mSupportedModes) {
- result.append(" ");
+ for (const auto& [id, mode] : mSupportedModes) {
+ result.append(" ");
result.append(to_string(*mode));
- result.append("\n");
+ result.push_back('\n');
}
+
StringAppendF(&result, " deviceProductInfo=");
if (mDeviceProductInfo) {
mDeviceProductInfo->dump(result);
@@ -468,16 +465,6 @@
capabilities.getDesiredMinLuminance());
}
-ui::DisplayModeId DisplayDevice::getPreferredBootModeId() const {
- const auto preferredBootHwcModeId = mCompositionDisplay->getPreferredBootHwcConfigId();
- const auto mode = getModefromHwcId(preferredBootHwcModeId);
- if (mode == nullptr) {
- ALOGE("%s: invalid display mode (%d)", __FUNCTION__, preferredBootHwcModeId);
- return BAD_VALUE;
- }
- return mode->getId().value();
-}
-
void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) {
if (!enable) {
mRefreshRateOverlay.reset();
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 690f240..d5d87b4 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -21,6 +21,7 @@
#include <string>
#include <unordered_map>
+#include <android-base/thread_annotations.h>
#include <android/native_window.h>
#include <binder/IBinder.h>
#include <gui/LayerState.h>
@@ -28,6 +29,7 @@
#include <renderengine/RenderEngine.h>
#include <system/window.h>
#include <ui/DisplayId.h>
+#include <ui/DisplayIdentification.h>
#include <ui/DisplayState.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
@@ -39,15 +41,11 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include "MainThreadGuard.h"
-
-#include <ui/DisplayIdentification.h>
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/Hal.h"
#include "DisplayHardware/PowerAdvisor.h"
-
#include "Scheduler/RefreshRateConfigs.h"
-
+#include "ThreadContext.h"
#include "TracedOrdinal.h"
namespace android {
@@ -99,9 +97,9 @@
void setLayerStack(ui::LayerStack);
void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
- void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD);
- void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
- bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD);
+ void stageBrightness(float brightness) REQUIRES(kMainThreadContext);
+ void persistBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
+ bool isBrightnessStale() const REQUIRES(kMainThreadContext);
void setFlags(uint32_t flags);
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
@@ -109,7 +107,7 @@
static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
- std::optional<float> getStagedBrightness() const REQUIRES(SF_MAIN_THREAD);
+ std::optional<float> getStagedBrightness() const REQUIRES(kMainThreadContext);
ui::Transform::RotationFlags getTransformHint() const;
const ui::Transform& getTransform() const;
const Rect& getLayerStackSpaceRect() const;
@@ -157,9 +155,6 @@
// respectively if hardware composer doesn't return meaningful values.
HdrCapabilities getHdrCapabilities() const;
- // Returns the boot display mode preferred by the implementation.
- ui::DisplayModeId getPreferredBootModeId() const;
-
// Return true if intent is supported by the display.
bool hasRenderIntent(ui::RenderIntent intent) const;
@@ -212,15 +207,15 @@
bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
- ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) {
+ ActiveModeInfo getUpcomingActiveMode() const REQUIRES(kMainThreadContext) {
return mUpcomingActiveMode;
}
- void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD);
+ void setActiveMode(DisplayModeId) REQUIRES(kMainThreadContext);
status_t initiateModeChange(const ActiveModeInfo&,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline)
- REQUIRES(SF_MAIN_THREAD);
+ 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.
@@ -232,8 +227,7 @@
// set-top boxes after a hotplug reconnect.
DisplayModePtr getMode(DisplayModeId) const;
- // Returns nullptr if the given mode ID is not supported.
- DisplayModePtr getModefromHwcId(uint32_t) const;
+ std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const;
// Returns the refresh rate configs for this display.
scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; }
@@ -308,7 +302,7 @@
ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
TracedOrdinal<bool> mDesiredActiveModeChanged
GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
- ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD);
+ ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 92592f7..297a776 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -247,8 +247,8 @@
case OptionalFeature::RefreshRateSwitching:
case OptionalFeature::ExpectedPresentTime:
case OptionalFeature::DisplayBrightnessCommand:
- case OptionalFeature::BootDisplayConfig:
case OptionalFeature::KernelIdleTimer:
+ case OptionalFeature::PhysicalDisplayOrientation:
return true;
}
}
@@ -1126,5 +1126,17 @@
return Error::NONE;
}
+Error AidlComposer::getPhysicalDisplayOrientation(Display displayId,
+ AidlTransform* outDisplayOrientation) {
+ const auto status =
+ mAidlComposerClient->getDisplayPhysicalOrientation(translate<int64_t>(displayId),
+ outDisplayOrientation);
+ if (!status.isOk()) {
+ ALOGE("getPhysicalDisplayOrientation failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 6c0f636..28ff167 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -223,6 +223,9 @@
std::optional<DisplayDecorationSupport>* support) override;
Error setIdleTimerEnabled(Display displayId, std::chrono::milliseconds timeout) override;
+ Error getPhysicalDisplayOrientation(Display displayId,
+ AidlTransform* outDisplayOrientation) override;
+
private:
// Many public functions above simply write a command into the command
// queue to batch the calls. validateDisplay and presentDisplay will call
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 6abe7d1..2dc0830 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -38,6 +38,7 @@
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
+#include <aidl/android/hardware/graphics/common/Transform.h>
#include <optional>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -80,6 +81,7 @@
using PerFrameMetadata = IComposerClient::PerFrameMetadata;
using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob;
+using AidlTransform = ::aidl::android::hardware::graphics::common::Transform;
class Composer {
public:
@@ -92,8 +94,8 @@
ExpectedPresentTime,
// Whether setDisplayBrightness is able to be applied as part of a display command.
DisplayBrightnessCommand,
- BootDisplayConfig,
KernelIdleTimer,
+ PhysicalDisplayOrientation,
};
virtual bool isSupported(OptionalFeature) const = 0;
@@ -277,6 +279,8 @@
std::optional<::aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
virtual Error setIdleTimerEnabled(Display displayId, std::chrono::milliseconds timeout) = 0;
+ virtual Error getPhysicalDisplayOrientation(Display displayId,
+ AidlTransform* outDisplayOrientation) = 0;
};
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 0ab9605..61a9a08 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -18,10 +18,10 @@
#include <cstddef>
#include <memory>
-#include <vector>
#include <android-base/stringprintf.h>
#include <android/configuration.h>
+#include <ftl/small_map.h>
#include <ui/DisplayId.h>
#include <ui/DisplayMode.h>
#include <ui/Size.h>
@@ -38,8 +38,17 @@
class DisplayMode;
using DisplayModePtr = std::shared_ptr<const DisplayMode>;
-using DisplayModes = std::vector<DisplayModePtr>;
-using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, Compare, Hash>;
+
+// Prevent confusion with fps_approx_ops on the underlying Fps.
+bool operator<(const DisplayModePtr&, const DisplayModePtr&) = delete;
+bool operator>(const DisplayModePtr&, const DisplayModePtr&) = delete;
+bool operator<=(const DisplayModePtr&, const DisplayModePtr&) = delete;
+bool operator>=(const DisplayModePtr&, const DisplayModePtr&) = delete;
+
+using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, Compare>;
+
+using DisplayModes = ftl::SmallMap<DisplayModeId, DisplayModePtr, 3>;
+using DisplayModeIterator = DisplayModes::const_iterator;
class DisplayMode {
public:
@@ -61,35 +70,30 @@
return *this;
}
- Builder& setWidth(int32_t width) {
- mDisplayMode->mWidth = width;
+ Builder& setResolution(ui::Size resolution) {
+ mDisplayMode->mResolution = resolution;
return *this;
}
- Builder& setHeight(int32_t height) {
- mDisplayMode->mHeight = height;
- return *this;
- }
-
- Builder& setVsyncPeriod(int32_t vsyncPeriod) {
+ Builder& setVsyncPeriod(nsecs_t vsyncPeriod) {
mDisplayMode->mFps = Fps::fromPeriodNsecs(vsyncPeriod);
return *this;
}
Builder& setDpiX(int32_t dpiX) {
if (dpiX == -1) {
- mDisplayMode->mDpiX = getDefaultDensity();
+ mDisplayMode->mDpi.x = getDefaultDensity();
} else {
- mDisplayMode->mDpiX = dpiX / 1000.0f;
+ mDisplayMode->mDpi.x = dpiX / 1000.f;
}
return *this;
}
Builder& setDpiY(int32_t dpiY) {
if (dpiY == -1) {
- mDisplayMode->mDpiY = getDefaultDensity();
+ mDisplayMode->mDpi.y = getDefaultDensity();
} else {
- mDisplayMode->mDpiY = dpiY / 1000.0f;
+ mDisplayMode->mDpi.y = dpiY / 1000.f;
}
return *this;
}
@@ -107,59 +111,76 @@
// information to begin with. This is also used for virtual displays and
// older HWC implementations, so be careful about orientation.
- auto longDimension = std::max(mDisplayMode->mWidth, mDisplayMode->mHeight);
- if (longDimension >= 1080) {
+ if (std::max(mDisplayMode->getWidth(), mDisplayMode->getHeight()) >= 1080) {
return ACONFIGURATION_DENSITY_XHIGH;
} else {
return ACONFIGURATION_DENSITY_TV;
}
}
+
std::shared_ptr<DisplayMode> mDisplayMode;
};
DisplayModeId getId() const { return mId; }
+
hal::HWConfigId getHwcId() const { return mHwcId; }
PhysicalDisplayId getPhysicalDisplayId() const { return mPhysicalDisplayId; }
- int32_t getWidth() const { return mWidth; }
- int32_t getHeight() const { return mHeight; }
- ui::Size getSize() const { return {mWidth, mHeight}; }
+ ui::Size getResolution() const { return mResolution; }
+ int32_t getWidth() const { return mResolution.getWidth(); }
+ int32_t getHeight() const { return mResolution.getHeight(); }
+
Fps getFps() const { return mFps; }
nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); }
- float getDpiX() const { return mDpiX; }
- float getDpiY() const { return mDpiY; }
+
+ struct Dpi {
+ float x = -1;
+ float y = -1;
+
+ bool operator==(Dpi other) const { return x == other.x && y == other.y; }
+ };
+
+ Dpi getDpi() const { return mDpi; }
// Switches between modes in the same group are seamless, i.e.
// without visual interruptions such as a black screen.
int32_t getGroup() const { return mGroup; }
- bool equalsExceptDisplayModeId(const DisplayModePtr& other) const {
- return mHwcId == other->mHwcId && mWidth == other->mWidth && mHeight == other->mHeight &&
- getVsyncPeriod() == other->getVsyncPeriod() && mDpiX == other->mDpiX &&
- mDpiY == other->mDpiY && mGroup == other->mGroup;
- }
-
private:
explicit DisplayMode(hal::HWConfigId id) : mHwcId(id) {}
- hal::HWConfigId mHwcId;
+ const hal::HWConfigId mHwcId;
DisplayModeId mId;
+
PhysicalDisplayId mPhysicalDisplayId;
- int32_t mWidth = -1;
- int32_t mHeight = -1;
+ ui::Size mResolution;
Fps mFps;
- float mDpiX = -1;
- float mDpiY = -1;
+ Dpi mDpi;
int32_t mGroup = -1;
};
+inline bool equalsExceptDisplayModeId(const DisplayMode& lhs, const DisplayMode& rhs) {
+ return lhs.getHwcId() == rhs.getHwcId() && lhs.getResolution() == rhs.getResolution() &&
+ lhs.getVsyncPeriod() == rhs.getVsyncPeriod() && lhs.getDpi() == rhs.getDpi() &&
+ lhs.getGroup() == rhs.getGroup();
+}
+
inline std::string to_string(const DisplayMode& mode) {
- return base::StringPrintf("{id=%d, hwcId=%d, width=%d, height=%d, refreshRate=%s, "
- "dpiX=%.2f, dpiY=%.2f, group=%d}",
+ return base::StringPrintf("{id=%d, hwcId=%d, resolution=%dx%d, refreshRate=%s, "
+ "dpi=%.2fx%.2f, group=%d}",
mode.getId().value(), mode.getHwcId(), mode.getWidth(),
- mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(),
- mode.getDpiY(), mode.getGroup());
+ mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpi().x,
+ mode.getDpi().y, mode.getGroup());
+}
+
+template <typename... DisplayModePtrs>
+inline DisplayModes makeModes(const DisplayModePtrs&... modePtrs) {
+ DisplayModes modes;
+ // Note: The omission of std::move(modePtrs) is intentional, because order of evaluation for
+ // arguments is unspecified.
+ (modes.try_emplace(modePtrs->getId(), modePtrs), ...);
+ return modes;
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 6501276..c0432bf 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -154,6 +154,11 @@
isCapabilitySupported;
}
+Error Display::getPhysicalDisplayOrientation(Hwc2::AidlTransform* outTransform) const {
+ auto error = mComposer.getPhysicalDisplayOrientation(mId, outTransform);
+ return static_cast<Error>(error);
+}
+
Error Display::getChangedCompositionTypes(std::unordered_map<HWC2::Layer*, Composition>* outTypes) {
std::vector<Hwc2::Layer> layerIds;
std::vector<Composition> types;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index c03cede..a805566 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -94,81 +94,79 @@
virtual bool hasDisplayIdleTimerCapability() const = 0;
virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0;
- [[clang::warn_unused_result]] virtual hal::Error acceptChanges() = 0;
- [[clang::warn_unused_result]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>
+ [[nodiscard]] virtual hal::Error acceptChanges() = 0;
+ [[nodiscard]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>
createLayer() = 0;
- [[clang::warn_unused_result]] virtual hal::Error getChangedCompositionTypes(
+ [[nodiscard]] virtual hal::Error getChangedCompositionTypes(
std::unordered_map<Layer*, aidl::android::hardware::graphics::composer3::Composition>*
outTypes) = 0;
- [[clang::warn_unused_result]] virtual hal::Error getColorModes(
- std::vector<hal::ColorMode>* outModes) const = 0;
+ [[nodiscard]] virtual hal::Error getColorModes(std::vector<hal::ColorMode>* outModes) const = 0;
// Returns a bitmask which contains HdrMetadata::Type::*.
- [[clang::warn_unused_result]] virtual int32_t getSupportedPerFrameMetadata() const = 0;
- [[clang::warn_unused_result]] virtual hal::Error getRenderIntents(
+ [[nodiscard]] virtual int32_t getSupportedPerFrameMetadata() const = 0;
+ [[nodiscard]] virtual hal::Error getRenderIntents(
hal::ColorMode colorMode, std::vector<hal::RenderIntent>* outRenderIntents) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error getDataspaceSaturationMatrix(
- hal::Dataspace dataspace, android::mat4* outMatrix) = 0;
+ [[nodiscard]] virtual hal::Error getDataspaceSaturationMatrix(hal::Dataspace dataspace,
+ android::mat4* outMatrix) = 0;
- [[clang::warn_unused_result]] virtual hal::Error getName(std::string* outName) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error getRequests(
+ [[nodiscard]] virtual hal::Error getName(std::string* outName) const = 0;
+ [[nodiscard]] virtual hal::Error getRequests(
hal::DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, hal::LayerRequest>* outLayerRequests) = 0;
- [[clang::warn_unused_result]] virtual hal::Error getConnectionType(
- ui::DisplayConnectionType*) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error supportsDoze(bool* outSupport) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error getHdrCapabilities(
+ [[nodiscard]] virtual hal::Error getConnectionType(ui::DisplayConnectionType*) const = 0;
+ [[nodiscard]] virtual hal::Error supportsDoze(bool* outSupport) const = 0;
+ [[nodiscard]] virtual hal::Error getHdrCapabilities(
android::HdrCapabilities* outCapabilities) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error getDisplayedContentSamplingAttributes(
+ [[nodiscard]] virtual hal::Error getDisplayedContentSamplingAttributes(
hal::PixelFormat* outFormat, hal::Dataspace* outDataspace,
uint8_t* outComponentMask) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error setDisplayContentSamplingEnabled(
- bool enabled, uint8_t componentMask, uint64_t maxFrames) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error getDisplayedContentSample(
+ [[nodiscard]] virtual hal::Error setDisplayContentSamplingEnabled(bool enabled,
+ uint8_t componentMask,
+ uint64_t maxFrames) const = 0;
+ [[nodiscard]] virtual hal::Error getDisplayedContentSample(
uint64_t maxFrames, uint64_t timestamp,
android::DisplayedFrameStats* outStats) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error getReleaseFences(
+ [[nodiscard]] virtual hal::Error getReleaseFences(
std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error present(
- android::sp<android::Fence>* outPresentFence) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setClientTarget(
+ [[nodiscard]] virtual hal::Error present(android::sp<android::Fence>* outPresentFence) = 0;
+ [[nodiscard]] virtual hal::Error setClientTarget(
uint32_t slot, const android::sp<android::GraphicBuffer>& target,
const android::sp<android::Fence>& acquireFence, hal::Dataspace dataspace) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setColorMode(
- hal::ColorMode mode, hal::RenderIntent renderIntent) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setColorTransform(
- const android::mat4& matrix) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setOutputBuffer(
+ [[nodiscard]] virtual hal::Error setColorMode(hal::ColorMode mode,
+ hal::RenderIntent renderIntent) = 0;
+ [[nodiscard]] virtual hal::Error setColorTransform(const android::mat4& matrix) = 0;
+ [[nodiscard]] virtual hal::Error setOutputBuffer(
const android::sp<android::GraphicBuffer>& buffer,
const android::sp<android::Fence>& releaseFence) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setPowerMode(hal::PowerMode mode) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setVsyncEnabled(hal::Vsync enabled) = 0;
- [[clang::warn_unused_result]] virtual hal::Error validate(nsecs_t expectedPresentTime,
- uint32_t* outNumTypes,
- uint32_t* outNumRequests) = 0;
- [[clang::warn_unused_result]] virtual hal::Error presentOrValidate(
- nsecs_t expectedPresentTime, uint32_t* outNumTypes, uint32_t* outNumRequests,
- android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
- [[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness(
+ [[nodiscard]] virtual hal::Error setPowerMode(hal::PowerMode mode) = 0;
+ [[nodiscard]] virtual hal::Error setVsyncEnabled(hal::Vsync enabled) = 0;
+ [[nodiscard]] virtual hal::Error validate(nsecs_t expectedPresentTime, uint32_t* outNumTypes,
+ uint32_t* outNumRequests) = 0;
+ [[nodiscard]] virtual hal::Error presentOrValidate(nsecs_t expectedPresentTime,
+ uint32_t* outNumTypes,
+ uint32_t* outNumRequests,
+ android::sp<android::Fence>* outPresentFence,
+ uint32_t* state) = 0;
+ [[nodiscard]] virtual std::future<hal::Error> setDisplayBrightness(
float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints(
+ [[nodiscard]] virtual hal::Error setActiveConfigWithConstraints(
hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setBootDisplayConfig(
- hal::HWConfigId configId) = 0;
- [[clang::warn_unused_result]] virtual hal::Error clearBootDisplayConfig() = 0;
- [[clang::warn_unused_result]] virtual hal::Error getPreferredBootDisplayConfig(
+ [[nodiscard]] virtual hal::Error setBootDisplayConfig(hal::HWConfigId configId) = 0;
+ [[nodiscard]] virtual hal::Error clearBootDisplayConfig() = 0;
+ [[nodiscard]] virtual hal::Error getPreferredBootDisplayConfig(
hal::HWConfigId* configId) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
- [[clang::warn_unused_result]] virtual hal::Error getSupportedContentTypes(
+ [[nodiscard]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
+ [[nodiscard]] virtual hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>*) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
- [[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty(
+ [[nodiscard]] virtual hal::Error setContentType(hal::ContentType) = 0;
+ [[nodiscard]] virtual hal::Error getClientTargetProperty(
hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
- [[clang::warn_unused_result]] virtual hal::Error getDisplayDecorationSupport(
+ [[nodiscard]] virtual hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setIdleTimerEnabled(
- std::chrono::milliseconds timeout) = 0;
+ [[nodiscard]] virtual hal::Error setIdleTimerEnabled(std::chrono::milliseconds timeout) = 0;
+ [[nodiscard]] virtual hal::Error getPhysicalDisplayOrientation(
+ Hwc2::AidlTransform* outTransform) const = 0;
};
namespace impl {
@@ -256,6 +254,7 @@
bool isVsyncPeriodSwitchSupported() const override;
bool hasDisplayIdleTimerCapability() const override;
void onLayerDestroyed(hal::HWLayerId layerId) override;
+ hal::Error getPhysicalDisplayOrientation(Hwc2::AidlTransform* outTransform) const override;
private:
@@ -296,45 +295,39 @@
virtual hal::HWLayerId getId() const = 0;
- [[clang::warn_unused_result]] virtual hal::Error setCursorPosition(int32_t x, int32_t y) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setBuffer(
- uint32_t slot, const android::sp<android::GraphicBuffer>& buffer,
- const android::sp<android::Fence>& acquireFence) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setSurfaceDamage(
- const android::Region& damage) = 0;
+ [[nodiscard]] virtual hal::Error setCursorPosition(int32_t x, int32_t y) = 0;
+ [[nodiscard]] virtual hal::Error setBuffer(uint32_t slot,
+ const android::sp<android::GraphicBuffer>& buffer,
+ const android::sp<android::Fence>& acquireFence) = 0;
+ [[nodiscard]] virtual hal::Error setSurfaceDamage(const android::Region& damage) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setBlendMode(hal::BlendMode mode) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setColor(
+ [[nodiscard]] virtual hal::Error setBlendMode(hal::BlendMode mode) = 0;
+ [[nodiscard]] virtual hal::Error setColor(
aidl::android::hardware::graphics::composer3::Color color) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setCompositionType(
+ [[nodiscard]] virtual hal::Error setCompositionType(
aidl::android::hardware::graphics::composer3::Composition type) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setDataspace(hal::Dataspace dataspace) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setPerFrameMetadata(
- const int32_t supportedPerFrameMetadata, const android::HdrMetadata& metadata) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setDisplayFrame(
- const android::Rect& frame) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setPlaneAlpha(float alpha) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setSidebandStream(
- const native_handle_t* stream) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setSourceCrop(
- const android::FloatRect& crop) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setTransform(hal::Transform transform) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setVisibleRegion(
- const android::Region& region) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setZOrder(uint32_t z) = 0;
+ [[nodiscard]] virtual hal::Error setDataspace(hal::Dataspace dataspace) = 0;
+ [[nodiscard]] virtual hal::Error setPerFrameMetadata(const int32_t supportedPerFrameMetadata,
+ const android::HdrMetadata& metadata) = 0;
+ [[nodiscard]] virtual hal::Error setDisplayFrame(const android::Rect& frame) = 0;
+ [[nodiscard]] virtual hal::Error setPlaneAlpha(float alpha) = 0;
+ [[nodiscard]] virtual hal::Error setSidebandStream(const native_handle_t* stream) = 0;
+ [[nodiscard]] virtual hal::Error setSourceCrop(const android::FloatRect& crop) = 0;
+ [[nodiscard]] virtual hal::Error setTransform(hal::Transform transform) = 0;
+ [[nodiscard]] virtual hal::Error setVisibleRegion(const android::Region& region) = 0;
+ [[nodiscard]] virtual hal::Error setZOrder(uint32_t z) = 0;
// Composer HAL 2.3
- [[clang::warn_unused_result]] virtual hal::Error setColorTransform(
- const android::mat4& matrix) = 0;
+ [[nodiscard]] virtual hal::Error setColorTransform(const android::mat4& matrix) = 0;
// Composer HAL 2.4
- [[clang::warn_unused_result]] virtual hal::Error setLayerGenericMetadata(
- const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
+ [[nodiscard]] virtual hal::Error setLayerGenericMetadata(const std::string& name,
+ bool mandatory,
+ const std::vector<uint8_t>& value) = 0;
// AIDL HAL
- [[clang::warn_unused_result]] virtual hal::Error setBrightness(float brightness) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setBlockingRegion(
- const android::Region& region) = 0;
+ [[nodiscard]] virtual hal::Error setBrightness(float brightness) = 0;
+ [[nodiscard]] virtual hal::Error setBlockingRegion(const android::Region& region) = 0;
};
namespace impl {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 02b3772..459291a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -740,10 +740,6 @@
});
}
-bool HWComposer::getBootDisplayModeSupport() {
- return mComposer->isSupported(Hwc2::Composer::OptionalFeature::BootDisplayConfig);
-}
-
status_t HWComposer::setBootDisplayMode(PhysicalDisplayId displayId,
hal::HWConfigId displayModeId) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -814,10 +810,11 @@
}
status_t HWComposer::getSupportedContentTypes(
- PhysicalDisplayId displayId, std::vector<hal::ContentType>* outSupportedContentTypes) {
+ PhysicalDisplayId displayId,
+ std::vector<hal::ContentType>* outSupportedContentTypes) const {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- const auto error =
- mDisplayData[displayId].hwcDisplay->getSupportedContentTypes(outSupportedContentTypes);
+ const auto error = mDisplayData.at(displayId).hwcDisplay->getSupportedContentTypes(
+ outSupportedContentTypes);
RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
@@ -986,9 +983,19 @@
return NO_ERROR;
}
-bool HWComposer::hasDisplayIdleTimerCapability(PhysicalDisplayId displayId) {
+bool HWComposer::hasDisplayIdleTimerCapability(PhysicalDisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, false);
- return mDisplayData[displayId].hwcDisplay->hasDisplayIdleTimerCapability();
+ return mDisplayData.at(displayId).hwcDisplay->hasDisplayIdleTimerCapability();
+}
+
+Hwc2::AidlTransform HWComposer::getPhysicalDisplayOrientation(PhysicalDisplayId displayId) const {
+ ATRACE_CALL();
+ RETURN_IF_INVALID_DISPLAY(displayId, Hwc2::AidlTransform::NONE);
+ Hwc2::AidlTransform outTransform;
+ const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay;
+ const auto error = hwcDisplay->getPhysicalDisplayOrientation(&outTransform);
+ RETURN_IF_HWC_ERROR(error, displayId, Hwc2::AidlTransform::NONE);
+ return outTransform;
}
void HWComposer::loadLayerMetadataSupport() {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f9637f0..0e15a7c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -234,8 +234,16 @@
hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
virtual status_t setAutoLowLatencyMode(PhysicalDisplayId, bool on) = 0;
virtual status_t getSupportedContentTypes(
- PhysicalDisplayId, std::vector<hal::ContentType>* outSupportedContentTypes) = 0;
+ PhysicalDisplayId, std::vector<hal::ContentType>* outSupportedContentTypes) const = 0;
+
+ bool supportsContentType(PhysicalDisplayId displayId, hal::ContentType type) const {
+ std::vector<hal::ContentType> types;
+ return getSupportedContentTypes(displayId, &types) == NO_ERROR &&
+ std::find(types.begin(), types.end(), type) != types.end();
+ }
+
virtual status_t setContentType(PhysicalDisplayId, hal::ContentType) = 0;
+
virtual const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata()
const = 0;
@@ -259,7 +267,6 @@
virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const = 0;
// Composer 3.0
- virtual bool getBootDisplayModeSupport() = 0;
virtual status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) = 0;
virtual status_t clearBootDisplayMode(PhysicalDisplayId) = 0;
virtual std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
@@ -268,7 +275,8 @@
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
virtual status_t setIdleTimerEnabled(PhysicalDisplayId, std::chrono::milliseconds timeout) = 0;
- virtual bool hasDisplayIdleTimerCapability(PhysicalDisplayId) = 0;
+ virtual bool hasDisplayIdleTimerCapability(PhysicalDisplayId) const = 0;
+ virtual Hwc2::AidlTransform getPhysicalDisplayOrientation(PhysicalDisplayId) const = 0;
};
namespace impl {
@@ -390,13 +398,13 @@
const hal::VsyncPeriodChangeConstraints&,
hal::VsyncPeriodChangeTimeline* outTimeline) override;
status_t setAutoLowLatencyMode(PhysicalDisplayId, bool) override;
- status_t getSupportedContentTypes(PhysicalDisplayId, std::vector<hal::ContentType>*) override;
+ status_t getSupportedContentTypes(PhysicalDisplayId,
+ std::vector<hal::ContentType>*) const override;
status_t setContentType(PhysicalDisplayId, hal::ContentType) override;
const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata() const override;
// Composer 3.0
- bool getBootDisplayModeSupport() override;
status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) override;
status_t clearBootDisplayMode(PhysicalDisplayId) override;
std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) override;
@@ -405,7 +413,8 @@
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
status_t setIdleTimerEnabled(PhysicalDisplayId, std::chrono::milliseconds timeout) override;
- bool hasDisplayIdleTimerCapability(PhysicalDisplayId) override;
+ bool hasDisplayIdleTimerCapability(PhysicalDisplayId) const override;
+ Hwc2::AidlTransform getPhysicalDisplayOrientation(PhysicalDisplayId) const override;
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 33adceb..d9af553 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -235,8 +235,8 @@
return mClient_2_4 != nullptr;
case OptionalFeature::ExpectedPresentTime:
case OptionalFeature::DisplayBrightnessCommand:
- case OptionalFeature::BootDisplayConfig:
case OptionalFeature::KernelIdleTimer:
+ case OptionalFeature::PhysicalDisplayOrientation:
return false;
}
}
@@ -1331,6 +1331,11 @@
"OptionalFeature::KernelIdleTimer is not supported on HIDL");
}
+Error HidlComposer::getPhysicalDisplayOrientation(Display, AidlTransform*) {
+ LOG_ALWAYS_FATAL("getPhysicalDisplayOrientation should have never been called on this as "
+ "OptionalFeature::PhysicalDisplayOrientation is not supported on HIDL");
+}
+
void HidlComposer::registerCallback(ComposerCallback& callback) {
const bool vsyncSwitchingSupported =
isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching);
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index a1ea4f2..5869ae5 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -334,6 +334,9 @@
support) override;
Error setIdleTimerEnabled(Display displayId, std::chrono::milliseconds timeout) override;
+ Error getPhysicalDisplayOrientation(Display displayId,
+ AidlTransform* outDisplayOrientation) override;
+
private:
class CommandWriter : public CommandWriterBase {
public:
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 3dab389..44c086d 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -542,7 +542,7 @@
static constexpr double kAllowedTargetDeviationPercent = 0.05;
// Target used for init and normalization, the actual value does not really matter
static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
- // amount of time after the last message was sent before the session goes stale
+ // 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;
};
@@ -551,7 +551,7 @@
base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
const bool AidlPowerHalWrapper::sNormalizeTarget =
- base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), true);
+ base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), false);
PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 81747d5..66beff2 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -618,15 +618,15 @@
}
}
-void SurfaceFrame::tracePredictions(int64_t displayFrameToken) const {
+void SurfaceFrame::tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedSurfaceFrameStartEvent = event->set_expected_surface_frame_start();
@@ -644,8 +644,8 @@
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedSurfaceFrameEndEvent = event->set_frame_end();
@@ -654,14 +654,14 @@
});
}
-void SurfaceFrame::traceActuals(int64_t displayFrameToken) const {
+void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
// Actual start time is not yet available, so use expected start instead
if (mPredictionState == PredictionState::Expired) {
// If prediction is expired, we can't use the predicted start time. Instead, just use a
@@ -669,11 +669,12 @@
// frame in the trace.
nsecs_t endTime =
(mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime);
- packet->set_timestamp(
- static_cast<uint64_t>(endTime - kPredictionExpiredStartTimeDelta));
+ const auto timestamp = endTime - kPredictionExpiredStartTimeDelta;
+ packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
} else {
- packet->set_timestamp(static_cast<uint64_t>(
- mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime));
+ const auto timestamp =
+ mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime;
+ packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
}
auto* event = packet->set_frame_timeline_event();
@@ -706,11 +707,11 @@
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
if (mPresentState == PresentState::Dropped) {
- packet->set_timestamp(static_cast<uint64_t>(mDropTime));
+ packet->set_timestamp(static_cast<uint64_t>(mDropTime + monoBootOffset));
} else {
- packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
+ packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime + monoBootOffset));
}
auto* event = packet->set_frame_timeline_event();
@@ -723,7 +724,7 @@
/**
* TODO(b/178637512): add inputEventId to the perfetto trace.
*/
-void SurfaceFrame::trace(int64_t displayFrameToken) const {
+void SurfaceFrame::trace(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID ||
displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
// No packets can be traced with a missing token.
@@ -732,9 +733,9 @@
if (getPredictionState() != PredictionState::Expired) {
// Expired predictions have zeroed timestamps. This cannot be used in any meaningful way in
// a trace.
- tracePredictions(displayFrameToken);
+ tracePredictions(displayFrameToken, monoBootOffset);
}
- traceActuals(displayFrameToken);
+ traceActuals(displayFrameToken, monoBootOffset);
}
namespace impl {
@@ -760,8 +761,9 @@
}
FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
- JankClassificationThresholds thresholds)
- : mMaxDisplayFrames(kDefaultMaxDisplayFrames),
+ JankClassificationThresholds thresholds, bool useBootTimeClock)
+ : mUseBootTimeClock(useBootTimeClock),
+ mMaxDisplayFrames(kDefaultMaxDisplayFrames),
mTimeStats(std::move(timeStats)),
mSurfaceFlingerPid(surfaceFlingerPid),
mJankClassificationThresholds(thresholds) {
@@ -1016,14 +1018,16 @@
}
}
-void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid,
+ nsecs_t monoBootOffset) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedDisplayFrameStartEvent = event->set_expected_display_frame_start();
@@ -1037,8 +1041,9 @@
// Expected timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerPredictions.endTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerPredictions.endTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedDisplayFrameEndEvent = event->set_frame_end();
@@ -1047,14 +1052,16 @@
});
}
-void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid,
+ nsecs_t monoBootOffset) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerActuals.startTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerActuals.startTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* actualDisplayFrameStartEvent = event->set_actual_display_frame_start();
@@ -1075,8 +1082,9 @@
// Actual timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerActuals.presentTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerActuals.presentTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* actualDisplayFrameEndEvent = event->set_frame_end();
@@ -1085,7 +1093,7 @@
});
}
-void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const {
if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
// DisplayFrame should not have an invalid token.
ALOGE("Cannot trace DisplayFrame with invalid token");
@@ -1095,12 +1103,12 @@
if (mPredictionState == PredictionState::Valid) {
// Expired and unknown predictions have zeroed timestamps. This cannot be used in any
// meaningful way in a trace.
- tracePredictions(surfaceFlingerPid);
+ tracePredictions(surfaceFlingerPid, monoBootOffset);
}
- traceActuals(surfaceFlingerPid);
+ traceActuals(surfaceFlingerPid, monoBootOffset);
for (auto& surfaceFrame : mSurfaceFrames) {
- surfaceFrame->trace(mToken);
+ surfaceFrame->trace(mToken, monoBootOffset);
}
}
@@ -1164,6 +1172,12 @@
}
void FrameTimeline::flushPendingPresentFences() {
+ // Perfetto is using boottime clock to void drifts when the device goes
+ // to suspend.
+ const auto monoBootOffset = mUseBootTimeClock
+ ? (systemTime(SYSTEM_TIME_BOOTTIME) - systemTime(SYSTEM_TIME_MONOTONIC))
+ : 0;
+
for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
const auto& pendingPresentFence = mPendingPresentFences[i];
nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
@@ -1175,7 +1189,7 @@
}
auto& displayFrame = pendingPresentFence.second;
displayFrame->onPresent(signalTime, mPreviousPresentTime);
- displayFrame->trace(mSurfaceFlingerPid);
+ displayFrame->trace(mSurfaceFlingerPid, monoBootOffset);
mPreviousPresentTime = signalTime;
mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 36d6290..a2305af 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -204,8 +204,9 @@
std::string miniDump() const;
// Emits a packet for perfetto tracing. The function body will be executed only if tracing is
// enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
- // DisplayFrame at the trace processor side.
- void trace(int64_t displayFrameToken) const;
+ // DisplayFrame at the trace processor side. monoBootOffset is the difference
+ // between SYSTEM_TIME_BOOTTIME and SYSTEM_TIME_MONOTONIC.
+ void trace(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
// Getter functions used only by FrameTimelineTests and SurfaceFrame internally
TimelineItem getActuals() const;
@@ -225,8 +226,8 @@
std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
private:
- void tracePredictions(int64_t displayFrameToken) const;
- void traceActuals(int64_t displayFrameToken) const;
+ void tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
+ void traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
void classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
nsecs_t& deadlineDelta) REQUIRES(mMutex);
@@ -369,8 +370,9 @@
// Dumpsys interface - dumps all data irrespective of jank
void dumpAll(std::string& result, nsecs_t baseTime) const;
// Emits a packet for perfetto tracing. The function body will be executed only if tracing
- // is enabled.
- void trace(pid_t surfaceFlingerPid) const;
+ // is enabled. monoBootOffset is the difference between SYSTEM_TIME_BOOTTIME
+ // and SYSTEM_TIME_MONOTONIC.
+ void trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const;
// Sets the token, vsyncPeriod, predictions and SF start time.
void onSfWakeUp(int64_t token, Fps refreshRate, std::optional<TimelineItem> predictions,
nsecs_t wakeUpTime);
@@ -401,8 +403,8 @@
private:
void dump(std::string& result, nsecs_t baseTime) const;
- void tracePredictions(pid_t surfaceFlingerPid) const;
- void traceActuals(pid_t surfaceFlingerPid) const;
+ void tracePredictions(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const;
+ void traceActuals(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const;
void classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync,
nsecs_t previousPresentTime);
@@ -442,7 +444,7 @@
};
FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
- JankClassificationThresholds thresholds = {});
+ JankClassificationThresholds thresholds = {}, bool useBootTimeClock = true);
~FrameTimeline() = default;
frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
@@ -484,6 +486,7 @@
TokenManager mTokenManager;
TraceCookieCounter mTraceCookieCounter;
mutable std::mutex mMutex;
+ const bool mUseBootTimeClock;
uint32_t mMaxDisplayFrames;
std::shared_ptr<TimeStats> mTimeStats;
const pid_t mSurfaceFlingerPid;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index aeaf1e1..894fb8d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -37,6 +37,7 @@
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <ftl/enum.h>
+#include <ftl/fake_guard.h>
#include <gui/BufferItem.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
@@ -833,6 +834,14 @@
return false;
}
+ if (CC_UNLIKELY(relative->usingRelativeZ(LayerVector::StateSet::Drawing)) &&
+ (relative->mDrawingState.zOrderRelativeOf == this)) {
+ ALOGE("Detected relative layer loop between %s and %s",
+ mName.c_str(), relative->mName.c_str());
+ ALOGE("Ignoring new call to set relative layer");
+ return false;
+ }
+
mFlinger->mSomeChildrenChanged = true;
mDrawingState.sequence++;
@@ -1990,6 +1999,18 @@
}
}
+bool Layer::findInHierarchy(const sp<Layer>& l) {
+ if (l == this) {
+ return true;
+ }
+ for (auto& child : mDrawingChildren) {
+ if (child->findInHierarchy(l)) {
+ return true;
+ }
+ }
+ return false;
+}
+
void Layer::commitChildList() {
for (size_t i = 0; i < mCurrentChildren.size(); i++) {
const auto& child = mCurrentChildren[i];
@@ -1997,6 +2018,17 @@
}
mDrawingChildren = mCurrentChildren;
mDrawingParent = mCurrentParent;
+ if (CC_UNLIKELY(usingRelativeZ(LayerVector::StateSet::Drawing))) {
+ auto zOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
+ if (zOrderRelativeOf == nullptr) return;
+ if (findInHierarchy(zOrderRelativeOf)) {
+ ALOGE("Detected Z ordering loop between %s and %s", mName.c_str(),
+ zOrderRelativeOf->mName.c_str());
+ ALOGE("Severing rel Z loop, potentially dangerous");
+ mDrawingState.isRelativeOf = false;
+ zOrderRelativeOf->removeZOrderRelative(this);
+ }
+ }
}
@@ -2014,10 +2046,10 @@
writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
+ ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread.
+
// Only populate for the primary display.
- UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread.
- const auto display = mFlinger->getDefaultDisplayDeviceLocked();
- if (display) {
+ if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) {
const auto compositionType = getCompositionType(*display);
layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
LayerProtoHelper::writeToProto(getVisibleRegion(display.get()),
@@ -2177,7 +2209,6 @@
void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
Rect tmpBounds = getInputBounds();
if (!tmpBounds.isValid()) {
- info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true);
info.touchableRegion.clear();
// A layer could have invalid input bounds and still expect to receive touch input if it has
// replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated
@@ -2392,7 +2423,8 @@
}
bool Layer::hasInputInfo() const {
- return mDrawingState.inputInfo.token != nullptr;
+ return mDrawingState.inputInfo.token != nullptr ||
+ mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);
}
bool Layer::canReceiveInput() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 0fb16f2..846460d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2007 The Android Open Source Project
*
@@ -1139,6 +1138,7 @@
bool mIsAtRoot = false;
uint32_t mLayerCreationFlags;
+ bool findInHierarchy(const sp<Layer>&);
};
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate);
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index a1e1455..896f254 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -26,18 +26,12 @@
namespace android {
namespace {
-struct ReparentForDrawing {
- const sp<Layer>& oldParent;
-
- ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
- const Rect& drawingBounds)
- : oldParent(oldParent) {
+void reparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
+ const Rect& drawingBounds) {
// Compute and cache the bounds for the new parent layer.
newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(),
- 0.f /* shadowRadius */);
+ 0.f /* shadowRadius */);
oldParent->setChildrenDrawingParent(newParent);
- }
- ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
};
} // namespace
@@ -114,11 +108,19 @@
} else {
// In the "childrenOnly" case we reparent the children to a screenshot
// 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()});
-
- ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
+ {&mFlinger, nullptr, "Screenshot Parent"s, 0, LayerMetadata()});
+ {
+ Mutex::Autolock _l(mFlinger.mStateLock);
+ reparentForDrawing(mLayer, screenshotParentLayer, sourceCrop);
+ }
drawLayers();
+ {
+ Mutex::Autolock _l(mFlinger.mStateLock);
+ mLayer->setChildrenDrawingParent(mLayer);
+ }
}
}
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
index 6a90694..41273e0 100644
--- a/services/surfaceflinger/LayerRenderArea.h
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -46,6 +46,7 @@
Rect getSourceCrop() const override;
void render(std::function<void()> drawLayers) override;
+ virtual sp<Layer> getParentLayer() const { return mLayer; }
private:
const sp<Layer> mLayer;
@@ -58,4 +59,4 @@
const bool mChildrenOnly;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h
deleted file mode 100644
index c1aa118..0000000
--- a/services/surfaceflinger/MainThreadGuard.h
+++ /dev/null
@@ -1,35 +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.
- */
-
-#pragma once
-
-#include <utils/Mutex.h>
-
-namespace android {
-namespace {
-
-// Helps to ensure that some functions runs on SF's main thread by using the
-// clang thread safety annotations.
-class CAPABILITY("mutex") MainThreadGuard {
-} SF_MAIN_THREAD;
-
-struct SCOPED_CAPABILITY MainThreadScopedGuard {
-public:
- explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {}
- ~MainThreadScopedGuard() RELEASE() {}
-};
-} // namespace
-} // namespace android
diff --git a/services/surfaceflinger/MutexUtils.h b/services/surfaceflinger/MutexUtils.h
new file mode 100644
index 0000000..f8be6f3
--- /dev/null
+++ b/services/surfaceflinger/MutexUtils.h
@@ -0,0 +1,53 @@
+/*
+ * 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 <log/log.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+struct SCOPED_CAPABILITY ConditionalLock {
+ ConditionalLock(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) {
+ if (lock) mutex.lock();
+ }
+
+ ~ConditionalLock() RELEASE() {
+ if (lock) mutex.unlock();
+ }
+
+ Mutex& mutex;
+ const bool lock;
+};
+
+struct SCOPED_CAPABILITY TimedLock {
+ TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex)
+ : mutex(mutex), status(mutex.timedLock(timeout)) {
+ ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status);
+ }
+
+ ~TimedLock() RELEASE() {
+ if (locked()) mutex.unlock();
+ }
+
+ bool locked() const { return status == NO_ERROR; }
+
+ Mutex& mutex;
+ const status_t status;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index c9f7f46..387364c 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -4,6 +4,7 @@
#include <ui/Transform.h>
#include <functional>
+#include "Layer.h"
namespace android {
@@ -85,6 +86,10 @@
// Returns the source display viewport.
const Rect& getLayerStackSpaceRect() const { return mLayerStackSpaceRect; }
+ // If this is a LayerRenderArea, return the root layer of the
+ // capture operation.
+ virtual sp<Layer> getParentLayer() const { return nullptr; }
+
protected:
const bool mAllowSecureLayers;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 65c8613..3226f22 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -38,10 +38,33 @@
namespace android::scheduler {
namespace {
+struct RefreshRateScore {
+ DisplayModeIterator modeIt;
+ float score;
+};
+
+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, score] = current;
+
+ std::string name = to_string(modeIt->second->getFps());
+ ALOGV("%s scores %.2f", name.c_str(), score);
+
+ ATRACE_INT(name.c_str(), static_cast<int>(std::round(score * 100)));
+
+ constexpr float kEpsilon = 0.0001f;
+ return score > max.score * (1 + kEpsilon);
+ });
+
+ return it->modeIt->second;
+}
+
constexpr RefreshRateConfigs::GlobalSignals kNoSignals;
std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
- return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(),
+ return base::StringPrintf("%s (type=%s, weight=%.2f, seamlessness=%s) %s", layer.name.c_str(),
ftl::enum_string(layer.vote).c_str(), weight,
ftl::enum_string(layer.seamlessness).c_str(),
to_string(layer.desiredRefreshRate).c_str());
@@ -52,8 +75,8 @@
knownFrameRates.reserve(knownFrameRates.size() + modes.size());
// Add all supported refresh rates.
- for (const auto& mode : modes) {
- knownFrameRates.push_back(Fps::fromPeriodNsecs(mode->getVsyncPeriod()));
+ for (const auto& [id, mode] : modes) {
+ knownFrameRates.push_back(mode->getFps());
}
// Sort and remove duplicates.
@@ -64,17 +87,51 @@
return knownFrameRates;
}
-} // namespace
+// The Filter is a `bool(const DisplayMode&)` predicate.
+template <typename Filter>
+std::vector<DisplayModeIterator> sortByRefreshRate(const DisplayModes& modes, Filter&& filter) {
+ std::vector<DisplayModeIterator> sortedModes;
+ sortedModes.reserve(modes.size());
-using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
-using RefreshRate = RefreshRateConfigs::RefreshRate;
+ for (auto it = modes.begin(); it != modes.end(); ++it) {
+ const auto& [id, mode] = *it;
-std::string RefreshRate::toString() const {
- return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
- getModeId().value(), mode->getHwcId(), getFps().getValue(),
- mode->getWidth(), mode->getHeight(), getModeGroup());
+ if (filter(*mode)) {
+ ALOGV("%s: including mode %d", __func__, id.value());
+ sortedModes.push_back(it);
+ }
+ }
+
+ std::sort(sortedModes.begin(), sortedModes.end(), [](auto it1, auto it2) {
+ const auto& mode1 = it1->second;
+ const auto& mode2 = it2->second;
+
+ if (mode1->getVsyncPeriod() == mode2->getVsyncPeriod()) {
+ return mode1->getGroup() > mode2->getGroup();
+ }
+
+ return mode1->getVsyncPeriod() > mode2->getVsyncPeriod();
+ });
+
+ return sortedModes;
}
+bool canModesSupportFrameRateOverride(const std::vector<DisplayModeIterator>& sortedModes) {
+ for (const auto it1 : sortedModes) {
+ const auto& mode1 = it1->second;
+ for (const auto it2 : sortedModes) {
+ const auto& mode2 = it2->second;
+
+ if (RefreshRateConfigs::getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace
+
std::string RefreshRateConfigs::Policy::toString() const {
return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d"
", primary range: %s, app request range: %s",
@@ -94,15 +151,14 @@
return {quotient, remainder};
}
-bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer,
- const RefreshRate& refreshRate) const {
+bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, Fps refreshRate) const {
using namespace fps_approx_ops;
switch (layer.vote) {
case LayerVoteType::ExplicitExactOrMultiple:
case LayerVoteType::Heuristic:
if (mConfig.frameRateMultipleThreshold != 0 &&
- refreshRate.getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
+ refreshRate >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2)) {
// Don't vote high refresh rates past the threshold for layers with a low desired
// refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for
@@ -120,11 +176,11 @@
return true;
}
-float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(
- const LayerRequirement& layer, const RefreshRate& refreshRate) const {
+float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer,
+ Fps refreshRate) const {
constexpr float kScoreForFractionalPairs = .8f;
- const auto displayPeriod = refreshRate.getVsyncPeriod();
+ const auto displayPeriod = refreshRate.getPeriodNsecs();
const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
if (layer.vote == LayerVoteType::ExplicitDefault) {
// Find the actual rate the layer will render, assuming
@@ -147,7 +203,7 @@
if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
layer.vote == LayerVoteType::Heuristic) {
- if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) {
+ if (isFractionalPairOrMultiple(refreshRate, layer.desiredRefreshRate)) {
return kScoreForFractionalPairs;
}
@@ -182,8 +238,7 @@
return 0;
}
-float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
- const RefreshRate& refreshRate,
+float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
bool isSeamlessSwitch) const {
if (!isVoteAllowed(layer, refreshRate)) {
return 0;
@@ -195,14 +250,14 @@
// If the layer wants Max, give higher score to the higher refresh rate
if (layer.vote == LayerVoteType::Max) {
- const auto ratio = refreshRate.getFps().getValue() /
- mAppRequestRefreshRates.back()->getFps().getValue();
+ 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;
}
if (layer.vote == LayerVoteType::ExplicitExact) {
- const int divisor = getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate);
+ const int divisor = getFrameRateDivisor(refreshRate, layer.desiredRefreshRate);
if (mSupportsFrameRateOverrideByContent) {
// Since we support frame rate override, allow refresh rates which are
// multiples of the layer's request, as those apps would be throttled
@@ -215,7 +270,7 @@
// If the layer frame rate is a divisor of the refresh rate it should score
// the highest score.
- if (getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
+ if (getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) {
return 1.0f * seamlessness;
}
@@ -227,14 +282,9 @@
kNonExactMatchingPenalty;
}
-struct RefreshRateScore {
- const RefreshRate* refreshRate;
- float score;
-};
-
auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
GlobalSignals signals) const
- -> std::pair<RefreshRate, GlobalSignals> {
+ -> std::pair<DisplayModePtr, GlobalSignals> {
std::lock_guard lock(mLock);
if (mGetBestRefreshRateCache &&
@@ -249,7 +299,7 @@
auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
GlobalSignals signals) const
- -> std::pair<RefreshRate, GlobalSignals> {
+ -> std::pair<DisplayModePtr, GlobalSignals> {
ATRACE_CALL();
ALOGV("%s: %zu layers", __func__, layers.size());
@@ -298,21 +348,22 @@
explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0;
const Policy* policy = getCurrentPolicyLocked();
- const auto& defaultMode = mRefreshRates.at(policy->defaultMode);
+ 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.
// However if a seamed layer is still present we anchor around the group
// of the current mode, in order to prevent unnecessary seamed mode switches
// (e.g. when pausing a video playback).
- const auto anchorGroup = seamedFocusedLayers > 0 ? mCurrentRefreshRate->getModeGroup()
- : defaultMode->getModeGroup();
+ const auto anchorGroup =
+ seamedFocusedLayers > 0 ? mActiveModeIt->second->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) {
- ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
- return {getMaxRefreshRateByPolicyLocked(anchorGroup), GlobalSignals{.touch = true}};
+ const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
+ ALOGV("TouchBoost - choose %s", to_string(max->getFps()).c_str());
+ return {max, GlobalSignals{.touch = true}};
}
// If the primary range consists of a single refresh rate then we can only
@@ -322,28 +373,30 @@
isApproxEqual(policy->primaryRange.min, policy->primaryRange.max);
if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
- ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
- return {getMinRefreshRateByPolicyLocked(), GlobalSignals{.idle = true}};
+ const DisplayModePtr& min = getMinRefreshRateByPolicyLocked();
+ ALOGV("Idle - choose %s", to_string(min->getFps()).c_str());
+ return {min, GlobalSignals{.idle = true}};
}
if (layers.empty() || noVoteLayers == layers.size()) {
- const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
- ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str());
- return {refreshRate, kNoSignals};
+ const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
+ ALOGV("no layers with votes - choose %s", to_string(max->getFps()).c_str());
+ return {max, kNoSignals};
}
// Only if all layers want Min we should return Min
if (noVoteLayers + minVoteLayers == layers.size()) {
- ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
- return {getMinRefreshRateByPolicyLocked(), kNoSignals};
+ const DisplayModePtr& min = getMinRefreshRateByPolicyLocked();
+ ALOGV("all layers Min - choose %s", to_string(min->getFps()).c_str());
+ return {min, kNoSignals};
}
// Find the best refresh rate based on score
std::vector<RefreshRateScore> scores;
scores.reserve(mAppRequestRefreshRates.size());
- for (const auto refreshRate : mAppRequestRefreshRates) {
- scores.emplace_back(RefreshRateScore{refreshRate, 0.0f});
+ for (const DisplayModeIterator modeIt : mAppRequestRefreshRates) {
+ scores.emplace_back(RefreshRateScore{modeIt, 0.0f});
}
for (const auto& layer : layers) {
@@ -354,17 +407,16 @@
continue;
}
- auto weight = layer.weight;
+ const auto weight = layer.weight;
- for (auto i = 0u; i < scores.size(); i++) {
- const bool isSeamlessSwitch =
- scores[i].refreshRate->getModeGroup() == mCurrentRefreshRate->getModeGroup();
+ for (auto& [modeIt, score] : scores) {
+ const auto& [id, mode] = *modeIt;
+ const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup();
if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s",
- formatLayerInfo(layer, weight).c_str(),
- scores[i].refreshRate->toString().c_str(),
- mCurrentRefreshRate->toString().c_str());
+ formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(),
+ to_string(*mActiveModeIt->second).c_str());
continue;
}
@@ -372,9 +424,8 @@
!layer.focused) {
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(),
- scores[i].refreshRate->toString().c_str(),
- mCurrentRefreshRate->toString().c_str());
+ formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(),
+ to_string(*mActiveModeIt->second).c_str());
continue;
}
@@ -383,17 +434,14 @@
// mode group otherwise. In second case, if the current mode group is different
// from the default, this means a layer with seamlessness=SeamedAndSeamless has just
// disappeared.
- const bool isInPolicyForDefault = scores[i].refreshRate->getModeGroup() == anchorGroup;
+ const bool isInPolicyForDefault = mode->getGroup() == anchorGroup;
if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) {
ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(),
- scores[i].refreshRate->toString().c_str(),
- mCurrentRefreshRate->toString().c_str());
+ to_string(*mode).c_str(), to_string(*mActiveModeIt->second).c_str());
continue;
}
- const bool inPrimaryRange =
- policy->primaryRange.includes(scores[i].refreshRate->getFps());
-
+ const bool inPrimaryRange = policy->primaryRange.includes(mode->getFps());
if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
!(layer.focused &&
(layer.vote == LayerVoteType::ExplicitDefault ||
@@ -404,30 +452,31 @@
}
const auto layerScore =
- calculateLayerScoreLocked(layer, *scores[i].refreshRate, isSeamlessSwitch);
+ calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch);
ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
- scores[i].refreshRate->getName().c_str(), layerScore);
- scores[i].score += weight * layerScore;
+ to_string(mode->getFps()).c_str(), layerScore);
+
+ score += weight * layerScore;
}
}
// Now that we scored all the refresh rates we need to pick the one that got the highest score.
// In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
// or the lower otherwise.
- const RefreshRate* bestRefreshRate = maxVoteLayers > 0
- ? getBestRefreshRate(scores.rbegin(), scores.rend())
- : getBestRefreshRate(scores.begin(), scores.end());
+ const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0
+ ? getMaxScoreRefreshRate(scores.rbegin(), scores.rend())
+ : getMaxScoreRefreshRate(scores.begin(), scores.end());
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.score == 0; })) {
- const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
- ALOGV("layers not scored - choose %s", refreshRate.getName().c_str());
- return {refreshRate, kNoSignals};
+ const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
+ ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str());
+ return {max, kNoSignals};
} else {
- return {*bestRefreshRate, kNoSignals};
+ return {bestRefreshRate, kNoSignals};
}
}
@@ -435,7 +484,7 @@
// 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 RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
+ const DisplayModePtr& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
const bool touchBoostForExplicitExact = [&] {
if (mSupportsFrameRateOverrideByContent) {
@@ -450,12 +499,12 @@
using fps_approx_ops::operator<;
if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
- bestRefreshRate->getFps() < touchRefreshRate.getFps()) {
- ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
+ bestRefreshRate->getFps() < touchRefreshRate->getFps()) {
+ ALOGV("TouchBoost - choose %s", to_string(touchRefreshRate->getFps()).c_str());
return {touchRefreshRate, GlobalSignals{.touch = true}};
}
- return {*bestRefreshRate, kNoSignals};
+ return {bestRefreshRate, kNoSignals};
}
std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>>
@@ -489,26 +538,28 @@
return layersByUid;
}
-std::vector<RefreshRateScore> initializeScoresForAllRefreshRates(
- const AllRefreshRatesMapType& refreshRates) {
- std::vector<RefreshRateScore> scores;
- scores.reserve(refreshRates.size());
- for (const auto& [ignored, refreshRate] : refreshRates) {
- scores.emplace_back(RefreshRateScore{refreshRate.get(), 0.0f});
- }
- std::sort(scores.begin(), scores.end(),
- [](const auto& a, const auto& b) { return *a.refreshRate < *b.refreshRate; });
- return scores;
-}
-
RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides(
- const std::vector<LayerRequirement>& layers, Fps displayFrameRate,
+ const std::vector<LayerRequirement>& layers, Fps displayRefreshRate,
GlobalSignals globalSignals) const {
ATRACE_CALL();
- ALOGV("getFrameRateOverrides %zu layers", layers.size());
+ ALOGV("%s: %zu layers", __func__, layers.size());
+
std::lock_guard lock(mLock);
- std::vector<RefreshRateScore> scores = initializeScoresForAllRefreshRates(mRefreshRates);
+
+ std::vector<RefreshRateScore> scores;
+ scores.reserve(mDisplayModes.size());
+
+ for (auto it = mDisplayModes.begin(); it != mDisplayModes.end(); ++it) {
+ scores.emplace_back(RefreshRateScore{it, 0.0f});
+ }
+
+ std::sort(scores.begin(), scores.end(), [](const auto& lhs, const auto& rhs) {
+ const auto& mode1 = lhs.modeIt->second;
+ const auto& mode2 = rhs.modeIt->second;
+ return isStrictlyLess(mode1->getFps(), mode2->getFps());
+ });
+
std::unordered_map<uid_t, std::vector<const LayerRequirement*>> layersByUid =
groupLayersByUid(layers);
UidToFrameRateOverride frameRateOverrides;
@@ -524,8 +575,8 @@
continue;
}
- for (auto& score : scores) {
- score.score = 0;
+ for (auto& [_, score] : scores) {
+ score = 0;
}
for (const auto& layer : layersWithSameUid) {
@@ -536,137 +587,114 @@
LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
layer->vote != LayerVoteType::ExplicitExact);
- for (RefreshRateScore& score : scores) {
- const auto layerScore = calculateLayerScoreLocked(*layer, *score.refreshRate,
- /*isSeamlessSwitch*/ true);
- score.score += layer->weight * layerScore;
+ for (auto& [modeIt, score] : scores) {
+ constexpr bool isSeamlessSwitch = true;
+ const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(),
+ isSeamlessSwitch);
+ score += layer->weight * layerScore;
}
}
// We just care about the refresh rates which are a divisor of the
// display refresh rate
- auto iter =
- std::remove_if(scores.begin(), scores.end(), [&](const RefreshRateScore& score) {
- return getFrameRateDivisor(displayFrameRate, score.refreshRate->getFps()) == 0;
- });
- scores.erase(iter, scores.end());
+ const auto it = std::remove_if(scores.begin(), scores.end(), [&](RefreshRateScore score) {
+ const auto& [id, mode] = *score.modeIt;
+ return getFrameRateDivisor(displayRefreshRate, mode->getFps()) == 0;
+ });
+ scores.erase(it, scores.end());
// If we never scored any layers, we don't have a preferred frame rate
if (std::all_of(scores.begin(), scores.end(),
- [](const RefreshRateScore& score) { return score.score == 0; })) {
+ [](RefreshRateScore score) { return score.score == 0; })) {
continue;
}
// Now that we scored all the refresh rates we need to pick the one that got the highest
// score.
- const RefreshRate* bestRefreshRate = getBestRefreshRate(scores.begin(), scores.end());
+ const DisplayModePtr& bestRefreshRate =
+ getMaxScoreRefreshRate(scores.begin(), scores.end());
+
frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
}
return frameRateOverrides;
}
-template <typename Iter>
-const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
- constexpr auto kEpsilon = 0.0001f;
- const RefreshRate* bestRefreshRate = begin->refreshRate;
- float max = begin->score;
- for (auto i = begin; i != end; ++i) {
- const auto [refreshRate, score] = *i;
- ALOGV("%s scores %.2f", refreshRate->getName().c_str(), score);
-
- ATRACE_INT(refreshRate->getName().c_str(), static_cast<int>(std::round(score * 100)));
-
- if (score > max * (1 + kEpsilon)) {
- max = score;
- bestRefreshRate = refreshRate;
- }
- }
-
- return bestRefreshRate;
-}
-
std::optional<Fps> RefreshRateConfigs::onKernelTimerChanged(
- std::optional<DisplayModeId> desiredActiveConfigId, bool timerExpired) const {
+ std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const {
std::lock_guard lock(mLock);
- const auto& current = desiredActiveConfigId ? *mRefreshRates.at(*desiredActiveConfigId)
- : *mCurrentRefreshRate;
- const auto& min = *mMinSupportedRefreshRate;
+ const DisplayModePtr& current = desiredActiveModeId
+ ? mDisplayModes.get(*desiredActiveModeId)->get()
+ : mActiveModeIt->second;
- if (current != min) {
- const auto& refreshRate = timerExpired ? min : current;
- return refreshRate.getFps();
+ const DisplayModePtr& min = mMinRefreshRateModeIt->second;
+ if (current == min) {
+ return {};
}
- return {};
+ const auto& mode = timerExpired ? min : current;
+ return mode->getFps();
}
-const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
- for (auto refreshRate : mPrimaryRefreshRates) {
- if (mCurrentRefreshRate->getModeGroup() == refreshRate->getModeGroup()) {
- return *refreshRate;
+const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
+ for (const DisplayModeIterator modeIt : mPrimaryRefreshRates) {
+ const auto& mode = modeIt->second;
+ if (mActiveModeIt->second->getGroup() == mode->getGroup()) {
+ return mode;
}
}
+
ALOGE("Can't find min refresh rate by policy with the same mode group"
" as the current mode %s",
- mCurrentRefreshRate->toString().c_str());
- // Defaulting to the lowest refresh rate
- return *mPrimaryRefreshRates.front();
+ to_string(*mActiveModeIt->second).c_str());
+
+ // Default to the lowest refresh rate.
+ return mPrimaryRefreshRates.front()->second;
}
-RefreshRate RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
+DisplayModePtr RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
return getMaxRefreshRateByPolicyLocked();
}
-const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
- for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) {
- const auto& refreshRate = (**it);
- if (anchorGroup == refreshRate.getModeGroup()) {
- return refreshRate;
+const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
+ for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) {
+ const auto& mode = (*it)->second;
+ if (anchorGroup == mode->getGroup()) {
+ return mode;
}
}
+
ALOGE("Can't find max refresh rate by policy with the same mode group"
" as the current mode %s",
- mCurrentRefreshRate->toString().c_str());
- // Defaulting to the highest refresh rate
- return *mPrimaryRefreshRates.back();
+ to_string(*mActiveModeIt->second).c_str());
+
+ // Default to the highest refresh rate.
+ return mPrimaryRefreshRates.back()->second;
}
-RefreshRate RefreshRateConfigs::getCurrentRefreshRate() const {
+DisplayModePtr RefreshRateConfigs::getActiveMode() const {
std::lock_guard lock(mLock);
- return *mCurrentRefreshRate;
+ return mActiveModeIt->second;
}
-RefreshRate RefreshRateConfigs::getCurrentRefreshRateByPolicy() const {
- std::lock_guard lock(mLock);
- return getCurrentRefreshRateByPolicyLocked();
-}
-
-const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const {
- if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
- mCurrentRefreshRate) != mAppRequestRefreshRates.end()) {
- return *mCurrentRefreshRate;
- }
- return *mRefreshRates.at(getCurrentPolicyLocked()->defaultMode);
-}
-
-void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) {
+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();
- mCurrentRefreshRate = mRefreshRates.at(modeId).get();
+ mActiveModeIt = mDisplayModes.find(modeId);
+ LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end());
}
-RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
+RefreshRateConfigs::RefreshRateConfigs(DisplayModes modes, DisplayModeId activeModeId,
Config config)
: mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
initializeIdleTimer();
- updateDisplayModes(modes, currentModeId);
+ updateDisplayModes(std::move(modes), activeModeId);
}
void RefreshRateConfigs::initializeIdleTimer() {
@@ -688,64 +716,43 @@
}
}
-void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,
- DisplayModeId currentModeId) {
+void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) {
std::lock_guard lock(mLock);
- // The current mode should be supported
- LOG_ALWAYS_FATAL_IF(std::none_of(modes.begin(), modes.end(), [&](DisplayModePtr mode) {
- return mode->getId() == currentModeId;
- }));
-
// Invalidate the cached invocation to getBestRefreshRate. This forces
// the refresh rate to be recomputed on the next call to getBestRefreshRate.
mGetBestRefreshRateCache.reset();
- mRefreshRates.clear();
- for (const auto& mode : modes) {
- const auto modeId = mode->getId();
- mRefreshRates.emplace(modeId,
- std::make_unique<RefreshRate>(mode, RefreshRate::ConstructorTag(0)));
- if (modeId == currentModeId) {
- mCurrentRefreshRate = mRefreshRates.at(modeId).get();
- }
- }
+ mDisplayModes = std::move(modes);
+ mActiveModeIt = mDisplayModes.find(activeModeId);
+ LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end());
- std::vector<const RefreshRate*> sortedModes;
- getSortedRefreshRateListLocked([](const RefreshRate&) { return true; }, &sortedModes);
+ const auto sortedModes =
+ sortByRefreshRate(mDisplayModes, [](const DisplayMode&) { return true; });
+ mMinRefreshRateModeIt = sortedModes.front();
+ mMaxRefreshRateModeIt = sortedModes.back();
+
// Reset the policy because the old one may no longer be valid.
mDisplayManagerPolicy = {};
- mDisplayManagerPolicy.defaultMode = currentModeId;
- mMinSupportedRefreshRate = sortedModes.front();
- mMaxSupportedRefreshRate = sortedModes.back();
+ mDisplayManagerPolicy.defaultMode = activeModeId;
- mSupportsFrameRateOverrideByContent = false;
- if (mConfig.enableFrameRateOverride) {
- for (const auto& mode1 : sortedModes) {
- for (const auto& mode2 : sortedModes) {
- if (getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) {
- mSupportsFrameRateOverrideByContent = true;
- break;
- }
- }
- }
- }
+ mSupportsFrameRateOverrideByContent =
+ mConfig.enableFrameRateOverride && canModesSupportFrameRateOverride(sortedModes);
constructAvailableRefreshRates();
}
bool RefreshRateConfigs::isPolicyValidLocked(const Policy& policy) const {
// defaultMode must be a valid mode, and within the given refresh rate range.
- auto iter = mRefreshRates.find(policy.defaultMode);
- if (iter == mRefreshRates.end()) {
+ if (const auto mode = mDisplayModes.get(policy.defaultMode)) {
+ if (!policy.primaryRange.includes(mode->get()->getFps())) {
+ ALOGE("Default mode is not in the primary range.");
+ return false;
+ }
+ } else {
ALOGE("Default mode is not found.");
return false;
}
- const RefreshRate& refreshRate = *iter->second;
- if (!policy.primaryRange.includes(refreshRate.getFps())) {
- ALOGE("Default mode is not in the primary range.");
- return false;
- }
using namespace fps_approx_ops;
return policy.appRequestRange.min <= policy.primaryRange.min &&
@@ -799,77 +806,46 @@
bool RefreshRateConfigs::isModeAllowed(DisplayModeId modeId) const {
std::lock_guard lock(mLock);
- for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
- if (refreshRate->getModeId() == modeId) {
- return true;
- }
- }
- return false;
-}
-
-void RefreshRateConfigs::getSortedRefreshRateListLocked(
- const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
- std::vector<const RefreshRate*>* outRefreshRates) {
- outRefreshRates->clear();
- outRefreshRates->reserve(mRefreshRates.size());
- for (const auto& [type, refreshRate] : mRefreshRates) {
- if (shouldAddRefreshRate(*refreshRate)) {
- ALOGV("getSortedRefreshRateListLocked: mode %d added to list policy",
- refreshRate->getModeId().value());
- outRefreshRates->push_back(refreshRate.get());
- }
- }
-
- std::sort(outRefreshRates->begin(), outRefreshRates->end(),
- [](const auto refreshRate1, const auto refreshRate2) {
- if (refreshRate1->mode->getVsyncPeriod() !=
- refreshRate2->mode->getVsyncPeriod()) {
- return refreshRate1->mode->getVsyncPeriod() >
- refreshRate2->mode->getVsyncPeriod();
- } else {
- return refreshRate1->mode->getGroup() > refreshRate2->mode->getGroup();
- }
- });
+ return std::any_of(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
+ [modeId](DisplayModeIterator modeIt) {
+ return modeIt->second->getId() == modeId;
+ });
}
void RefreshRateConfigs::constructAvailableRefreshRates() {
- // Filter modes based on current policy and sort based on vsync period
+ // Filter modes based on current policy and sort on refresh rate.
const Policy* policy = getCurrentPolicyLocked();
- const auto& defaultMode = mRefreshRates.at(policy->defaultMode)->mode;
- ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str());
+ ALOGV("%s: %s ", __func__, policy->toString().c_str());
- auto filterRefreshRates =
- [&](FpsRange range, const char* rangeName,
- std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock) {
- getSortedRefreshRateListLocked(
- [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
- const auto& mode = refreshRate.mode;
+ const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get();
- return mode->getHeight() == defaultMode->getHeight() &&
- mode->getWidth() == defaultMode->getWidth() &&
- mode->getDpiX() == defaultMode->getDpiX() &&
- mode->getDpiY() == defaultMode->getDpiY() &&
- (policy->allowGroupSwitching ||
- mode->getGroup() == defaultMode->getGroup()) &&
- range.includes(mode->getFps());
- },
- outRefreshRates);
+ const auto filterRefreshRates = [&](FpsRange range, const char* rangeName) REQUIRES(mLock) {
+ const auto filter = [&](const DisplayMode& mode) {
+ return mode.getResolution() == defaultMode->getResolution() &&
+ mode.getDpi() == defaultMode->getDpi() &&
+ (policy->allowGroupSwitching || mode.getGroup() == defaultMode->getGroup()) &&
+ range.includes(mode.getFps());
+ };
- LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(), "No matching modes for %s range %s",
- rangeName, to_string(range).c_str());
+ const auto modes = sortByRefreshRate(mDisplayModes, filter);
+ LOG_ALWAYS_FATAL_IF(modes.empty(), "No matching modes for %s range %s", rangeName,
+ to_string(range).c_str());
- auto stringifyRefreshRates = [&]() -> std::string {
- std::string str;
- for (auto refreshRate : *outRefreshRates) {
- base::StringAppendF(&str, "%s ", refreshRate->getName().c_str());
- }
- return str;
- };
- ALOGV("%s refresh rates: %s", rangeName, stringifyRefreshRates().c_str());
- };
+ const auto stringifyModes = [&] {
+ std::string str;
+ for (const auto modeIt : modes) {
+ str += to_string(modeIt->second->getFps());
+ str.push_back(' ');
+ }
+ return str;
+ };
+ ALOGV("%s refresh rates: %s", rangeName, stringifyModes().c_str());
- filterRefreshRates(policy->primaryRange, "primary", &mPrimaryRefreshRates);
- filterRefreshRates(policy->appRequestRange, "app request", &mAppRequestRefreshRates);
+ return modes;
+ };
+
+ mPrimaryRefreshRates = filterRefreshRates(policy->primaryRange, "primary");
+ mAppRequestRefreshRates = filterRefreshRates(policy->appRequestRange, "app request");
}
Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
@@ -893,36 +869,39 @@
RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const {
std::lock_guard lock(mLock);
- const auto& deviceMin = *mMinSupportedRefreshRate;
- const auto& minByPolicy = getMinRefreshRateByPolicyLocked();
- const auto& maxByPolicy = getMaxRefreshRateByPolicyLocked();
- const auto& currentPolicy = getCurrentPolicyLocked();
+
+ const Fps deviceMinFps = mMinRefreshRateModeIt->second->getFps();
+ const DisplayModePtr& minByPolicy = getMinRefreshRateByPolicyLocked();
// Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that
// the min allowed refresh rate is higher than the device min, we do not want to enable the
// timer.
- if (deviceMin < minByPolicy) {
- return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
+ if (isStrictlyLess(deviceMinFps, minByPolicy->getFps())) {
+ return KernelIdleTimerAction::TurnOff;
}
+
+ const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked();
if (minByPolicy == maxByPolicy) {
- // when min primary range in display manager policy is below device min turn on the timer.
- if (isApproxLess(currentPolicy->primaryRange.min, deviceMin.getFps())) {
- return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
+ // Turn on the timer when the min of the primary range is below the device min.
+ if (const Policy* currentPolicy = getCurrentPolicyLocked();
+ isApproxLess(currentPolicy->primaryRange.min, deviceMinFps)) {
+ return KernelIdleTimerAction::TurnOn;
}
- return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
+ return KernelIdleTimerAction::TurnOff;
}
+
// Turn on the timer in all other cases.
- return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
+ return KernelIdleTimerAction::TurnOn;
}
-int RefreshRateConfigs::getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate) {
+int RefreshRateConfigs::getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate) {
// This calculation needs to be in sync with the java code
// in DisplayManagerService.getDisplayInfoForFrameRateOverride
// The threshold must be smaller than 0.001 in order to differentiate
// between the fractional pairs (e.g. 59.94 and 60).
constexpr float kThreshold = 0.0009f;
- const auto numPeriods = displayFrameRate.getValue() / layerFrameRate.getValue();
+ const auto numPeriods = displayRefreshRate.getValue() / layerFrameRate.getValue();
const auto numPeriodsRounded = std::round(numPeriods);
if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
return 0;
@@ -952,29 +931,32 @@
currentPolicy.toString().c_str());
}
- auto mode = mCurrentRefreshRate->mode;
- base::StringAppendF(&result, "Current mode: %s\n", mCurrentRefreshRate->toString().c_str());
+ base::StringAppendF(&result, "Active mode: %s\n", to_string(*mActiveModeIt->second).c_str());
- result.append("Refresh rates:\n");
- for (const auto& [id, refreshRate] : mRefreshRates) {
- mode = refreshRate->mode;
- base::StringAppendF(&result, "\t%s\n", refreshRate->toString().c_str());
+ result.append("Display modes:\n");
+ for (const auto& [id, mode] : mDisplayModes) {
+ result.push_back('\t');
+ result.append(to_string(*mode));
+ result.push_back('\n');
}
base::StringAppendF(&result, "Supports Frame Rate Override By Content: %s\n",
mSupportsFrameRateOverrideByContent ? "yes" : "no");
- base::StringAppendF(&result, "Idle timer: ");
- if (mConfig.kernelIdleTimerController.has_value()) {
- if (mConfig.kernelIdleTimerController == KernelIdleTimerController::Sysprop) {
- base::StringAppendF(&result, "(kernel(sysprop))");
- } else {
- base::StringAppendF(&result, "(kernel(hwc))");
- }
+
+ result.append("Idle timer: ");
+ if (const auto controller = mConfig.kernelIdleTimerController) {
+ base::StringAppendF(&result, "(kernel via %s) ", ftl::enum_string(*controller).c_str());
} else {
- base::StringAppendF(&result, "(platform)");
+ result.append("(platform) ");
}
- base::StringAppendF(&result, " %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : "off");
- result.append("\n");
+
+ if (mIdleTimer) {
+ result.append(mIdleTimer->dump());
+ } else {
+ result.append("off");
+ }
+
+ result.append("\n\n");
}
std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 30d3edd..05a8692 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -56,50 +56,6 @@
static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION =
std::chrono::nanoseconds(800us).count();
- class RefreshRate {
- private:
- // Effectively making the constructor private while allowing
- // std::make_unique to create the object
- struct ConstructorTag {
- explicit ConstructorTag(int) {}
- };
-
- public:
- RefreshRate(DisplayModePtr mode, ConstructorTag) : mode(mode) {}
-
- DisplayModeId getModeId() const { return mode->getId(); }
- nsecs_t getVsyncPeriod() const { return mode->getVsyncPeriod(); }
- int32_t getModeGroup() const { return mode->getGroup(); }
- std::string getName() const { return to_string(getFps()); }
- Fps getFps() const { return mode->getFps(); }
- DisplayModePtr getMode() const { return mode; }
-
- // Checks whether the fps of this RefreshRate struct is within a given min and max refresh
- // rate passed in. Margin of error is applied to the boundaries for approximation.
- bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const;
-
- bool operator==(const RefreshRate& other) const { return mode == other.mode; }
- bool operator!=(const RefreshRate& other) const { return !operator==(other); }
-
- bool operator<(const RefreshRate& other) const {
- return isStrictlyLess(getFps(), other.getFps());
- }
-
- std::string toString() const;
- friend std::ostream& operator<<(std::ostream& os, const RefreshRate& refreshRate) {
- return os << refreshRate.toString();
- }
-
- private:
- friend RefreshRateConfigs;
- friend class RefreshRateConfigsTest;
-
- DisplayModePtr mode;
- };
-
- using AllRefreshRatesMapType =
- std::unordered_map<DisplayModeId, std::unique_ptr<const RefreshRate>>;
-
struct Policy {
private:
static constexpr int kAllowGroupSwitchingDefault = false;
@@ -236,12 +192,12 @@
// 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<RefreshRate, GlobalSignals> getBestRefreshRate(const std::vector<LayerRequirement>&,
- GlobalSignals) const EXCLUDES(mLock);
+ std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRate(
+ const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock);
FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
std::lock_guard lock(mLock);
- return {mMinSupportedRefreshRate->getFps(), mMaxSupportedRefreshRate->getFps()};
+ return {mMinRefreshRateModeIt->second->getFps(), mMaxRefreshRateModeIt->second->getFps()};
}
std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId,
@@ -249,30 +205,15 @@
// Returns the highest refresh rate according to the current policy. May change at runtime. Only
// uses the primary range, not the app request range.
- RefreshRate getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
+ DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
- // Returns the current refresh rate
- RefreshRate getCurrentRefreshRate() const EXCLUDES(mLock);
-
- // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
- // the policy.
- RefreshRate getCurrentRefreshRateByPolicy() const;
-
- // Returns the refresh rate that corresponds to a DisplayModeId. This may change at
- // runtime.
- // TODO(b/159590486) An invalid mode id may be given here if the dipslay modes have changed.
- RefreshRate getRefreshRateFromModeId(DisplayModeId modeId) const EXCLUDES(mLock) {
- std::lock_guard lock(mLock);
- return *mRefreshRates.at(modeId);
- };
-
- // Stores the current modeId the device operates at
- void setCurrentModeId(DisplayModeId) EXCLUDES(mLock);
+ void setActiveModeId(DisplayModeId) EXCLUDES(mLock);
+ DisplayModePtr getActiveMode() const EXCLUDES(mLock);
// Returns a known frame rate that is the closest to frameRate
Fps findClosestKnownFrameRate(Fps frameRate) const;
- enum class KernelIdleTimerController { Sysprop, HwcApi };
+ enum class KernelIdleTimerController { Sysprop, HwcApi, ftl_last = HwcApi };
// Configuration flags.
struct Config {
@@ -291,7 +232,7 @@
std::optional<KernelIdleTimerController> kernelIdleTimerController;
};
- RefreshRateConfigs(const DisplayModes&, DisplayModeId,
+ RefreshRateConfigs(DisplayModes, DisplayModeId activeModeId,
Config config = {.enableFrameRateOverride = false,
.frameRateMultipleThreshold = 0,
.idleTimerTimeout = 0ms,
@@ -305,7 +246,7 @@
// differ in resolution.
bool canSwitch() const EXCLUDES(mLock) {
std::lock_guard lock(mLock);
- return mRefreshRates.size() > 1;
+ return mDisplayModes.size() > 1;
}
// Class to enumerate options around toggling the kernel timer on and off.
@@ -323,7 +264,7 @@
// Return the display refresh rate divisor to match the layer
// frame rate, or 0 if the display refresh rate is not a multiple of the
// layer refresh rate.
- static int getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate);
+ static int getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate);
// Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000
// for an integer t.
@@ -391,54 +332,39 @@
void constructAvailableRefreshRates() REQUIRES(mLock);
- void getSortedRefreshRateListLocked(
- const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
- std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock);
-
- std::pair<RefreshRate, GlobalSignals> getBestRefreshRateLocked(
+ std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRateLocked(
const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock);
- // Returns the refresh rate with the highest score in the collection specified from begin
- // to end. If there are more than one with the same highest refresh rate, the first one is
- // returned.
- template <typename Iter>
- const RefreshRate* getBestRefreshRate(Iter begin, Iter end) const;
-
// Returns number of display frames and remainder when dividing the layer refresh period by
// display refresh period.
std::pair<nsecs_t, nsecs_t> getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const;
// Returns the lowest refresh rate according to the current policy. May change at runtime. Only
// uses the primary range, not the app request range.
- const RefreshRate& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock);
+ const DisplayModePtr& getMinRefreshRateByPolicyLocked() const REQUIRES(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.
- const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) {
- return getMaxRefreshRateByPolicyLocked(mCurrentRefreshRate->getModeGroup());
+ const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock);
+ const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) {
+ return getMaxRefreshRateByPolicyLocked(mActiveModeIt->second->getGroup());
}
- const RefreshRate& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock);
-
- // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
- // the policy.
- const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock);
-
const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
// Returns whether the layer is allowed to vote for the given refresh rate.
- bool isVoteAllowed(const LayerRequirement&, const RefreshRate&) const;
+ bool isVoteAllowed(const LayerRequirement&, Fps) const;
// 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&, const RefreshRate&,
+ float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate,
bool isSeamlessSwitch) const REQUIRES(mLock);
- float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&,
- const RefreshRate&) const REQUIRES(mLock);
+ float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const
+ REQUIRES(mLock);
- void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
+ void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock);
void initializeIdleTimer();
@@ -449,32 +375,22 @@
: mIdleTimerCallbacks->platform;
}
- // The list of refresh rates, indexed by display modes ID. This may change after this
- // object is initialized.
- AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
+ // The display modes of the active display. The DisplayModeIterators below are pointers into
+ // this container, so must be invalidated whenever the DisplayModes change. The Policy below
+ // is also dependent, so must be reset as well.
+ DisplayModes mDisplayModes GUARDED_BY(mLock);
- // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod
- // (the first element is the lowest refresh rate).
- std::vector<const RefreshRate*> mPrimaryRefreshRates GUARDED_BY(mLock);
+ DisplayModeIterator mActiveModeIt GUARDED_BY(mLock);
+ DisplayModeIterator mMinRefreshRateModeIt GUARDED_BY(mLock);
+ DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock);
- // The list of refresh rates in the app request range of the current policy, ordered by
- // vsyncPeriod (the first element is the lowest refresh rate).
- std::vector<const RefreshRate*> mAppRequestRefreshRates GUARDED_BY(mLock);
+ // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate.
+ std::vector<DisplayModeIterator> mPrimaryRefreshRates GUARDED_BY(mLock);
+ std::vector<DisplayModeIterator> mAppRequestRefreshRates GUARDED_BY(mLock);
- // The current display mode. This will change at runtime. This is set by SurfaceFlinger on
- // the main thread, and read by the Scheduler (and other objects) on other threads.
- const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock);
-
- // The policy values will change at runtime. They're set by SurfaceFlinger on the main thread,
- // and read by the Scheduler (and other objects) on other threads.
Policy mDisplayManagerPolicy GUARDED_BY(mLock);
std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);
- // The min and max refresh rates supported by the device.
- // This may change at runtime.
- const RefreshRate* mMinSupportedRefreshRate GUARDED_BY(mLock);
- const RefreshRate* mMaxSupportedRefreshRate GUARDED_BY(mLock);
-
mutable std::mutex mLock;
// A sorted list of known frame rates that a Heuristic layer will choose
@@ -486,7 +402,7 @@
struct GetBestRefreshRateCache {
std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
- std::pair<RefreshRate, GlobalSignals> result;
+ std::pair<DisplayModePtr, GlobalSignals> result;
};
mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index f1ad755..ed65bc6 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -17,7 +17,9 @@
#pragma once
#include <chrono>
-#include <numeric>
+#include <cinttypes>
+#include <cstdlib>
+#include <string>
#include <android-base/stringprintf.h>
#include <ftl/small_map.h>
@@ -25,6 +27,7 @@
#include <scheduler/Fps.h>
+#include "DisplayHardware/Hal.h"
#include "TimeStats/TimeStats.h"
namespace android::scheduler {
@@ -41,16 +44,16 @@
static constexpr int64_t MS_PER_HOUR = 60 * MS_PER_MIN;
static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
+ using PowerMode = android::hardware::graphics::composer::hal::PowerMode;
+
public:
// TODO(b/185535769): Inject clock to avoid sleeping in tests.
- RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate,
- android::hardware::graphics::composer::hal::PowerMode currentPowerMode)
+ RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate, PowerMode currentPowerMode)
: mTimeStats(timeStats),
mCurrentRefreshRate(currentRefreshRate),
mCurrentPowerMode(currentPowerMode) {}
- // Sets power mode.
- void setPowerMode(android::hardware::graphics::composer::hal::PowerMode mode) {
+ void setPowerMode(PowerMode mode) {
if (mCurrentPowerMode == mode) {
return;
}
@@ -115,7 +118,7 @@
uint32_t fps = 0;
- if (mCurrentPowerMode == android::hardware::graphics::composer::hal::PowerMode::ON) {
+ if (mCurrentPowerMode == PowerMode::ON) {
// Normal power mode is counted under different config modes.
const auto total = std::as_const(mFpsTotalTimes)
.get(mCurrentRefreshRate)
@@ -144,7 +147,7 @@
TimeStats& mTimeStats;
Fps mCurrentRefreshRate;
- android::hardware::graphics::composer::hal::PowerMode mCurrentPowerMode;
+ PowerMode mCurrentPowerMode;
ftl::SmallMap<Fps, std::chrono::milliseconds, 2, FpsApproxEqual> mFpsTotalTimes;
std::chrono::milliseconds mScreenOffTime = std::chrono::milliseconds::zero();
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 1fa455a..3aa0a5f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -166,18 +166,15 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
- const auto refreshRateConfigs = holdRefreshRateConfigs();
- nsecs_t basePeriod = refreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps();
+ const nsecs_t basePeriod = refreshRate.getPeriodNsecs();
+
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
return basePeriod;
}
- const auto divisor =
- scheduler::RefreshRateConfigs::getFrameRateDivisor(refreshRateConfigs
- ->getCurrentRefreshRate()
- .getFps(),
- *frameRate);
+ const auto divisor = RefreshRateConfigs::getFrameRateDivisor(refreshRate, *frameRate);
if (divisor <= 1) {
return basePeriod;
}
@@ -307,7 +304,7 @@
// 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->getCurrentRefreshRate().getMode() != mPolicy.mode) {
+ mRefreshRateConfigs->getActiveMode() != mPolicy.mode) {
return;
}
@@ -422,7 +419,7 @@
}
}
-void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
+void Scheduler::resyncToHardwareVsync(bool makeAvailable, Fps refreshRate) {
{
std::lock_guard<std::mutex> lock(mHWVsyncLock);
if (makeAvailable) {
@@ -434,11 +431,7 @@
}
}
- if (period <= 0) {
- return;
- }
-
- setVsyncPeriod(period);
+ setVsyncPeriod(refreshRate.getPeriodNsecs());
}
void Scheduler::resync() {
@@ -448,15 +441,17 @@
const nsecs_t last = mLastResyncTime.exchange(now);
if (now - last > kIgnoreDelay) {
- const auto vsyncPeriod = [&] {
+ const auto refreshRate = [&] {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ return mRefreshRateConfigs->getActiveMode()->getFps();
}();
- resyncToHardwareVsync(false, vsyncPeriod);
+ resyncToHardwareVsync(false, refreshRate);
}
}
void Scheduler::setVsyncPeriod(nsecs_t period) {
+ if (period <= 0) return;
+
std::lock_guard<std::mutex> lock(mHWVsyncLock);
mVsyncSchedule->getController().startPeriodTransition(period);
@@ -578,21 +573,20 @@
// TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
// magic number
- const auto refreshRate = [&] {
+ const Fps refreshRate = [&] {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getCurrentRefreshRate();
+ return mRefreshRateConfigs->getActiveMode()->getFps();
}();
constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
using namespace fps_approx_ops;
- if (state == TimerState::Reset && refreshRate.getFps() > FPS_THRESHOLD_FOR_KERNEL_TIMER) {
+ if (state == TimerState::Reset && refreshRate > FPS_THRESHOLD_FOR_KERNEL_TIMER) {
// If we're not in performance mode then the kernel timer shouldn't do
// anything, as the refresh rate during DPU power collapse will be the
// same.
- resyncToHardwareVsync(true /* makeAvailable */, refreshRate.getVsyncPeriod());
- } else if (state == TimerState::Expired &&
- refreshRate.getFps() <= FPS_THRESHOLD_FOR_KERNEL_TIMER) {
+ resyncToHardwareVsync(true /* makeAvailable */, refreshRate);
+ } else if (state == TimerState::Expired && refreshRate <= FPS_THRESHOLD_FOR_KERNEL_TIMER) {
// Disable HW VSYNC if the timer expired, as we don't need it enabled if
// we're not pushing frames, and if we're in PERFORMANCE mode then we'll
// need to update the VsyncController model anyway.
@@ -693,11 +687,9 @@
}
}
if (refreshRateChanged) {
- const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
-
- mSchedulerCallback.changeRefreshRate(newRefreshRate,
- consideredSignals.idle ? DisplayModeEvent::None
- : DisplayModeEvent::Changed);
+ mSchedulerCallback.requestDisplayMode(std::move(newMode),
+ consideredSignals.idle ? DisplayModeEvent::None
+ : DisplayModeEvent::Changed);
}
if (frameRateOverridesChanged) {
mSchedulerCallback.triggerOnFrameRateOverridesChanged();
@@ -715,16 +707,13 @@
if (mDisplayPowerTimer &&
(!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) {
constexpr GlobalSignals kNoSignals;
- return {configs->getMaxRefreshRateByPolicy().getMode(), kNoSignals};
+ return {configs->getMaxRefreshRateByPolicy(), kNoSignals};
}
const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active,
.idle = mPolicy.idleTimer == TimerState::Expired};
- const auto [refreshRate, consideredSignals] =
- configs->getBestRefreshRate(mPolicy.contentRequirements, signals);
-
- return {refreshRate.getMode(), consideredSignals};
+ return configs->getBestRefreshRate(mPolicy.contentRequirements, signals);
}
DisplayModePtr Scheduler::getPreferredDisplayMode() {
@@ -737,10 +726,6 @@
}
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
- if (timeline.refreshRequired) {
- mSchedulerCallback.scheduleComposite(FrameHint::kNone);
- }
-
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
mLastVsyncPeriodChangeTimeline = std::make_optional(timeline);
@@ -750,23 +735,17 @@
}
}
-void Scheduler::onPostComposition(nsecs_t presentTime) {
- const bool recomposite = [=] {
- std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
- if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
- if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
- // We need to composite again as refreshTimeNanos is still in the future.
- return true;
- }
-
- mLastVsyncPeriodChangeTimeline->refreshRequired = false;
+bool Scheduler::onPostComposition(nsecs_t presentTime) {
+ std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
+ if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
+ if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
+ // We need to composite again as refreshTimeNanos is still in the future.
+ return true;
}
- return false;
- }();
- if (recomposite) {
- mSchedulerCallback.scheduleComposite(FrameHint::kNone);
+ mLastVsyncPeriodChangeTimeline->refreshRequired = false;
}
+ return false;
}
void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index f6c81c0..0c72124 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -83,15 +83,10 @@
namespace scheduler {
struct ISchedulerCallback {
- // Indicates frame activity, i.e. whether commit and/or composite is taking place.
- enum class FrameHint { kNone, kActive };
-
- using RefreshRate = RefreshRateConfigs::RefreshRate;
using DisplayModeEvent = scheduler::DisplayModeEvent;
- virtual void scheduleComposite(FrameHint) = 0;
virtual void setVsyncEnabled(bool) = 0;
- virtual void changeRefreshRate(const RefreshRate&, DisplayModeEvent) = 0;
+ virtual void requestDisplayMode(DisplayModePtr, DisplayModeEvent) = 0;
virtual void kernelTimerChanged(bool expired) = 0;
virtual void triggerOnFrameRateOverridesChanged() = 0;
@@ -166,8 +161,7 @@
// If makeAvailable is true, then hardware vsync will be turned on.
// Otherwise, if hardware vsync is not already enabled then this method will
// no-op.
- // The period is the vsync period from the current display configuration.
- void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
+ void resyncToHardwareVsync(bool makeAvailable, Fps refreshRate);
void resync() EXCLUDES(mRefreshRateConfigsLock);
void forceNextResync() { mLastResyncTime = 0; }
@@ -212,8 +206,8 @@
// Notifies the scheduler about a refresh rate timeline change.
void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
- // Notifies the scheduler post composition.
- void onPostComposition(nsecs_t presentTime);
+ // Notifies the scheduler post composition. Returns if recomposite is needed.
+ bool onPostComposition(nsecs_t presentTime);
// Notifies the scheduler when the display size has changed. Called from SF's main thread
void onActiveDisplayAreaChanged(uint32_t displayArea);
@@ -236,7 +230,7 @@
nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ return mRefreshRateConfigs->getActiveMode()->getFps().getPeriodNsecs();
}
// Returns the framerate of the layer with the given sequence ID
@@ -247,8 +241,6 @@
private:
friend class TestableScheduler;
- using FrameHint = ISchedulerCallback::FrameHint;
-
enum class ContentDetectionState { Off, On };
enum class TimerState { Reset, Expired };
enum class TouchState { Inactive, Active };
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 3186d6d..4923031 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -29,6 +29,7 @@
namespace android::scheduler {
+class TimeKeeper;
class VSyncTracker;
// VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 425b78b..4fc9d27 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -24,7 +24,10 @@
#include "SurfaceFlinger.h"
+#include <android-base/parseint.h>
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android/configuration.h>
#include <android/gui/IDisplayEventConnection.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
@@ -49,6 +52,7 @@
#include <configstore/Utils.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
+#include <ftl/fake_guard.h>
#include <ftl/future.h>
#include <ftl/small_map.h>
#include <gui/BufferQueue.h>
@@ -123,6 +127,7 @@
#include "LayerRenderArea.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
+#include "MutexUtils.h"
#include "NativeWindowSurface.h"
#include "RefreshRateOverlay.h"
#include "RegionSamplingThread.h"
@@ -138,49 +143,26 @@
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
#include "WindowInfosListenerInvoker.h"
-#include "android-base/parseint.h"
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
-#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
-
-// Note: The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
-#define ON_MAIN_THREAD(expr) \
- [&]() -> decltype(auto) { \
- LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
- UnnecessaryLock lock(mStateLock); \
- return (expr); \
- }()
-
-#define MAIN_THREAD_GUARD(expr) \
- [&]() -> decltype(auto) { \
- LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
- MainThreadScopedGuard lock(SF_MAIN_THREAD); \
- return (expr); \
- }()
-
#undef NO_THREAD_SAFETY_ANALYSIS
#define NO_THREAD_SAFETY_ANALYSIS \
- _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
-
-using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
-using aidl::android::hardware::graphics::composer3::Capability;
-using aidl::android::hardware::graphics::composer3::DisplayCapability;
-using KernelIdleTimerController =
- ::android::scheduler::RefreshRateConfigs::KernelIdleTimerController;
+ _Pragma("GCC error \"Prefer <ftl/fake_guard.h> or MutexUtils.h helpers.\"")
namespace android {
using namespace std::string_literals;
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-using namespace android::sysprop;
+using namespace hardware::configstore;
+using namespace hardware::configstore::V1_0;
+using namespace sysprop;
-using android::hardware::power::Boost;
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
+using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
+
using base::StringAppendF;
using gui::DisplayInfo;
using gui::IDisplayEventConnection;
@@ -191,6 +173,8 @@
using ui::DisplayPrimaries;
using ui::RenderIntent;
+using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController;
+
namespace hal = android::hardware::graphics::composer::hal;
namespace {
@@ -222,38 +206,6 @@
#pragma clang diagnostic pop
-template <typename Mutex>
-struct SCOPED_CAPABILITY ConditionalLockGuard {
- ConditionalLockGuard(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) {
- if (lock) mutex.lock();
- }
-
- ~ConditionalLockGuard() RELEASE() {
- if (lock) mutex.unlock();
- }
-
- Mutex& mutex;
- const bool lock;
-};
-
-using ConditionalLock = ConditionalLockGuard<Mutex>;
-
-struct SCOPED_CAPABILITY TimedLock {
- TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex)
- : mutex(mutex), status(mutex.timedLock(timeout)) {
- ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status);
- }
-
- ~TimedLock() RELEASE() {
- if (locked()) mutex.unlock();
- }
-
- bool locked() const { return status == NO_ERROR; }
-
- Mutex& mutex;
- const status_t status;
-};
-
// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
@@ -324,7 +276,6 @@
uint32_t SurfaceFlinger::maxGraphicsWidth;
uint32_t SurfaceFlinger::maxGraphicsHeight;
bool SurfaceFlinger::hasWideColorDisplay;
-ui::Rotation SurfaceFlinger::internalDisplayOrientation = ui::ROTATION_0;
bool SurfaceFlinger::useContextPriority;
Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
@@ -416,22 +367,6 @@
useContextPriority = use_context_priority(true);
- using Values = SurfaceFlingerProperties::primary_display_orientation_values;
- switch (primary_display_orientation(Values::ORIENTATION_0)) {
- case Values::ORIENTATION_0:
- break;
- case Values::ORIENTATION_90:
- internalDisplayOrientation = ui::ROTATION_90;
- break;
- case Values::ORIENTATION_180:
- internalDisplayOrientation = ui::ROTATION_180;
- break;
- case Values::ORIENTATION_270:
- internalDisplayOrientation = ui::ROTATION_270;
- break;
- }
- ALOGV("Internal Display Orientation: %s", toCString(internalDisplayOrientation));
-
mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
// debugging stuff...
@@ -578,13 +513,13 @@
const ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
if (index < 0) {
- ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ ALOGE("%s: Invalid display token %p", __func__, displayToken.get());
return;
}
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
if (state.physical) {
- ALOGE("%s: Invalid operation on physical display", __FUNCTION__);
+ ALOGE("%s: Invalid operation on physical display", __func__);
return;
}
mInterceptor->saveDisplayDeletion(state.sequenceId);
@@ -707,10 +642,9 @@
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
- mFlagManager = std::make_unique<android::FlagManager>();
mFrameTracer->initialize();
mFrameTimeline->onBootFinished();
- getRenderEngine().setEnableTracing(mFlagManager->use_skia_tracing());
+ getRenderEngine().setEnableTracing(mFlagManager.use_skia_tracing());
// wait patiently for the window manager death
const String16 name("window");
@@ -738,22 +672,22 @@
}
readPersistentProperties();
- std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
- std::vector<int32_t> tidList;
- tidList.emplace_back(gettid());
- if (renderEngineTid.has_value()) {
- tidList.emplace_back(*renderEngineTid);
- }
mPowerAdvisor.onBootFinished();
- mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint());
+ mPowerAdvisor.enablePowerHint(mFlagManager.use_adpf_cpu_hint());
if (mPowerAdvisor.usePowerHintSession()) {
+ std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
+ std::vector<int32_t> tidList;
+ tidList.emplace_back(gettid());
+ if (renderEngineTid.has_value()) {
+ tidList.emplace_back(*renderEngineTid);
+ }
mPowerAdvisor.startPowerHintSession(tidList);
}
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
- ON_MAIN_THREAD(enableRefreshRateOverlay(true));
+ FTL_FAKE_GUARD(mStateLock, enableRefreshRateOverlay(true));
}
}));
}
@@ -954,8 +888,9 @@
FrameEvent::DEQUEUE_READY,
FrameEvent::RELEASE,
};
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
+
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+
if (!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
}
@@ -1014,9 +949,7 @@
info->secure = display->isSecure();
info->deviceProductInfo = display->getDeviceProductInfo();
-
- // TODO: Scale this to multiple displays.
- info->installOrientation = display->isPrimary() ? internalDisplayOrientation : ui::ROTATION_0;
+ info->installOrientation = display->getPhysicalOrientation();
return NO_ERROR;
}
@@ -1039,24 +972,21 @@
return INVALID_OPERATION;
}
- info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value());
+ info->activeDisplayModeId = display->getActiveMode()->getId().value();
const auto& supportedModes = display->getSupportedModes();
info->supportedDisplayModes.clear();
info->supportedDisplayModes.reserve(supportedModes.size());
- for (const auto& mode : supportedModes) {
+
+ for (const auto& [id, mode] : supportedModes) {
ui::DisplayMode outMode;
- outMode.id = static_cast<int32_t>(mode->getId().value());
+ outMode.id = static_cast<int32_t>(id.value());
- auto width = mode->getWidth();
- auto height = mode->getHeight();
+ auto [width, height] = mode->getResolution();
+ auto [xDpi, yDpi] = mode->getDpi();
- auto xDpi = mode->getDpiX();
- auto yDpi = mode->getDpiY();
-
- if (display->isPrimary() &&
- (internalDisplayOrientation == ui::ROTATION_90 ||
- internalDisplayOrientation == ui::ROTATION_270)) {
+ if (const auto physicalOrientation = display->getPhysicalOrientation();
+ physicalOrientation == ui::ROTATION_90 || physicalOrientation == ui::ROTATION_270) {
std::swap(width, height);
std::swap(xDpi, yDpi);
}
@@ -1104,13 +1034,18 @@
info->autoLowLatencyModeSupported =
getHwComposer().hasDisplayCapability(*displayId,
DisplayCapability::AUTO_LOW_LATENCY_MODE);
- std::vector<hal::ContentType> types;
- getHwComposer().getSupportedContentTypes(*displayId, &types);
- info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) {
- return type == hal::ContentType::GAME;
- });
+ info->gameContentTypeSupported =
+ getHwComposer().supportsContentType(*displayId, hal::ContentType::GAME);
- info->preferredBootDisplayMode = display->getPreferredBootModeId();
+ 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)) {
+ info->preferredBootDisplayMode = modeId->value();
+ }
+ }
+ }
return NO_ERROR;
}
@@ -1142,7 +1077,7 @@
// Start receiving vsync samples now, so that we can detect a period
// switch.
- mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod());
+ mScheduler->resyncToHardwareVsync(true, info.mode->getFps());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// VsyncController model is locked.
modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
@@ -1160,7 +1095,7 @@
}
auto future = mScheduler->schedule([=]() -> status_t {
- const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
+ 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());
@@ -1201,14 +1136,16 @@
return;
}
- const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode());
+ const auto upcomingModeInfo =
+ FTL_FAKE_GUARD(kMainThreadContext, 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()->getSize() != upcomingModeInfo.mode->getSize()) {
+ 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).
@@ -1220,9 +1157,8 @@
return;
}
- // We just created this display so we can call even if we are not on
- // the main thread
- MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ // 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());
const Fps refreshRate = upcomingModeInfo.mode->getFps();
@@ -1244,7 +1180,7 @@
void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) {
const auto refreshRate = display->getDesiredActiveMode()->mode->getFps();
clearDesiredActiveModeState(display);
- mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs());
+ mScheduler->resyncToHardwareVsync(true, refreshRate);
updatePhaseConfiguration(refreshRate);
}
@@ -1307,8 +1243,10 @@
constraints.seamlessRequired = false;
hal::VsyncPeriodChangeTimeline outTimeline;
- const auto status = MAIN_THREAD_GUARD(
- display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline));
+ const auto status = FTL_FAKE_GUARD(kMainThreadContext,
+ display->initiateModeChange(*desiredActiveMode,
+ constraints, &outTimeline));
+
if (status != NO_ERROR) {
// initiateModeChange may fail if a hotplug event is just about
// to be sent. We just log the error in this case.
@@ -1318,7 +1256,7 @@
mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
if (outTimeline.refreshRequired) {
- // Scheduler will submit an empty frame to HWC.
+ scheduleComposite(FrameHint::kNone);
mSetActiveModePending = true;
} else {
// Updating the internal state should be done outside the loop,
@@ -1341,7 +1279,7 @@
}
void SurfaceFlinger::disableExpensiveRendering() {
- auto future = mScheduler->schedule([=]() MAIN_THREAD {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
ATRACE_CALL();
if (mPowerAdvisor.isUsingExpensiveRendering()) {
for (const auto& [_, display] : mDisplays) {
@@ -1390,7 +1328,7 @@
return BAD_VALUE;
}
- auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
@@ -1425,38 +1363,48 @@
}
status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const {
- auto future = mScheduler->schedule([=]() MAIN_THREAD mutable -> status_t {
- *outSupport = getHwComposer().getBootDisplayModeSupport();
- return NO_ERROR;
- });
- return future.get();
+ auto future = mScheduler->schedule(
+ [this] { return getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG); });
+
+ *outSupport = future.get();
+ return NO_ERROR;
}
-status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) {
- auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
- if (const auto displayDevice = getDisplayDeviceLocked(displayToken)) {
- const auto mode = displayDevice->getMode(DisplayModeId{id});
- if (mode == nullptr) {
- ALOGE("%s: invalid display mode (%d)", __FUNCTION__, id);
- return BAD_VALUE;
- }
+status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken,
+ ui::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());
+ return NAME_NOT_FOUND;
+ }
- return getHwComposer().setBootDisplayMode(displayDevice->getPhysicalId(),
- mode->getHwcId());
- } else {
- ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", whence);
+ return INVALID_OPERATION;
+ }
+
+ 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());
return BAD_VALUE;
}
+
+ return getHwComposer().setBootDisplayMode(displayId, mode->getHwcId());
});
return future.get();
}
status_t SurfaceFlinger::clearBootDisplayMode(const sp<IBinder>& displayToken) {
- auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ const char* const whence = __func__;
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
return getHwComposer().clearBootDisplayMode(*displayId);
} else {
- ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ ALOGE("%s: Invalid display token %p", whence, displayToken.get());
return BAD_VALUE;
}
});
@@ -1465,7 +1413,7 @@
void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
const char* const whence = __func__;
- static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+ static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
getHwComposer().setAutoLowLatencyMode(*displayId, on);
} else {
@@ -1476,7 +1424,7 @@
void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
const char* const whence = __func__;
- static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+ static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE;
getHwComposer().setContentType(*displayId, type);
@@ -1504,7 +1452,7 @@
auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
- ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ ALOGE("%s: Invalid display token %p", __func__, displayToken.get());
return NAME_NOT_FOUND;
}
@@ -1541,7 +1489,7 @@
bool enable, uint8_t componentMask,
uint64_t maxFrames) {
const char* const whence = __func__;
- auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
componentMask, maxFrames);
@@ -1618,7 +1566,7 @@
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) {
outLayers->clear();
auto future = mScheduler->schedule([=] {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
mDrawingState.traverseInZOrder([&](Layer* layer) {
outLayers->push_back(layer->getLayerDebugInfo(display.get()));
});
@@ -1730,7 +1678,7 @@
}
const char* const whence = __func__;
- return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD {
+ return ftl::chain(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
if (const auto display = getDisplayDeviceLocked(displayToken)) {
const bool supportsDisplayBrightnessCommand =
getHwComposer().getComposer()->isSupported(
@@ -1744,7 +1692,9 @@
compositionDisplay->editState().displayBrightnessNits;
compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits,
brightness.displayBrightnessNits);
- MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
+ FTL_FAKE_GUARD(kMainThreadContext,
+ display->stageBrightness(brightness.displayBrightness));
+
if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits !=
currentDimmingRatio) {
scheduleComposite(FrameHint::kNone);
@@ -1814,6 +1764,7 @@
}
status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) {
+ using hardware::power::Boost;
Boost powerBoost = static_cast<Boost>(boostId);
if (powerBoost == Boost::INTERACTION) {
@@ -1949,6 +1900,10 @@
hal::HWDisplayId, const hal::VsyncPeriodChangeTimeline& timeline) {
Mutex::Autolock lock(mStateLock);
mScheduler->onNewVsyncPeriodChangeTimeline(timeline);
+
+ if (timeline.refreshRequired) {
+ scheduleComposite(FrameHint::kNone);
+ }
}
void SurfaceFlinger::onComposerHalSeamlessPossible(hal::HWDisplayId) {
@@ -1970,7 +1925,7 @@
ATRACE_CALL();
// On main thread to avoid race conditions with display power state.
- static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+ static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;
if (const auto display = getDefaultDisplayDeviceLocked();
@@ -2018,8 +1973,8 @@
: stats.vsyncTime + stats.vsyncPeriod;
}
-bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) {
- MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
+ FTL_FAKE_GUARD(kMainThreadContext) {
// we set this once at the beginning of commit to ensure consistency throughout the whole frame
mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession();
if (mPowerHintSessionData.sessionEnabled) {
@@ -2185,20 +2140,21 @@
mLayerTracing.notify(mVisibleRegionsDirty, frameTime);
}
- MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite));
+ persistDisplayBrightness(mustComposite);
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
-void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) {
+void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId)
+ FTL_FAKE_GUARD(kMainThreadContext) {
ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
- MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+
if (mPowerHintSessionData.sessionEnabled) {
mPowerHintSessionData.compositeStart = systemTime();
}
compositionengine::CompositionRefreshArgs refreshArgs;
- const auto& displays = ON_MAIN_THREAD(mDisplays);
+ const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
refreshArgs.outputs.reserve(displays.size());
for (const auto& [_, display] : displays) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
@@ -2256,7 +2212,9 @@
mTimeStats->recordFrameDuration(frameTime, systemTime());
- mScheduler->onPostComposition(presentTime);
+ if (mScheduler->onPostComposition(presentTime)) {
+ scheduleComposite(FrameHint::kNone);
+ }
postFrame();
postComposition();
@@ -2394,11 +2352,47 @@
return true;
}
+ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId,
+ bool isPrimary) const {
+ const auto id = PhysicalDisplayId::tryCast(displayId);
+ if (!id) {
+ return ui::ROTATION_0;
+ }
+ if (getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::PhysicalDisplayOrientation)) {
+ switch (getHwComposer().getPhysicalDisplayOrientation(*id)) {
+ case Hwc2::AidlTransform::ROT_90:
+ return ui::ROTATION_90;
+ case Hwc2::AidlTransform::ROT_180:
+ return ui::ROTATION_180;
+ case Hwc2::AidlTransform::ROT_270:
+ return ui::ROTATION_270;
+ default:
+ return ui::ROTATION_0;
+ }
+ }
+
+ if (isPrimary) {
+ using Values = SurfaceFlingerProperties::primary_display_orientation_values;
+ switch (primary_display_orientation(Values::ORIENTATION_0)) {
+ case Values::ORIENTATION_90:
+ return ui::ROTATION_90;
+ case Values::ORIENTATION_180:
+ return ui::ROTATION_180;
+ case Values::ORIENTATION_270:
+ return ui::ROTATION_270;
+ default:
+ break;
+ }
+ }
+ return ui::ROTATION_0;
+}
+
void SurfaceFlinger::postComposition() {
ATRACE_CALL();
ALOGV("postComposition");
- const auto* display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()).get();
+ const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
@@ -2598,44 +2592,37 @@
}
FloatRect SurfaceFlinger::getMaxDisplayBounds() {
- // Find the largest width and height among all the displays.
- int32_t maxDisplayWidth = 0;
- int32_t maxDisplayHeight = 0;
+ const ui::Size maxSize = [this] {
+ ftl::FakeGuard guard(mStateLock);
- // If there are no displays, set a valid display bounds so we can still compute a valid layer
- // bounds.
- if (ON_MAIN_THREAD(mDisplays.size()) == 0) {
- maxDisplayWidth = maxDisplayHeight = 5000;
- }
+ // The LayerTraceGenerator tool runs without displays.
+ if (mDisplays.empty()) return ui::Size{5000, 5000};
- for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
- const auto& displayDevice = pair.second;
- int32_t width = displayDevice->getWidth();
- int32_t height = displayDevice->getHeight();
- if (width > maxDisplayWidth) {
- maxDisplayWidth = width;
- }
- if (height > maxDisplayHeight) {
- maxDisplayHeight = height;
- }
- }
+ return std::accumulate(mDisplays.begin(), mDisplays.end(), ui::kEmptySize,
+ [](ui::Size size, const auto& pair) -> ui::Size {
+ const auto& display = pair.second;
+ return {std::max(size.getWidth(), display->getWidth()),
+ std::max(size.getHeight(), display->getHeight())};
+ });
+ }();
// Ignore display bounds for now since they will be computed later. Use a large Rect bound
// to ensure it's bigger than an actual display will be.
- FloatRect maxBounds = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10,
- maxDisplayWidth * 10, maxDisplayHeight * 10);
- return maxBounds;
+ const float xMax = maxSize.getWidth() * 10.f;
+ const float yMax = maxSize.getHeight() * 10.f;
+
+ return {-xMax, -yMax, xMax, yMax};
}
void SurfaceFlinger::computeLayerBounds() {
- FloatRect maxBounds = getMaxDisplayBounds();
+ const FloatRect maxBounds = getMaxDisplayBounds();
for (const auto& layer : mDrawingState.layersSortedByZ) {
layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
}
}
void SurfaceFlinger::postFrame() {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ 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) {
@@ -2666,11 +2653,11 @@
mDebugInTransaction = 0;
}
-void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes,
- DisplayModePtr& outActiveMode) const {
+std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes(
+ PhysicalDisplayId displayId) const {
std::vector<HWComposer::HWCDisplayMode> hwcModes;
std::optional<hal::HWDisplayId> activeModeHwcId;
- bool activeModeIsSupported;
+
int attempt = 0;
constexpr int kMaxAttempts = 3;
do {
@@ -2678,63 +2665,60 @@
activeModeHwcId = getHwComposer().getActiveMode(displayId);
LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active mode");
- activeModeIsSupported =
- std::any_of(hwcModes.begin(), hwcModes.end(),
- [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) {
- return mode.hwcId == *activeModeHwcId;
- });
- } while (!activeModeIsSupported && ++attempt < kMaxAttempts);
- LOG_ALWAYS_FATAL_IF(!activeModeIsSupported,
+ const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) {
+ return mode.hwcId == *activeModeHwcId;
+ };
+
+ if (std::any_of(hwcModes.begin(), hwcModes.end(), isActiveMode)) {
+ break;
+ }
+ } 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",
+ " 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();
}
- int largestUsedModeId = -1; // Use int instead of DisplayModeId for signedness
- for (const auto& mode : oldModes) {
- const auto id = static_cast<int>(mode->getId().value());
- if (id > largestUsedModeId) {
- largestUsedModeId = id;
- }
- }
+ ui::DisplayModeId nextModeId = 1 +
+ std::accumulate(oldModes.begin(), oldModes.end(), static_cast<ui::DisplayModeId>(-1),
+ [](ui::DisplayModeId max, const auto& pair) {
+ return std::max(max, pair.first.value());
+ });
DisplayModes newModes;
- int32_t nextModeId = largestUsedModeId + 1;
for (const auto& hwcMode : hwcModes) {
- newModes.push_back(DisplayMode::Builder(hwcMode.hwcId)
- .setId(DisplayModeId{nextModeId++})
- .setPhysicalDisplayId(displayId)
- .setWidth(hwcMode.width)
- .setHeight(hwcMode.height)
- .setVsyncPeriod(hwcMode.vsyncPeriod)
- .setDpiX(hwcMode.dpiX)
- .setDpiY(hwcMode.dpiY)
- .setGroup(hwcMode.configGroup)
- .build());
+ const DisplayModeId id{nextModeId++};
+ newModes.try_emplace(id,
+ DisplayMode::Builder(hwcMode.hwcId)
+ .setId(id)
+ .setPhysicalDisplayId(displayId)
+ .setResolution({hwcMode.width, hwcMode.height})
+ .setVsyncPeriod(hwcMode.vsyncPeriod)
+ .setDpiX(hwcMode.dpiX)
+ .setDpiY(hwcMode.dpiY)
+ .setGroup(hwcMode.configGroup)
+ .build());
}
- const bool modesAreSame =
+ const bool sameModes =
std::equal(newModes.begin(), newModes.end(), oldModes.begin(), oldModes.end(),
- [](DisplayModePtr left, DisplayModePtr right) {
- return left->equalsExceptDisplayModeId(right);
+ [](const auto& lhs, const auto& rhs) {
+ return equalsExceptDisplayModeId(*lhs.second, *rhs.second);
});
- if (modesAreSame) {
- // The supported modes have not changed, keep the old IDs.
- outModes = oldModes;
- } else {
- outModes = newModes;
- }
+ // Keep IDs if modes have not changed.
+ const auto& modes = sameModes ? oldModes : newModes;
+ const DisplayModePtr activeMode =
+ std::find_if(modes.begin(), modes.end(), [activeModeHwcId](const auto& pair) {
+ return pair.second->getHwcId() == activeModeHwcId;
+ })->second;
- outActiveMode = *std::find_if(outModes.begin(), outModes.end(),
- [activeModeHwcId](const DisplayModePtr& mode) {
- return mode->getHwcId() == *activeModeHwcId;
- });
+ return {modes, activeMode};
}
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
@@ -2750,9 +2734,7 @@
const auto it = mPhysicalDisplayTokens.find(displayId);
if (event.connection == hal::Connection::CONNECTED) {
- DisplayModes supportedModes;
- DisplayModePtr activeMode;
- loadDisplayModes(displayId, supportedModes, activeMode);
+ auto [supportedModes, activeMode] = loadDisplayModes(displayId);
if (it == mPhysicalDisplayTokens.end()) {
ALOGV("Creating display %s", to_string(displayId).c_str());
@@ -2763,7 +2745,7 @@
.hwcDisplayId = event.hwcDisplayId,
.deviceProductInfo = std::move(info->deviceProductInfo),
.supportedModes = std::move(supportedModes),
- .activeMode = activeMode};
+ .activeMode = std::move(activeMode)};
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = std::move(info->name);
@@ -2778,7 +2760,7 @@
auto& state = mCurrentState.displays.editValueFor(token);
state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId
state.physical->supportedModes = std::move(supportedModes);
- state.physical->activeMode = activeMode;
+ state.physical->activeMode = std::move(activeMode);
if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) {
state.physical->deviceProductInfo = std::move(info->deviceProductInfo);
}
@@ -2873,7 +2855,8 @@
}
creationArgs.physicalOrientation =
- creationArgs.isPrimary ? internalDisplayOrientation : ui::ROTATION_0;
+ getPhysicalDisplayOrientation(compositionDisplay->getId(), creationArgs.isPrimary);
+ ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation));
// virtual displays are always considered enabled
creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
@@ -2893,7 +2876,8 @@
RenderIntent::COLORIMETRIC,
Dataspace::UNKNOWN});
if (!state.isVirtual()) {
- MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId()));
+ FTL_FAKE_GUARD(kMainThreadContext,
+ display->setActiveMode(state.physical->activeMode->getId()));
display->setDeviceProductInfo(state.physical->deviceProductInfo);
}
@@ -2911,7 +2895,7 @@
ui::Size resolution(0, 0);
ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
if (state.physical) {
- resolution = state.physical->activeMode->getSize();
+ resolution = state.physical->activeMode->getResolution();
pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
} else if (state.surface != nullptr) {
int status = state.surface->query(NATIVE_WINDOW_WIDTH, &resolution.width);
@@ -2965,7 +2949,7 @@
LOG_FATAL_IF(!displayId);
displaySurface =
sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer,
- state.physical->activeMode->getSize(),
+ state.physical->activeMode->getResolution(),
ui::Size(maxGraphicsWidth, maxGraphicsHeight));
producer = bqProducer;
}
@@ -3078,7 +3062,7 @@
}
void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) {
mVsyncConfiguration->reset();
- const Fps refreshRate = activeDisplay->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ const Fps refreshRate = activeDisplay->refreshRateConfigs().getActiveMode()->getFps();
updatePhaseConfiguration(refreshRate);
mRefreshRateStats->setRefreshRate(refreshRate);
}
@@ -3263,7 +3247,7 @@
return;
}
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
if (const auto brightness = display->getStagedBrightness(); brightness) {
if (!needsComposite) {
const status_t error =
@@ -3286,7 +3270,7 @@
std::vector<DisplayInfo>& outDisplayInfos) {
ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos;
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
const auto layerStack = display->getLayerStack();
const auto info = display->getInputInfo();
@@ -3331,7 +3315,7 @@
void SurfaceFlinger::updateCursorAsync() {
compositionengine::CompositionRefreshArgs refreshArgs;
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
if (HalDisplayId::tryCast(display->getId())) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
@@ -3340,7 +3324,7 @@
mCompositionEngine->updateCursorAsync(refreshArgs);
}
-void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, DisplayModeEvent event) {
+void SurfaceFlinger::requestDisplayMode(DisplayModePtr mode, DisplayModeEvent event) {
// If this is called from the main thread mStateLock must be locked before
// Currently the only way to call this function from the main thread is from
// Scheduler::chooseRefreshRateForContent
@@ -3353,14 +3337,12 @@
}
ATRACE_CALL();
- // Don't do any updating if the current fps is the same as the new one.
- if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) {
- ALOGV("Skipping mode %d as it is not part of allowed modes",
- refreshRate.getModeId().value());
+ if (!display->refreshRateConfigs().isModeAllowed(mode->getId())) {
+ ALOGV("Skipping disallowed mode %d", mode->getId().value());
return;
}
- setDesiredActiveMode({refreshRate.getMode(), event});
+ setDesiredActiveMode({std::move(mode), event});
}
void SurfaceFlinger::triggerOnFrameRateOverridesChanged() {
@@ -3518,7 +3500,7 @@
}
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
- for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [token, displayDevice] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
auto display = displayDevice->getCompositionDisplay();
if (display->includesLayer(layer->getOutputFilter())) {
display->editState().dirtyRegion.orSelf(dirty);
@@ -3648,16 +3630,13 @@
return mTransactionFlags.fetch_and(~mask) & mask;
}
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask) {
- return setTransactionFlags(mask, TransactionSchedule::Late);
-}
-
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
- const sp<IBinder>& applyToken) {
- const uint32_t old = mTransactionFlags.fetch_or(mask);
+void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
+ const sp<IBinder>& applyToken) {
modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
- if ((old & mask) == 0) scheduleCommit(FrameHint::kActive);
- return old;
+
+ if (const bool scheduled = mTransactionFlags.fetch_or(mask) & mask; !scheduled) {
+ scheduleCommit(FrameHint::kActive);
+ }
}
bool SurfaceFlinger::stopTransactionProcessing(
@@ -3673,6 +3652,15 @@
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,
@@ -3707,8 +3695,8 @@
break;
}
transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
- const bool frameNumberChanged =
- state.bufferData->flags.test(BufferData::BufferDataChange::frameNumberChanged);
+ const bool frameNumberChanged = state.bufferData->flags.test(
+ BufferData::BufferDataChange::frameNumberChanged);
if (frameNumberChanged) {
bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber;
} else {
@@ -3788,8 +3776,8 @@
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);
+ const bool frameNumberChanged = state.bufferData->flags.test(
+ BufferData::BufferDataChange::frameNumberChanged);
if (frameNumberChanged) {
bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber;
} else {
@@ -3798,7 +3786,7 @@
bufferLayersReadyToPresent[state.surface] =
std::numeric_limits<uint64_t>::max();
}
- });
+ });
transactions.emplace_back(std::move(transaction));
}
mTransactionQueue.pop_front();
@@ -3827,9 +3815,8 @@
// 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) {
- flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
- applyTokensWithUnsignaledTransactions,
- /*tryApplyUnsignaled*/ true);
+ flushUnsignaledPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+ applyTokensWithUnsignaledTransactions);
}
return applyTransactions(transactions, vsyncId);
@@ -4788,8 +4775,7 @@
{}, mPid, getuid(), transactionId);
setPowerModeInternal(display, hal::PowerMode::ON);
- const nsecs_t vsyncPeriod =
- display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
+ const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
mActiveDisplayTransformHint = display->getTransformHint();
// Use phase of 0 since phase is not known.
@@ -4800,12 +4786,13 @@
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
- static_cast<void>(mScheduler->schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
+ static_cast<void>(
+ mScheduler->schedule([this]() FTL_FAKE_GUARD(mStateLock) { onInitializeDisplays(); }));
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
if (display->isVirtual()) {
- ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ ALOGE("%s: Invalid operation on virtual display", __func__);
return;
}
@@ -4828,7 +4815,7 @@
if (mInterceptor->isEnabled()) {
mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
}
- const auto vsyncPeriod = display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
+ const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
if (currentMode == hal::PowerMode::OFF) {
// Turn on the display
if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
@@ -4846,7 +4833,7 @@
if (isDisplayActiveLocked(display) && mode != hal::PowerMode::DOZE_SUSPEND) {
setHWCVsyncEnabled(displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
- mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
+ mScheduler->resyncToHardwareVsync(true, refreshRate);
}
mVisibleRegionsDirty = true;
@@ -4876,7 +4863,7 @@
getHwComposer().setPowerMode(displayId, mode);
if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
- mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
+ mScheduler->resyncToHardwareVsync(true, refreshRate);
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
@@ -4900,7 +4887,7 @@
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- auto future = mScheduler->schedule([=]() MAIN_THREAD {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4947,7 +4934,7 @@
bool dumpLayers = true;
{
- TimedLock lock(mStateLock, s2ns(1), __FUNCTION__);
+ TimedLock lock(mStateLock, s2ns(1), __func__);
if (!lock.locked()) {
StringAppendF(&result, "Dumping without lock after timeout: %s (%d)\n",
strerror(-lock.status), lock.status);
@@ -5035,8 +5022,6 @@
mFrameTimeline->parseArgs(args, result);
}
-// This should only be called from the main thread. Otherwise it would need
-// the lock and should use mCurrentState rather than mDrawingState.
void SurfaceFlinger::logFrameStats() {
mDrawingState.traverse([&](Layer* layer) {
layer->logFrameStats();
@@ -5194,7 +5179,7 @@
}
void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const {
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
DisplayProto* displayProto = layersTraceProto.add_displays();
displayProto->set_id(display->getId().value);
displayProto->set_name(display->getDisplayName());
@@ -5362,8 +5347,10 @@
std::string fps, xDpi, yDpi;
if (const auto activeMode = display->getActiveMode()) {
fps = to_string(activeMode->getFps());
- xDpi = base::StringPrintf("%.2f", activeMode->getDpiX());
- yDpi = base::StringPrintf("%.2f", activeMode->getDpiY());
+
+ const auto dpi = activeMode->getDpi();
+ xDpi = base::StringPrintf("%.2f", dpi.x);
+ yDpi = base::StringPrintf("%.2f", dpi.y);
} else {
fps = "unknown";
xDpi = "unknown";
@@ -5436,7 +5423,7 @@
/*
* Dump flag/property manager state
*/
- mFlagManager->dump(result);
+ mFlagManager.dump(result);
result.append(mTimeStats->miniDump());
result.append("\n");
@@ -5833,7 +5820,7 @@
int64_t startingTime =
(fixedStartingTime) ? fixedStartingTime : systemTime();
mScheduler
- ->schedule([&]() MAIN_THREAD {
+ ->schedule([&]() FTL_FAKE_GUARD(mStateLock) {
mLayerTracing.notify("start", startingTime);
})
.wait();
@@ -5946,10 +5933,12 @@
switch (n = data.readInt32()) {
case 0:
case 1:
- ON_MAIN_THREAD(enableRefreshRateOverlay(static_cast<bool>(n)));
+ FTL_FAKE_GUARD(mStateLock,
+ enableRefreshRateOverlay(static_cast<bool>(n)));
break;
default: {
- reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled()));
+ reply->writeBool(
+ FTL_FAKE_GUARD(mStateLock, isRefreshRateOverlayEnabled()));
}
}
});
@@ -5987,7 +5976,7 @@
return mScheduler
->schedule([this] {
const auto display =
- ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
// This is a little racy, but not in a way that hurts anything. As
// we grab the defaultMode from the display manager policy, we could
@@ -6009,7 +5998,7 @@
return mScheduler
->schedule([this] {
const auto display =
- ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
constexpr bool kOverridePolicy = true;
return setDesiredDisplayModeSpecsInternal(display, {},
kOverridePolicy);
@@ -6123,9 +6112,9 @@
if (!updateOverlay) return;
// Update the overlay on the main thread to avoid race conditions with
- // mRefreshRateConfigs->getCurrentRefreshRate()
+ // mRefreshRateConfigs->getActiveMode()
static_cast<void>(mScheduler->schedule([=] {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
if (!display) {
ALOGW("%s: default display is null", __func__);
return;
@@ -6499,19 +6488,6 @@
// and failed if display is not in native mode. This provide a way to force using native
// colors when capture.
dataspace = args.dataspace;
- if (dataspace == ui::Dataspace::UNKNOWN) {
- auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
- return display.getLayerStack() == layerStack;
- });
- if (!display) {
- // If the layer is not on a display, use the dataspace for the default display.
- display = getDefaultDisplayDeviceLocked();
- }
-
- const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
- dataspace = pickDataspaceFromColorMode(colorMode);
- }
-
} // mStateLock
// really small crop or frameScale
@@ -6640,7 +6616,7 @@
renderArea->render([&] {
renderEngineResultFuture =
- renderScreenImplLocked(*renderArea, traverseLayers, buffer,
+ renderScreenImpl(*renderArea, traverseLayers, buffer,
canCaptureBlackoutContent, regionSampling, grayscale,
captureResults);
});
@@ -6673,7 +6649,7 @@
}
}
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScreenImplLocked(
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScreenImpl(
const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer,
bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
@@ -6697,7 +6673,22 @@
}
captureResults.buffer = buffer->getBuffer();
- captureResults.capturedDataspace = renderArea.getReqDataSpace();
+ auto dataspace = renderArea.getReqDataSpace();
+ auto parent = renderArea.getParentLayer();
+ if ((dataspace == ui::Dataspace::UNKNOWN) && (parent != nullptr)) {
+ Mutex::Autolock lock(mStateLock);
+ auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
+ return display.getLayerStack() == layerStack;
+ });
+ if (!display) {
+ // If the layer is not on a display, use the dataspace for the default display.
+ display = getDefaultDisplayDeviceLocked();
+ }
+
+ const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
+ dataspace = pickDataspaceFromColorMode(colorMode);
+ }
+ captureResults.capturedDataspace = dataspace;
const auto reqWidth = renderArea.getReqWidth();
const auto reqHeight = renderArea.getReqHeight();
@@ -6715,7 +6706,7 @@
clientCompositionDisplay.clip = sourceCrop;
clientCompositionDisplay.orientation = rotation;
- clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
+ clientCompositionDisplay.outputDataspace = dataspace;
clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
const float colorSaturation = grayscale ? 0 : 1;
@@ -6921,7 +6912,7 @@
}
auto future = mScheduler->schedule([=]() -> status_t {
- const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
if (!display) {
ALOGE("Attempt to set desired display modes for invalid display token %p",
displayToken.get());
@@ -7166,8 +7157,8 @@
if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) {
refreshRate = *frameRateOverride;
} else if (!getHwComposer().isHeadless()) {
- if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) {
- refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) {
+ refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index fa65803..97b0e8d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -56,6 +56,7 @@
#include "DisplayHardware/PowerAdvisor.h"
#include "DisplayIdGenerator.h"
#include "Effects/Daltonizer.h"
+#include "FlagManager.h"
#include "FrameTracker.h"
#include "LayerVector.h"
#include "Scheduler/RefreshRateConfigs.h"
@@ -63,6 +64,7 @@
#include "Scheduler/Scheduler.h"
#include "Scheduler/VsyncModulator.h"
#include "SurfaceFlingerFactory.h"
+#include "ThreadContext.h"
#include "TracedOrdinal.h"
#include "Tracing/LayerTracing.h"
#include "Tracing/TransactionTracing.h"
@@ -182,11 +184,6 @@
std::atomic<nsecs_t> mLastSwapTime = 0;
};
-struct SCOPED_CAPABILITY UnnecessaryLock {
- explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
- ~UnnecessaryLock() RELEASE() {}
-};
-
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
private IBinder::DeathRecipient,
@@ -256,8 +253,6 @@
// found on devices with wide color gamut (e.g. Display-P3) display.
static bool hasWideColorDisplay;
- static ui::Rotation internalDisplayOrientation;
-
// Indicate if device wants color management on its display.
static const constexpr bool useColorManagement = true;
@@ -288,10 +283,13 @@
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 };
+
// Schedule commit of transactions on the main thread ahead of the next VSYNC.
void scheduleCommit(FrameHint);
// As above, but also force composite regardless if transactions were committed.
- void scheduleComposite(FrameHint) override;
+ void scheduleComposite(FrameHint);
// As above, but also force dirty geometry to repaint.
void scheduleRepaint();
// Schedule sampling independently from commit or composite.
@@ -375,6 +373,7 @@
friend class MonitoredProducer;
friend class RefreshRateOverlay;
friend class RegionSamplingThread;
+ friend class LayerRenderArea;
friend class LayerTracing;
// For unit tests
@@ -679,8 +678,8 @@
// Toggles hardware VSYNC by calling into HWC.
void setVsyncEnabled(bool) override;
- // Initiates a refresh rate change to be applied on commit.
- void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override;
+ // Sets the desired display mode if allowed by policy.
+ void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override;
// Called when kernel idle timer has expired. Used to update the refresh rate overlay.
void kernelTimerChanged(bool expired) override;
// Called when the frame rate override list changed to trigger an event.
@@ -737,7 +736,7 @@
void updateLayerGeometry();
void updateInputFlinger();
- void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
+ void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
std::vector<gui::DisplayInfo>& outDisplayInfos);
void commitInputWindowCommands() REQUIRES(mStateLock);
@@ -771,27 +770,27 @@
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);
+
uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&,
int64_t desiredPresentTime, bool isAutoTimestamp,
int64_t postTime, uint32_t permissions) REQUIRES(mStateLock);
uint32_t getTransactionFlags() const;
- // Sets the masked bits, and returns the old flags.
- uint32_t setTransactionFlags(uint32_t mask);
+ // Sets the masked bits, and schedules a commit if needed.
+ void setTransactionFlags(uint32_t mask, TransactionSchedule = TransactionSchedule::Late,
+ const sp<IBinder>& applyToken = nullptr);
// Clears and returns the masked bits.
uint32_t clearTransactionFlags(uint32_t mask);
- // Indicate SF should call doTraversal on layers, but don't trigger a wakeup! We use this cases
- // where there are still pending transactions but we know they won't be ready until a frame
- // arrives from a different layer. So we need to ensure we performTransaction from invalidate
- // but there is no need to try and wake up immediately to do it. Rather we rely on
- // onFrameAvailable or another layer update to wake us up.
- void setTraversalNeeded();
- uint32_t setTransactionFlags(uint32_t mask, TransactionSchedule,
- const sp<IBinder>& applyToken = {});
void commitOffscreenLayers();
+
enum class TransactionReadiness {
NotReady,
NotReadyBarrier,
@@ -863,10 +862,10 @@
RenderAreaFuture, TraverseLayersFunction,
const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
bool grayscale, const sp<IScreenCaptureListener>&);
- std::shared_future<renderengine::RenderEngineResult> renderScreenImplLocked(
+ std::shared_future<renderengine::RenderEngineResult> renderScreenImpl(
const RenderArea&, TraverseLayersFunction,
const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
- bool regionSampling, bool grayscale, ScreenCaptureResults&);
+ bool regionSampling, bool grayscale, ScreenCaptureResults&) EXCLUDES(mStateLock);
// If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a
// matching ownerUid
@@ -970,13 +969,14 @@
void setCompositorTimingSnapped(const DisplayStatInfo& stats,
nsecs_t compositeToPresentLatency);
- void postFrame();
+ void postFrame() REQUIRES(kMainThreadContext);
/*
* Display management
*/
- void loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes,
- DisplayModePtr& outActiveMode) const REQUIRES(mStateLock);
+ std::pair<DisplayModes, DisplayModePtr> loadDisplayModes(PhysicalDisplayId) const
+ REQUIRES(mStateLock);
+
sp<DisplayDevice> setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay,
@@ -1084,7 +1084,7 @@
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();
+ void logFrameStats() REQUIRES(kMainThreadContext);
void dumpVSync(std::string& result) const REQUIRES(mStateLock);
void dumpStaticScreenStats(std::string& result) const;
@@ -1145,6 +1145,9 @@
bool isHdrLayer(Layer* layer) const;
+ ui::Rotation getPhysicalDisplayOrientation(DisplayId, bool isPrimary) const
+ REQUIRES(mStateLock);
+
sp<StartPropertySetThread> mStartPropertySetThread;
surfaceflinger::Factory& mFactory;
pid_t mPid;
@@ -1412,7 +1415,7 @@
const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
- std::unique_ptr<FlagManager> mFlagManager;
+ FlagManager mFlagManager;
// returns the framerate of the layer with the given sequence ID
float getLayerFramerate(nsecs_t now, int32_t id) const {
@@ -1424,7 +1427,7 @@
nsecs_t commitStart;
nsecs_t compositeStart;
nsecs_t presentEnd;
- } mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD);
+ } mPowerHintSessionData GUARDED_BY(kMainThreadContext);
nsecs_t mAnimationTransactionTimeout = s2ns(5);
diff --git a/services/surfaceflinger/ThreadContext.h b/services/surfaceflinger/ThreadContext.h
new file mode 100644
index 0000000..85c379d
--- /dev/null
+++ b/services/surfaceflinger/ThreadContext.h
@@ -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.
+ */
+
+#pragma once
+
+namespace android {
+
+// Enforces exclusive access by the main thread.
+constexpr class [[clang::capability("mutex")]] {
+} kMainThreadContext;
+
+} // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index afc1abd..f25043c 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -29,9 +29,6 @@
LatchUnsignaledConfig::Disabled,
};
-static constexpr ui::Rotation kRotations[] = {ui::Rotation::Rotation0, ui::Rotation::Rotation90,
- ui::Rotation::Rotation180, ui::Rotation::Rotation270};
-
static constexpr BnSurfaceComposer::ISurfaceComposerTag kSurfaceComposerTags[]{
BnSurfaceComposer::BOOT_FINISHED,
BnSurfaceComposer::CREATE_CONNECTION,
@@ -134,7 +131,6 @@
mFlinger->maxGraphicsWidth = mFdp.ConsumeIntegral<uint32_t>();
mFlinger->maxGraphicsHeight = mFdp.ConsumeIntegral<uint32_t>();
mFlinger->hasWideColorDisplay = mFdp.ConsumeBool();
- mFlinger->internalDisplayOrientation = mFdp.PickValueInArray(kRotations);
mFlinger->useContextPriority = mFdp.ConsumeBool();
mFlinger->defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces);
@@ -144,10 +140,8 @@
mFlinger->enableLatchUnsignaledConfig = mFdp.PickValueInArray(kLatchUnsignaledConfig);
- mFlinger->scheduleComposite(mFdp.ConsumeBool()
- ? scheduler::ISchedulerCallback::FrameHint::kActive
- : scheduler::ISchedulerCallback::FrameHint::kNone);
-
+ using FrameHint = SurfaceFlinger::FrameHint;
+ mFlinger->scheduleComposite(mFdp.ConsumeBool() ? FrameHint::kActive : FrameHint::kNone);
mFlinger->scheduleRepaint();
mFlinger->scheduleSample();
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index b796dfe..a80aca2 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -22,6 +22,7 @@
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <ftl/fake_guard.h>
#include <gui/LayerDebugInfo.h>
#include <gui/ScreenCaptureResults.h>
#include <gui/SurfaceComposerClient.h>
@@ -50,11 +51,13 @@
#include "SurfaceFlinger.h"
#include "SurfaceFlingerDefaultFactory.h"
#include "SurfaceInterceptor.h"
+#include "ThreadContext.h"
#include "TimeStats/TimeStats.h"
#include "renderengine/mock/RenderEngine.h"
#include "scheduler/TimeKeeper.h"
#include "tests/unittests/mock/DisplayHardware/MockComposer.h"
+#include "tests/unittests/mock/DisplayHardware/MockDisplayMode.h"
#include "tests/unittests/mock/DisplayHardware/MockHWC2.h"
#include "tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h"
#include "tests/unittests/mock/MockEventThread.h"
@@ -207,7 +210,9 @@
void setRefreshRateFps(Fps) override {}
void dump(std::string &) const override {}
};
+
namespace scheduler {
+
class TestableScheduler : public Scheduler, private ICompositor {
public:
TestableScheduler(const std::shared_ptr<scheduler::RefreshRateConfigs> &refreshRateConfigs,
@@ -216,9 +221,6 @@
std::make_unique<android::mock::VSyncTracker>(), refreshRateConfigs,
callback) {}
- void scheduleFrame(){};
- void postMessage(sp<MessageHandler> &&){};
-
TestableScheduler(std::unique_ptr<VsyncController> controller,
std::unique_ptr<VSyncTracker> tracker,
std::shared_ptr<RefreshRateConfigs> configs, ISchedulerCallback &callback)
@@ -273,8 +275,13 @@
bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
void composite(nsecs_t, int64_t) override {}
void sample() override {}
+
+ // MessageQueue overrides:
+ void scheduleFrame() override {}
+ void postMessage(sp<MessageHandler>&&) override {}
};
-}; // namespace scheduler
+
+} // namespace scheduler
namespace surfaceflinger::test {
@@ -405,8 +412,6 @@
return mFlinger->onInitializeDisplays();
}
- void scheduleComposite(FrameHint){};
-
void setGlobalShadowSettings(FuzzedDataProvider *fdp) {
const half4 ambientColor{fdp->ConsumeFloatingPoint<float>(),
fdp->ConsumeFloatingPoint<float>(),
@@ -442,7 +447,7 @@
mFlinger->clearStatsLocked(dumpArgs, result);
mFlinger->dumpTimeStats(dumpArgs, fdp->ConsumeBool(), result);
- mFlinger->logFrameStats();
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger->logFrameStats());
result = fdp->ConsumeRandomLengthString().c_str();
mFlinger->dumpFrameTimeline(dumpArgs, result);
@@ -648,7 +653,7 @@
updateCompositorTiming(&mFdp);
mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral<nsecs_t>());
- mFlinger->postFrame();
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame());
mFlinger->calculateExpectedPresentTime({});
mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
@@ -678,31 +683,22 @@
std::unique_ptr<EventThread> sfEventThread,
scheduler::ISchedulerCallback *callback = nullptr,
bool hasMultipleModes = false) {
- DisplayModes modes{DisplayMode::Builder(0)
- .setId(DisplayModeId(0))
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(16'666'667)
- .setGroup(0)
- .build()};
+ constexpr DisplayModeId kModeId60{0};
+ DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz));
if (hasMultipleModes) {
- modes.emplace_back(DisplayMode::Builder(1)
- .setId(DisplayModeId(1))
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(11'111'111)
- .setGroup(0)
- .build());
+ constexpr DisplayModeId kModeId90{1};
+ modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz));
}
- const auto currMode = DisplayModeId(0);
- mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, currMode);
- const auto currFps = mRefreshRateConfigs->getCurrentRefreshRate().getFps();
- mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps);
+ mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60);
+ const auto fps = mRefreshRateConfigs->getActiveMode()->getFps();
+ mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
mFlinger->mRefreshRateStats =
- std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
- /*powerMode=*/hal::PowerMode::OFF);
+ std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, fps,
+ hal::PowerMode::OFF);
mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
std::move(vsyncTracker), mRefreshRateConfigs,
@@ -765,8 +761,6 @@
return mFlinger->setPowerModeInternal(display, mode);
}
- auto onMessageReceived(int32_t /*what*/) { return 0; }
-
auto &getTransactionQueue() { return mFlinger->mTransactionQueue; }
auto &getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
@@ -818,15 +812,15 @@
}
private:
- void scheduleRefresh(FrameHint) {}
void setVsyncEnabled(bool) override {}
- void changeRefreshRate(const RefreshRate &, DisplayModeEvent) override {}
+ void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override {}
void kernelTimerChanged(bool) override {}
- void triggerOnFrameRateOverridesChanged() {}
+ void triggerOnFrameRateOverridesChanged() override {}
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
scheduler::TestableScheduler *mScheduler = nullptr;
std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
};
+
} // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index d504155..da60a69 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -15,22 +15,31 @@
*
*/
-#include "surfaceflinger_scheduler_fuzzer.h"
+#include <ftl/enum.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <processgroup/sched_policy.h>
+
#include "Scheduler/DispSyncSource.h"
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/VSyncDispatchTimerQueue.h"
#include "Scheduler/VSyncPredictor.h"
#include "Scheduler/VSyncReactor.h"
+
#include "surfaceflinger_fuzzers_utils.h"
+#include "surfaceflinger_scheduler_fuzzer.h"
namespace android::fuzz {
using hardware::graphics::composer::hal::PowerMode;
-static constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode::OFF,
- PowerMode::DOZE_SUSPEND, PowerMode::ON_SUSPEND};
+constexpr nsecs_t kVsyncPeriods[] = {(30_Hz).getPeriodNsecs(), (60_Hz).getPeriodNsecs(),
+ (72_Hz).getPeriodNsecs(), (90_Hz).getPeriodNsecs(),
+ (120_Hz).getPeriodNsecs()};
+
+constexpr auto kLayerVoteTypes = ftl::enum_range<scheduler::RefreshRateConfigs::LayerVoteType>();
+
+constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode::OFF,
+ PowerMode::DOZE_SUSPEND, PowerMode::ON_SUSPEND};
constexpr uint16_t kRandomStringLength = 256;
constexpr std::chrono::duration kSyncPeriod(16ms);
@@ -319,39 +328,42 @@
using RefreshRateConfigs = scheduler::RefreshRateConfigs;
using LayerRequirement = RefreshRateConfigs::LayerRequirement;
using RefreshRateStats = scheduler::RefreshRateStats;
- uint16_t minRefreshRate = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX >> 1);
- uint16_t maxRefreshRate = mFdp.ConsumeIntegralInRange<uint16_t>(minRefreshRate + 1, UINT16_MAX);
- DisplayModeId hwcConfigIndexType = DisplayModeId(mFdp.ConsumeIntegralInRange<uint8_t>(0, 10));
+ const uint16_t minRefreshRate = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX >> 1);
+ const uint16_t maxRefreshRate =
+ mFdp.ConsumeIntegralInRange<uint16_t>(minRefreshRate + 1, UINT16_MAX);
+
+ const DisplayModeId modeId{mFdp.ConsumeIntegralInRange<uint8_t>(0, 10)};
DisplayModes displayModes;
for (uint16_t fps = minRefreshRate; fps < maxRefreshRate; ++fps) {
- constexpr int32_t kGroup = 0;
- const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
- displayModes.push_back(scheduler::createDisplayMode(hwcConfigIndexType, kGroup,
- refreshRate.getPeriodNsecs()));
+ displayModes.try_emplace(modeId,
+ mock::createDisplayMode(modeId,
+ Fps::fromValue(static_cast<float>(fps))));
}
- auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(displayModes, hwcConfigIndexType);
+
+ RefreshRateConfigs refreshRateConfigs(displayModes, modeId);
+
const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
- auto layers = std::vector<LayerRequirement>{
- LayerRequirement{.weight = mFdp.ConsumeFloatingPoint<float>()}};
- refreshRateConfigs->getBestRefreshRate(layers, globalSignals);
+ std::vector<LayerRequirement> layers = {{.weight = mFdp.ConsumeFloatingPoint<float>()}};
+
+ refreshRateConfigs.getBestRefreshRate(layers, globalSignals);
+
layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength);
layers[0].ownerUid = mFdp.ConsumeIntegral<uint16_t>();
layers[0].desiredRefreshRate = Fps::fromValue(mFdp.ConsumeFloatingPoint<float>());
- layers[0].vote = mFdp.PickValueInArray(kLayerVoteTypes);
+ layers[0].vote = mFdp.PickValueInArray(kLayerVoteTypes.values);
auto frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers,
- Fps::fromValue(
- mFdp.ConsumeFloatingPoint<float>()),
- globalSignals);
+ refreshRateConfigs.getFrameRateOverrides(layers,
+ Fps::fromValue(
+ mFdp.ConsumeFloatingPoint<float>()),
+ globalSignals);
- refreshRateConfigs->setDisplayManagerPolicy(
- {hwcConfigIndexType,
+ refreshRateConfigs.setDisplayManagerPolicy(
+ {modeId,
{Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
- refreshRateConfigs->setCurrentModeId(hwcConfigIndexType);
+ refreshRateConfigs.setActiveModeId(modeId);
RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue(
mFdp.ConsumeFloatingPoint<float>()),
@@ -361,13 +373,13 @@
Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
android::mock::TimeStats timeStats;
- std::unique_ptr<RefreshRateStats> refreshRateStats =
- std::make_unique<RefreshRateStats>(timeStats,
- Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
- PowerMode::OFF);
- refreshRateStats->setRefreshRate(
- refreshRateConfigs->getRefreshRateFromModeId(hwcConfigIndexType).getFps());
- refreshRateStats->setPowerMode(mFdp.PickValueInArray(kPowerModes));
+ RefreshRateStats refreshRateStats(timeStats, Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+ PowerMode::OFF);
+
+ const auto fpsOpt = displayModes.get(modeId, [](const auto& mode) { return mode->getFps(); });
+ refreshRateStats.setRefreshRate(*fpsOpt);
+
+ refreshRateStats.setPowerMode(mFdp.PickValueInArray(kPowerModes));
}
void SchedulerFuzzer::process() {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
index 84b3912..1a49ead 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -22,6 +22,8 @@
#pragma once
+#include <scheduler/TimeKeeper.h>
+
#include "Clock.h"
#include "Layer.h"
#include "Scheduler/EventThread.h"
@@ -29,24 +31,9 @@
#include "Scheduler/Scheduler.h"
#include "Scheduler/VSyncTracker.h"
#include "Scheduler/VsyncModulator.h"
-#include "scheduler/TimeKeeper.h"
namespace android::fuzz {
-constexpr int64_t kVsyncPeriods[] = {static_cast<int64_t>(1e9f / 30),
- static_cast<int64_t>(1e9f / 60),
- static_cast<int64_t>(1e9f / 72),
- static_cast<int64_t>(1e9f / 90),
- static_cast<int64_t>(1e9f / 120)};
-
-android::scheduler::RefreshRateConfigs::LayerVoteType kLayerVoteTypes[] =
- {android::scheduler::RefreshRateConfigs::LayerVoteType::NoVote,
- android::scheduler::RefreshRateConfigs::LayerVoteType::Min,
- android::scheduler::RefreshRateConfigs::LayerVoteType::Max,
- android::scheduler::RefreshRateConfigs::LayerVoteType::Heuristic,
- android::scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault,
- android::scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple};
-
class FuzzImplClock : public android::scheduler::Clock {
public:
nsecs_t now() const { return 1; }
@@ -168,18 +155,6 @@
namespace android::scheduler {
-DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
- ui::Size resolution = ui::Size()) {
- return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
- .setId(modeId)
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(int32_t(vsyncPeriod))
- .setGroup(group)
- .setHeight(resolution.height)
- .setWidth(resolution.width)
- .build();
-}
-
class ControllableClock : public TimeKeeper {
public:
nsecs_t now() const { return 1; };
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 1669075..15c9d19 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -244,8 +244,8 @@
HAL_PIXEL_FORMAT_RGBA_8888, 1,
usage);
- auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
- forSystem, regionSampling);
+ auto result = mFlinger.renderScreenImpl(*renderArea, traverseLayers, mCaptureScreenBuffer,
+ forSystem, regionSampling);
EXPECT_TRUE(result.valid());
auto& [status, drawFence] = result.get();
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
index 40a9b1a..93af225 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
@@ -44,68 +44,42 @@
mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
- .setDisplayModes({kDisplayMode60, kDisplayMode90, kDisplayMode120},
- kDisplayModeId60)
+ .setDisplayModes(makeModes(kMode60, kMode90, kMode120), kModeId60)
.inject();
}
protected:
sp<DisplayDevice> mDisplay;
- const DisplayModeId kDisplayModeId60 = DisplayModeId(0);
- const DisplayModePtr kDisplayMode60 =
- DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value()))
- .setId(kDisplayModeId60)
- .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
- .setVsyncPeriod(int32_t(16'666'667))
- .setGroup(0)
- .setHeight(1000)
- .setWidth(1000)
- .build();
+ static constexpr DisplayModeId kModeId60{0};
+ static constexpr DisplayModeId kModeId90{1};
+ static constexpr DisplayModeId kModeId120{2};
- const DisplayModeId kDisplayModeId90 = DisplayModeId(1);
- const DisplayModePtr kDisplayMode90 =
- DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value()))
- .setId(kDisplayModeId90)
- .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
- .setVsyncPeriod(int32_t(11'111'111))
- .setGroup(0)
- .setHeight(1000)
- .setWidth(1000)
- .build();
-
- const DisplayModeId kDisplayModeId120 = DisplayModeId(2);
- const DisplayModePtr kDisplayMode120 =
- DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value()))
- .setId(kDisplayModeId120)
- .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
- .setVsyncPeriod(int32_t(8'333'333))
- .setGroup(0)
- .setHeight(1000)
- .setWidth(1000)
- .build();
+ static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz);
+ static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz);
+ static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz);
};
TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) {
- EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode60, Event::None}));
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode60, Event::None}));
EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
}
TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) {
- EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
// Setting another mode should be cached but return false
- EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None}));
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode120, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(kMode120, mDisplay->getDesiredActiveMode()->mode);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
}
TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) {
- EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
mDisplay->clearDesiredActiveModeState();
@@ -113,9 +87,9 @@
}
TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS {
- EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
hal::VsyncPeriodChangeConstraints constraints{
@@ -126,7 +100,7 @@
EXPECT_EQ(OK,
mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
&timeline));
- EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode);
EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
mDisplay->clearDesiredActiveModeState();
@@ -135,9 +109,9 @@
TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged)
NO_THREAD_SAFETY_ANALYSIS {
- EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
hal::VsyncPeriodChangeConstraints constraints{
@@ -148,21 +122,21 @@
EXPECT_EQ(OK,
mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
&timeline));
- EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode);
EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
- EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None}));
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode120, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(kMode120, mDisplay->getDesiredActiveMode()->mode);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
- EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode);
EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
EXPECT_EQ(OK,
mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
&timeline));
- EXPECT_EQ(kDisplayMode120, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(kMode120, mDisplay->getUpcomingActiveMode().mode);
EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
mDisplay->clearDesiredActiveModeState();
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
index 73c60e1..225ad16 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
@@ -19,6 +19,7 @@
#include "DisplayTransactionTestHelpers.h"
+#include <ftl/fake_guard.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -35,7 +36,7 @@
};
TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) {
- MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ ftl::FakeGuard guard(kMainThreadContext);
sp<DisplayDevice> displayDevice = getDisplayDevice();
EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
@@ -52,7 +53,7 @@
}
TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) {
- MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ ftl::FakeGuard guard(kMainThreadContext);
sp<DisplayDevice> displayDevice = getDisplayDevice();
EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
@@ -70,7 +71,7 @@
}
TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) {
- MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ ftl::FakeGuard guard(kMainThreadContext);
sp<DisplayDevice> displayDevice = getDisplayDevice();
EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 54b8bcb..565c244 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -45,6 +45,7 @@
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockDisplayMode.h"
#include "mock/DisplayHardware/MockPowerAdvisor.h"
#include "mock/MockEventThread.h"
#include "mock/MockNativeWindowSurface.h"
@@ -235,9 +236,9 @@
using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>;
- // The display width and height
static constexpr int WIDTH = width;
static constexpr int HEIGHT = height;
+ static constexpr ui::Size RESOLUTION{WIDTH, HEIGHT};
static constexpr int GRALLOC_USAGE = grallocUsage;
@@ -262,7 +263,7 @@
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
ceDisplayArgs.setId(DISPLAY_ID::get())
- .setPixels({WIDTH, HEIGHT})
+ .setPixels(RESOLUTION)
.setPowerAdvisor(&test->mPowerAdvisor);
auto compositionDisplay =
@@ -357,8 +358,7 @@
TestableSurfaceFlinger::FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE,
static_cast<bool>(DisplayVariant::PRIMARY))
.setHwcDisplayId(HWC_DISPLAY_ID)
- .setWidth(DisplayVariant::WIDTH)
- .setHeight(DisplayVariant::HEIGHT)
+ .setResolution(DisplayVariant::RESOLUTION)
.setActiveConfig(HWC_ACTIVE_CONFIG_ID)
.setPowerMode(INIT_POWER_MODE)
.inject(&test->mFlinger, test->mComposer);
@@ -381,7 +381,7 @@
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(DisplayVariant::DISPLAY_ID::get())
- .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT})
+ .setPixels(DisplayVariant::RESOLUTION)
.setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
.setPowerAdvisor(&test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
@@ -541,7 +541,7 @@
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(Base::DISPLAY_ID::get())
- .setPixels({Base::WIDTH, Base::HEIGHT})
+ .setPixels(Base::RESOLUTION)
.setIsSecure(static_cast<bool>(Base::SECURE))
.setPowerAdvisor(&test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
@@ -593,7 +593,7 @@
const auto displayId = Base::DISPLAY_ID::get();
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(displayId)
- .setPixels({Base::WIDTH, Base::HEIGHT})
+ .setPixels(Base::RESOLUTION)
.setIsSecure(static_cast<bool>(Base::SECURE))
.setPowerAdvisor(&test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
@@ -736,6 +736,12 @@
HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
+inline DisplayModePtr createDisplayMode(DisplayModeId modeId, Fps refreshRate, int32_t group = 0,
+ ui::Size resolution = ui::Size(1920, 1080)) {
+ return mock::createDisplayMode(modeId, refreshRate, group, resolution,
+ PrimaryDisplayVariant::DISPLAY_ID::get());
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 834a560..f1efa92 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -66,9 +66,10 @@
}
void SetUp() override {
+ constexpr bool kUseBootTimeClock = true;
mTimeStats = std::make_shared<mock::TimeStats>();
mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid,
- kTestThresholds);
+ kTestThresholds, !kUseBootTimeClock);
mFrameTimeline->registerDataSource();
mTokenManager = &mFrameTimeline->mTokenManager;
mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index e108bea..17511cd 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -31,6 +31,7 @@
#include "Scheduler/LayerInfo.h"
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockDisplayMode.h"
#include "mock/MockLayer.h"
#include "mock/MockSchedulerCallback.h"
@@ -42,6 +43,8 @@
using MockLayer = android::mock::MockLayer;
+using android::mock::createDisplayMode;
+
class LayerHistoryTest : public testing::Test {
protected:
static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::HISTORY_SIZE;
@@ -122,22 +125,12 @@
ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate);
}
- std::shared_ptr<RefreshRateConfigs> mConfigs = std::make_shared<
- RefreshRateConfigs>(DisplayModes{DisplayMode::Builder(0)
- .setId(DisplayModeId(0))
- .setPhysicalDisplayId(
- PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
- .setGroup(0)
- .build(),
- DisplayMode::Builder(1)
- .setId(DisplayModeId(1))
- .setPhysicalDisplayId(
- PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
- .setGroup(0)
- .build()},
- DisplayModeId(0));
+ std::shared_ptr<RefreshRateConfigs> mConfigs =
+ std::make_shared<RefreshRateConfigs>(makeModes(createDisplayMode(DisplayModeId(0),
+ LO_FPS),
+ createDisplayMode(DisplayModeId(1),
+ HI_FPS)),
+ DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 97f3747..fcde532 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -25,46 +25,33 @@
#include "DisplayHardware/HWC2.h"
#include "FpsOps.h"
#include "Scheduler/RefreshRateConfigs.h"
+#include "mock/DisplayHardware/MockDisplayMode.h"
using namespace std::chrono_literals;
namespace android::scheduler {
-namespace {
-
-DisplayModePtr createDisplayMode(DisplayModeId modeId, Fps refreshRate, int32_t group = 0,
- ui::Size resolution = ui::Size()) {
- return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
- .setId(modeId)
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(static_cast<int32_t>(refreshRate.getPeriodNsecs()))
- .setGroup(group)
- .setHeight(resolution.height)
- .setWidth(resolution.width)
- .build();
-}
-
-} // namespace
namespace hal = android::hardware::graphics::composer::hal;
-using RefreshRate = RefreshRateConfigs::RefreshRate;
using LayerVoteType = RefreshRateConfigs::LayerVoteType;
using LayerRequirement = RefreshRateConfigs::LayerRequirement;
+using mock::createDisplayMode;
+
struct TestableRefreshRateConfigs : RefreshRateConfigs {
using RefreshRateConfigs::RefreshRateConfigs;
- RefreshRate getMinSupportedRefreshRate() const {
+ DisplayModePtr getMinSupportedRefreshRate() const {
std::lock_guard lock(mLock);
- return *mMinSupportedRefreshRate;
+ return mMinRefreshRateModeIt->second;
}
- RefreshRate getMaxSupportedRefreshRate() const {
+ DisplayModePtr getMaxSupportedRefreshRate() const {
std::lock_guard lock(mLock);
- return *mMaxSupportedRefreshRate;
+ return mMaxRefreshRateModeIt->second;
}
- RefreshRate getMinRefreshRateByPolicy() const {
+ DisplayModePtr getMinRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
return getMinRefreshRateByPolicyLocked();
}
@@ -79,8 +66,8 @@
return RefreshRateConfigs::getBestRefreshRate(layers, signals);
}
- RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>& layers = {},
- GlobalSignals signals = {}) const {
+ DisplayModePtr getBestRefreshRate(const std::vector<LayerRequirement>& layers = {},
+ GlobalSignals signals = {}) const {
return getBestRefreshRateAndSignals(layers, signals).first;
}
};
@@ -90,10 +77,6 @@
RefreshRateConfigsTest();
~RefreshRateConfigsTest();
- static RefreshRate asRefreshRate(DisplayModePtr displayMode) {
- return {displayMode, RefreshRate::ConstructorTag(0)};
- }
-
static constexpr DisplayModeId kModeId60{0};
static constexpr DisplayModeId kModeId90{1};
static constexpr DisplayModeId kModeId72{2};
@@ -126,30 +109,30 @@
static inline const DisplayModePtr kMode24Frac = createDisplayMode(kModeId24Frac, 23.976_Hz);
// Test configurations.
- static inline const DisplayModes kModes_60 = {kMode60};
- static inline const DisplayModes kModes_60_90 = {kMode60, kMode90};
- static inline const DisplayModes kModes_60_90_G1 = {kMode60, kMode90_G1};
- static inline const DisplayModes kModes_60_90_4K = {kMode60, kMode90_4K};
- static inline const DisplayModes kModes_60_72_90 = {kMode60, kMode90, kMode72};
- static inline const DisplayModes kModes_60_90_72_120 = {kMode60, kMode90, kMode72, kMode120};
- static inline const DisplayModes kModes_30_60_72_90_120 = {kMode60, kMode90, kMode72, kMode120,
- kMode30};
+ static inline const DisplayModes kModes_60 = makeModes(kMode60);
+ static inline const DisplayModes kModes_60_90 = makeModes(kMode60, kMode90);
+ static inline const DisplayModes kModes_60_90_G1 = makeModes(kMode60, kMode90_G1);
+ static inline const DisplayModes kModes_60_90_4K = makeModes(kMode60, kMode90_4K);
+ static inline const DisplayModes kModes_60_72_90 = makeModes(kMode60, kMode90, kMode72);
+ static inline const DisplayModes kModes_60_90_72_120 =
+ makeModes(kMode60, kMode90, kMode72, kMode120);
+ static inline const DisplayModes kModes_30_60_72_90_120 =
+ makeModes(kMode60, kMode90, kMode72, kMode120, kMode30);
- static inline const DisplayModes kModes_30_60 = {kMode60, kMode90_G1, kMode72_G1, kMode120_G1,
- kMode30};
- static inline const DisplayModes kModes_30_60_72_90 = {kMode60, kMode90, kMode72, kMode120_G1,
- kMode30};
- static inline const DisplayModes kModes_30_60_90 = {kMode60, kMode90, kMode72_G1, kMode120_G1,
- kMode30};
- static inline const DisplayModes kModes_25_30_50_60 = {kMode60, kMode90, kMode72_G1,
- kMode120_G1, kMode30_G1, kMode25_G1,
- kMode50};
- static inline const DisplayModes kModes_60_120 = {kMode60, kMode120};
+ static inline const DisplayModes kModes_30_60 =
+ makeModes(kMode60, kMode90_G1, kMode72_G1, kMode120_G1, kMode30);
+ static inline const DisplayModes kModes_30_60_72_90 =
+ makeModes(kMode60, kMode90, kMode72, kMode120_G1, kMode30);
+ static inline const DisplayModes kModes_30_60_90 =
+ makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30);
+ static inline const DisplayModes kModes_25_30_50_60 =
+ makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30_G1, kMode25_G1, kMode50);
+ static inline const DisplayModes kModes_60_120 = makeModes(kMode60, kMode120);
// This is a typical TV configuration.
- static inline const DisplayModes kModes_24_25_30_50_60_Frac = {kMode24, kMode24Frac, kMode25,
- kMode30, kMode30Frac, kMode50,
- kMode60, kMode60Frac};
+ static inline const DisplayModes kModes_24_25_30_50_60_Frac =
+ makeModes(kMode24, kMode24Frac, kMode25, kMode30, kMode30Frac, kMode50, kMode60,
+ kMode60Frac);
};
RefreshRateConfigsTest::RefreshRateConfigsTest() {
@@ -183,8 +166,8 @@
const auto minRate = configs.getMinSupportedRefreshRate();
const auto performanceRate = configs.getMaxSupportedRefreshRate();
- EXPECT_EQ(asRefreshRate(kMode60), minRate);
- EXPECT_EQ(asRefreshRate(kMode90), performanceRate);
+ EXPECT_EQ(kMode60, minRate);
+ EXPECT_EQ(kMode90, performanceRate);
const auto minRateByPolicy = configs.getMinRefreshRateByPolicy();
const auto performanceRateByPolicy = configs.getMaxRefreshRateByPolicy();
@@ -201,19 +184,19 @@
const auto minRate60 = configs.getMinRefreshRateByPolicy();
const auto performanceRate60 = configs.getMaxRefreshRateByPolicy();
- EXPECT_EQ(asRefreshRate(kMode60), minRate);
- EXPECT_EQ(asRefreshRate(kMode60), minRate60);
- EXPECT_EQ(asRefreshRate(kMode60), performanceRate60);
+ EXPECT_EQ(kMode60, minRate);
+ EXPECT_EQ(kMode60, minRate60);
+ EXPECT_EQ(kMode60, performanceRate60);
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}), 0);
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
const auto minRate90 = configs.getMinRefreshRateByPolicy();
const auto performanceRate90 = configs.getMaxRefreshRateByPolicy();
- EXPECT_EQ(asRefreshRate(kMode90_G1), performanceRate);
- EXPECT_EQ(asRefreshRate(kMode90_G1), minRate90);
- EXPECT_EQ(asRefreshRate(kMode90_G1), performanceRate90);
+ EXPECT_EQ(kMode90_G1, performanceRate);
+ EXPECT_EQ(kMode90_G1, minRate90);
+ EXPECT_EQ(kMode90_G1, performanceRate90);
}
TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap_differentResolutions) {
@@ -224,19 +207,19 @@
const auto minRate60 = configs.getMinRefreshRateByPolicy();
const auto performanceRate60 = configs.getMaxRefreshRateByPolicy();
- EXPECT_EQ(asRefreshRate(kMode60), minRate);
- EXPECT_EQ(asRefreshRate(kMode60), minRate60);
- EXPECT_EQ(asRefreshRate(kMode60), performanceRate60);
+ EXPECT_EQ(kMode60, minRate);
+ EXPECT_EQ(kMode60, minRate60);
+ EXPECT_EQ(kMode60, performanceRate60);
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}), 0);
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
const auto minRate90 = configs.getMinRefreshRateByPolicy();
const auto performanceRate90 = configs.getMaxRefreshRateByPolicy();
- EXPECT_EQ(asRefreshRate(kMode90_4K), performanceRate);
- EXPECT_EQ(asRefreshRate(kMode90_4K), minRate90);
- EXPECT_EQ(asRefreshRate(kMode90_4K), performanceRate90);
+ EXPECT_EQ(kMode90_4K, performanceRate);
+ EXPECT_EQ(kMode90_4K, minRate90);
+ EXPECT_EQ(kMode90_4K, performanceRate90);
}
TEST_F(RefreshRateConfigsTest, twoModes_policyChange) {
@@ -245,35 +228,35 @@
const auto minRate = configs.getMinRefreshRateByPolicy();
const auto performanceRate = configs.getMaxRefreshRateByPolicy();
- EXPECT_EQ(asRefreshRate(kMode60), minRate);
- EXPECT_EQ(asRefreshRate(kMode90), performanceRate);
+ EXPECT_EQ(kMode60, minRate);
+ EXPECT_EQ(kMode90, performanceRate);
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
const auto minRate60 = configs.getMinRefreshRateByPolicy();
const auto performanceRate60 = configs.getMaxRefreshRateByPolicy();
- EXPECT_EQ(asRefreshRate(kMode60), minRate60);
- EXPECT_EQ(asRefreshRate(kMode60), performanceRate60);
+ EXPECT_EQ(kMode60, minRate60);
+ EXPECT_EQ(kMode60, performanceRate60);
}
-TEST_F(RefreshRateConfigsTest, twoModes_getCurrentRefreshRate) {
+TEST_F(RefreshRateConfigsTest, twoModes_getActiveMode) {
TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
{
- const auto current = configs.getCurrentRefreshRate();
- EXPECT_EQ(current.getModeId(), kModeId60);
+ const auto mode = configs.getActiveMode();
+ EXPECT_EQ(mode->getId(), kModeId60);
}
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
{
- const auto current = configs.getCurrentRefreshRate();
- EXPECT_EQ(current.getModeId(), kModeId90);
+ const auto mode = configs.getActiveMode();
+ EXPECT_EQ(mode->getId(), kModeId90);
}
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
{
- const auto current = configs.getCurrentRefreshRate();
- EXPECT_EQ(current.getModeId(), kModeId90);
+ const auto mode = configs.getActiveMode();
+ EXPECT_EQ(mode->getId(), kModeId90);
}
}
@@ -283,10 +266,10 @@
// If there are no layers we select the default frame rate, which is the max of the primary
// range.
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate());
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate());
EXPECT_EQ(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), NO_ERROR);
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate());
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate());
}
{
// We select max even when this will cause a non-seamless switch.
@@ -294,7 +277,7 @@
constexpr bool kAllowGroupSwitching = true;
EXPECT_EQ(configs.setDisplayManagerPolicy({kModeId90, kAllowGroupSwitching, {0_Hz, 90_Hz}}),
NO_ERROR);
- EXPECT_EQ(asRefreshRate(kMode90_G1), configs.getBestRefreshRate());
+ EXPECT_EQ(kMode90_G1, configs.getBestRefreshRate());
}
}
@@ -306,104 +289,104 @@
lr.vote = LayerVoteType::Min;
lr.name = "Min";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 45_Hz;
lr.name = "45Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 30_Hz;
lr.name = "30Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 24_Hz;
lr.name = "24Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.name = "";
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 45_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 24_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 45_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 24_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}}), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 45_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 24_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) {
@@ -414,32 +397,32 @@
lr.vote = LayerVoteType::Min;
lr.name = "Min";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 45_Hz;
lr.name = "45Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 30_Hz;
lr.name = "30Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 24_Hz;
lr.name = "24Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) {
@@ -449,26 +432,26 @@
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 45_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 24_Hz;
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) {
@@ -482,19 +465,19 @@
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 48_Hz;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 48_Hz;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) {
@@ -510,7 +493,7 @@
lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -518,7 +501,7 @@
lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -526,7 +509,7 @@
lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "60Hz ExplicitDefault";
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -534,7 +517,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -542,7 +525,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -550,7 +533,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
@@ -558,7 +541,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -566,7 +549,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -574,7 +557,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_multipleThreshold) {
@@ -591,7 +574,7 @@
lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -599,7 +582,7 @@
lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -607,7 +590,7 @@
lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "60Hz ExplicitDefault";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -615,7 +598,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -623,7 +606,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -631,7 +614,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
@@ -639,7 +622,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -647,7 +630,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -655,7 +638,7 @@
lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
@@ -665,26 +648,26 @@
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 45_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 24_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) {
@@ -695,42 +678,42 @@
lr.vote = LayerVoteType::Min;
lr.name = "Min";
- EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true}));
lr.desiredRefreshRate = 45_Hz;
lr.name = "45Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true}));
lr.desiredRefreshRate = 30_Hz;
lr.name = "30Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true}));
lr.desiredRefreshRate = 24_Hz;
lr.name = "24Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true}));
lr.desiredRefreshRate = 24_Hz;
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
lr.name = "24Hz ExplicitExactOrMultiple";
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) {
@@ -742,39 +725,39 @@
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Max;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 24_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 24_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 15_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 45_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 30_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 45_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) {
@@ -786,9 +769,9 @@
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
lr.desiredRefreshRate = Fps::fromValue(fps);
- const auto refreshRate = configs.getBestRefreshRate(layers);
- EXPECT_EQ(asRefreshRate(kMode60), refreshRate)
- << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
+ const auto mode = configs.getBestRefreshRate(layers);
+ EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses "
+ << to_string(mode->getFps());
}
}
@@ -802,9 +785,9 @@
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
lr.desiredRefreshRate = Fps::fromValue(fps);
- const auto refreshRate = configs.getBestRefreshRate(layers);
- EXPECT_EQ(asRefreshRate(kMode60), refreshRate)
- << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
+ const auto mode = configs.getBestRefreshRate(layers);
+ EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses "
+ << to_string(mode->getFps());
}
}
@@ -819,19 +802,19 @@
lr1.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
@@ -843,9 +826,9 @@
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
lr.desiredRefreshRate = Fps::fromValue(fps);
- const auto refreshRate = configs.getBestRefreshRate(layers, {});
- EXPECT_EQ(asRefreshRate(kMode90), refreshRate)
- << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
+ const auto mode = configs.getBestRefreshRate(layers, {});
+ EXPECT_EQ(kMode90, mode) << lr.desiredRefreshRate << " chooses "
+ << to_string(mode->getFps());
}
}
@@ -862,7 +845,7 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 90_Hz;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60_Hz;
@@ -870,14 +853,14 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.desiredRefreshRate = 90_Hz;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 30_Hz;
@@ -885,14 +868,14 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 90_Hz;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 30_Hz;
lr1.name = "30Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
@@ -907,28 +890,28 @@
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
// The other layer starts to provide buffers
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -937,7 +920,7 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 90_Hz;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, touchConsidered) {
@@ -1023,8 +1006,7 @@
ss << "ExplicitDefault " << desired;
lr.name = ss.str();
- const auto refreshRate = configs.getBestRefreshRate(layers);
- EXPECT_EQ(refreshRate.getFps(), expected);
+ EXPECT_EQ(expected, configs.getBestRefreshRate(layers)->getFps());
}
}
@@ -1035,36 +1017,36 @@
// Test that 23.976 will choose 24 if 23.976 is not supported
{
- TestableRefreshRateConfigs configs({kMode24, kMode25, kMode30, kMode30Frac, kMode60,
- kMode60Frac},
+ TestableRefreshRateConfigs configs(makeModes(kMode24, kMode25, kMode30, kMode30Frac,
+ kMode60, kMode60Frac),
kModeId60);
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
lr.desiredRefreshRate = 23.976_Hz;
lr.name = "ExplicitExactOrMultiple 23.976 Hz";
- EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers)->getId());
}
// Test that 24 will choose 23.976 if 24 is not supported
{
- TestableRefreshRateConfigs configs({kMode24Frac, kMode25, kMode30, kMode30Frac, kMode60,
- kMode60Frac},
+ TestableRefreshRateConfigs configs(makeModes(kMode24Frac, kMode25, kMode30, kMode30Frac,
+ kMode60, kMode60Frac),
kModeId60);
lr.desiredRefreshRate = 24_Hz;
lr.name = "ExplicitExactOrMultiple 24 Hz";
- EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers)->getId());
}
// Test that 29.97 will prefer 59.94 over 60 and 30
{
- TestableRefreshRateConfigs configs({kMode24, kMode24Frac, kMode25, kMode30, kMode60,
- kMode60Frac},
+ TestableRefreshRateConfigs configs(makeModes(kMode24, kMode24Frac, kMode25, kMode30,
+ kMode60, kMode60Frac),
kModeId60);
lr.desiredRefreshRate = 29.97_Hz;
lr.name = "ExplicitExactOrMultiple 29.97 Hz";
- EXPECT_EQ(kModeId60Frac, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId60Frac, configs.getBestRefreshRate(layers)->getId());
}
}
@@ -1083,32 +1065,31 @@
ss << "ExplicitExact " << desired;
lr.name = ss.str();
- auto selectedRefreshRate = configs.getBestRefreshRate(layers);
- EXPECT_EQ(selectedRefreshRate.getFps(), lr.desiredRefreshRate);
+ EXPECT_EQ(lr.desiredRefreshRate, configs.getBestRefreshRate(layers)->getFps());
}
}
// Test that 23.976 will choose 24 if 23.976 is not supported
{
- TestableRefreshRateConfigs configs({kMode24, kMode25, kMode30, kMode30Frac, kMode60,
- kMode60Frac},
+ TestableRefreshRateConfigs configs(makeModes(kMode24, kMode25, kMode30, kMode30Frac,
+ kMode60, kMode60Frac),
kModeId60);
lr.vote = LayerVoteType::ExplicitExact;
lr.desiredRefreshRate = 23.976_Hz;
lr.name = "ExplicitExact 23.976 Hz";
- EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers)->getId());
}
// Test that 24 will choose 23.976 if 24 is not supported
{
- TestableRefreshRateConfigs configs({kMode24Frac, kMode25, kMode30, kMode30Frac, kMode60,
- kMode60Frac},
+ TestableRefreshRateConfigs configs(makeModes(kMode24Frac, kMode25, kMode30, kMode30Frac,
+ kMode60, kMode60Frac),
kModeId60);
lr.desiredRefreshRate = 24_Hz;
lr.name = "ExplicitExact 24 Hz";
- EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers)->getId());
}
}
@@ -1126,10 +1107,9 @@
lr.name = "60Hz ExplicitDefault";
lr.focused = true;
- const auto [refreshRate, signals] =
- configs.getBestRefreshRate(layers, {.touch = true, .idle = true});
+ const auto [mode, signals] = configs.getBestRefreshRate(layers, {.touch = true, .idle = true});
- EXPECT_EQ(refreshRate, asRefreshRate(kMode60));
+ EXPECT_EQ(mode, kMode60);
EXPECT_FALSE(signals.touch);
}
@@ -1146,7 +1126,7 @@
lr.desiredRefreshRate = 90_Hz;
lr.name = "90Hz ExplicitDefault";
lr.focused = true;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.idle = true}));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.idle = true}));
}
TEST_F(RefreshRateConfigsTest,
@@ -1155,8 +1135,8 @@
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
- const auto [refreshRate, signals] = configs.getBestRefreshRateAndSignals({}, {});
- EXPECT_EQ(refreshRate, asRefreshRate(kMode90));
+ const auto [mode, signals] = configs.getBestRefreshRateAndSignals({}, {});
+ EXPECT_EQ(mode, kMode90);
EXPECT_FALSE(signals.touch);
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
@@ -1166,46 +1146,46 @@
lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz ExplicitExactOrMultiple";
lr.focused = false;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.focused = true;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::ExplicitDefault;
lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz ExplicitDefault";
lr.focused = false;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.focused = true;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Heuristic;
lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Heuristic";
lr.focused = false;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.focused = true;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Max;
lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Max";
lr.focused = false;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.focused = true;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.vote = LayerVoteType::Min;
lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Min";
lr.focused = false;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
lr.focused = true;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, groupSwitchingNotAllowed) {
@@ -1221,7 +1201,7 @@
layer.name = "90Hz ExplicitDefault";
layer.focused = true;
- EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) {
@@ -1239,7 +1219,7 @@
layer.seamlessness = Seamlessness::SeamedAndSeamless;
layer.name = "90Hz ExplicitDefault";
layer.focused = true;
- EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) {
@@ -1258,7 +1238,7 @@
layer.seamlessness = Seamlessness::OnlySeamless;
layer.name = "90Hz ExplicitDefault";
layer.focused = true;
- EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) {
@@ -1269,7 +1249,7 @@
policy.allowGroupSwitching = true;
EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
// Verify that we won't do a seamless switch if we request the same mode as the default
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
@@ -1279,7 +1259,7 @@
layer.seamlessness = Seamlessness::OnlySeamless;
layer.name = "60Hz ExplicitDefault";
layer.focused = true;
- EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) {
@@ -1290,7 +1270,7 @@
policy.allowGroupSwitching = true;
EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
// Verify that if the current config is in another group and there are no layers with
// seamlessness=SeamedAndSeamless we'll go back to the default group.
@@ -1303,7 +1283,7 @@
layer.name = "60Hz ExplicitDefault";
layer.focused = true;
- EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) {
@@ -1314,7 +1294,7 @@
policy.allowGroupSwitching = true;
EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
// If there's a layer with seamlessness=SeamedAndSeamless, another layer with
// seamlessness=OnlySeamless can't change the mode group.
@@ -1332,7 +1312,7 @@
layers[1].name = "90Hz ExplicitDefault";
layers[1].focused = false;
- EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) {
@@ -1343,7 +1323,7 @@
policy.allowGroupSwitching = true;
EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
// If there's a focused layer with seamlessness=SeamedAndSeamless, another layer with
// seamlessness=Default can't change the mode group back to the group of the default
@@ -1365,7 +1345,7 @@
layers[1].vote = LayerVoteType::ExplicitDefault;
layers[1].name = "90Hz ExplicitDefault";
- EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) {
@@ -1376,7 +1356,7 @@
policy.allowGroupSwitching = true;
EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
// Layer with seamlessness=Default can change the mode group if there's a not
// focused layer with seamlessness=SeamedAndSeamless. This happens for example,
@@ -1395,7 +1375,7 @@
layers[1].vote = LayerVoteType::ExplicitDefault;
layers[1].name = "90Hz ExplicitDefault";
- EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) {
@@ -1415,10 +1395,10 @@
layer.name = "60Hz ExplicitExactOrMultiple";
layer.focused = true;
- EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId());
- configs.setCurrentModeId(kModeId120);
- EXPECT_EQ(kModeId120, configs.getBestRefreshRate(layers).getModeId());
+ configs.setActiveModeId(kModeId120);
+ EXPECT_EQ(kModeId120, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) {
@@ -1443,14 +1423,14 @@
.weight = 1.f,
.focused = true}};
- EXPECT_EQ(kModeId50, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId50, configs.getBestRefreshRate(layers)->getId());
auto& seamedLayer = layers[0];
seamedLayer.desiredRefreshRate = 30_Hz;
seamedLayer.name = "30Hz ExplicitDefault";
- configs.setCurrentModeId(kModeId30);
+ configs.setActiveModeId(kModeId30);
- EXPECT_EQ(kModeId25, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId25, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, minLayersDontTrigerSeamedSwitch) {
@@ -1465,7 +1445,7 @@
std::vector<LayerRequirement> layers = {
{.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}};
- EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId());
+ EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId());
}
TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
@@ -1485,12 +1465,12 @@
layers[0].vote = voteType;
layers[0].desiredRefreshRate = fps;
layers[0].focused = args.focused;
- return configs.getBestRefreshRate(layers, {.touch = args.touch}).getModeId();
+ return configs.getBestRefreshRate(layers, {.touch = args.touch})->getId();
};
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}), 0);
- EXPECT_EQ(kModeId60, configs.getBestRefreshRate().getModeId());
+ EXPECT_EQ(kModeId60, configs.getBestRefreshRate()->getId());
EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
EXPECT_EQ(kModeId30, getFrameRate(LayerVoteType::Min, 90_Hz));
EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz));
@@ -1537,7 +1517,7 @@
// Refresh rate will be chosen by either touch state or idle state.
EXPECT_EQ(!touchActive, signals.idle);
- return refreshRate.getModeId();
+ return refreshRate->getId();
};
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
@@ -1555,10 +1535,10 @@
}
// With no layers, idle should still be lower priority than touch boost.
- EXPECT_EQ(kModeId90, configs.getBestRefreshRate({}, {.touch = true, .idle = true}).getModeId());
+ EXPECT_EQ(kModeId90, configs.getBestRefreshRate({}, {.touch = true, .idle = true})->getId());
// Idle should be higher precedence than other layer frame rate considerations.
- configs.setCurrentModeId(kModeId90);
+ configs.setActiveModeId(kModeId90);
{
constexpr bool kTouchActive = false;
@@ -1572,7 +1552,7 @@
}
// Idle should be applied rather than the current config when there are no layers.
- EXPECT_EQ(kModeId60, configs.getBestRefreshRate({}, {.idle = true}).getModeId());
+ EXPECT_EQ(kModeId60, configs.getBestRefreshRate({}, {.idle = true})->getId());
}
TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) {
@@ -1598,13 +1578,12 @@
struct Expectation {
Fps fps;
- const RefreshRate& refreshRate;
+ DisplayModePtr mode;
};
const std::initializer_list<Expectation> knownFrameRatesExpectations = {
- {24_Hz, asRefreshRate(kMode60)}, {30_Hz, asRefreshRate(kMode60)},
- {45_Hz, asRefreshRate(kMode90)}, {60_Hz, asRefreshRate(kMode60)},
- {72_Hz, asRefreshRate(kMode90)}, {90_Hz, asRefreshRate(kMode90)},
+ {24_Hz, kMode60}, {30_Hz, kMode60}, {45_Hz, kMode90},
+ {60_Hz, kMode60}, {72_Hz, kMode90}, {90_Hz, kMode90},
};
// Make sure the test tests all the known frame rate
@@ -1620,9 +1599,9 @@
auto& layer = layers[0];
layer.vote = LayerVoteType::Heuristic;
- for (const auto& [fps, refreshRate] : knownFrameRatesExpectations) {
+ for (const auto& [fps, mode] : knownFrameRatesExpectations) {
layer.desiredRefreshRate = fps;
- EXPECT_EQ(refreshRate, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(mode, configs.getBestRefreshRate(layers));
}
}
@@ -1641,21 +1620,21 @@
explicitExactLayer.name = "ExplicitExact";
explicitExactLayer.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers, {.touch = true}));
explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz;
explicitExactLayer.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
explicitExactLayer.desiredRefreshRate = 72_Hz;
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
explicitExactLayer.desiredRefreshRate = 90_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
explicitExactLayer.desiredRefreshRate = 120_Hz;
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) {
@@ -1674,21 +1653,21 @@
explicitExactLayer.name = "ExplicitExact";
explicitExactLayer.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers, {.touch = true}));
explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz;
explicitExactLayer.desiredRefreshRate = 60_Hz;
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
explicitExactLayer.desiredRefreshRate = 72_Hz;
- EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
explicitExactLayer.desiredRefreshRate = 90_Hz;
- EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
explicitExactLayer.desiredRefreshRate = 120_Hz;
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCache) {
@@ -1697,7 +1676,7 @@
using GlobalSignals = RefreshRateConfigs::GlobalSignals;
const auto args = std::make_pair(std::vector<LayerRequirement>{},
GlobalSignals{.touch = true, .idle = true});
- const auto result = std::make_pair(asRefreshRate(kMode90), GlobalSignals{.touch = true});
+ const auto result = std::make_pair(kMode90, GlobalSignals{.touch = true});
configs.mutableGetBestRefreshRateCache() = {args, result};
@@ -1736,13 +1715,13 @@
explicitExactLayer.name = "ExplicitExact";
explicitExactLayer.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers, {.touch = true}));
explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers, {.touch = true}));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers, {.touch = true}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
@@ -1761,7 +1740,7 @@
explicitDefaultLayer.name = "ExplicitDefault";
explicitDefaultLayer.desiredRefreshRate = 59.94_Hz;
- EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers));
+ EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
}
// b/190578904
@@ -1771,17 +1750,20 @@
DisplayModes displayModes;
for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
- displayModes.push_back(
- createDisplayMode(DisplayModeId(fps), Fps::fromValue(static_cast<float>(fps))));
+ const DisplayModeId modeId(fps);
+ displayModes.try_emplace(modeId,
+ createDisplayMode(modeId,
+ Fps::fromValue(static_cast<float>(fps))));
}
- const TestableRefreshRateConfigs configs(displayModes, displayModes[0]->getId());
+ const TestableRefreshRateConfigs configs(std::move(displayModes),
+ DisplayModeId(kMinRefreshRate));
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
layers[0].desiredRefreshRate = fps;
layers[0].vote = vote;
- EXPECT_EQ(fps.getIntValue(), configs.getBestRefreshRate(layers).getFps().getIntValue())
+ EXPECT_EQ(fps.getIntValue(), configs.getBestRefreshRate(layers)->getFps().getIntValue())
<< "Failed for " << ftl::enum_string(vote);
};
@@ -1796,15 +1778,14 @@
// b/190578904
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_conflictingVotes) {
- const DisplayModes displayModes = {
- createDisplayMode(DisplayModeId(0), 43_Hz),
- createDisplayMode(DisplayModeId(1), 53_Hz),
- createDisplayMode(DisplayModeId(2), 55_Hz),
- createDisplayMode(DisplayModeId(3), 60_Hz),
- };
+ constexpr DisplayModeId kActiveModeId{0};
+ DisplayModes displayModes = makeModes(createDisplayMode(kActiveModeId, 43_Hz),
+ createDisplayMode(DisplayModeId(1), 53_Hz),
+ createDisplayMode(DisplayModeId(2), 55_Hz),
+ createDisplayMode(DisplayModeId(3), 60_Hz));
const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
- const TestableRefreshRateConfigs configs(displayModes, displayModes[0]->getId());
+ const TestableRefreshRateConfigs configs(std::move(displayModes), kActiveModeId);
const std::vector<LayerRequirement> layers = {
{
@@ -1821,13 +1802,13 @@
},
};
- EXPECT_EQ(53_Hz, configs.getBestRefreshRate(layers, globalSignals).getFps());
+ EXPECT_EQ(53_Hz, configs.getBestRefreshRate(layers, globalSignals)->getFps());
}
-TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
- EXPECT_TRUE(asRefreshRate(kMode60) < asRefreshRate(kMode90));
- EXPECT_FALSE(asRefreshRate(kMode60) < asRefreshRate(kMode60));
- EXPECT_FALSE(asRefreshRate(kMode90) < asRefreshRate(kMode90));
+TEST_F(RefreshRateConfigsTest, modeComparison) {
+ EXPECT_LT(kMode60->getFps(), kMode90->getFps());
+ EXPECT_GE(kMode60->getFps(), kMode60->getFps());
+ EXPECT_GE(kMode90->getFps(), kMode90->getFps());
}
TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) {
@@ -1877,27 +1858,27 @@
RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30);
const auto frameRate = 30_Hz;
- Fps displayRefreshRate = configs.getCurrentRefreshRate().getFps();
+ Fps displayRefreshRate = configs.getActiveMode()->getFps();
EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
- configs.setCurrentModeId(kModeId60);
- displayRefreshRate = configs.getCurrentRefreshRate().getFps();
+ configs.setActiveModeId(kModeId60);
+ displayRefreshRate = configs.getActiveMode()->getFps();
EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
- configs.setCurrentModeId(kModeId72);
- displayRefreshRate = configs.getCurrentRefreshRate().getFps();
+ configs.setActiveModeId(kModeId72);
+ displayRefreshRate = configs.getActiveMode()->getFps();
EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
- configs.setCurrentModeId(kModeId90);
- displayRefreshRate = configs.getCurrentRefreshRate().getFps();
+ configs.setActiveModeId(kModeId90);
+ displayRefreshRate = configs.getActiveMode()->getFps();
EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
- configs.setCurrentModeId(kModeId120);
- displayRefreshRate = configs.getCurrentRefreshRate().getFps();
+ configs.setActiveModeId(kModeId120);
+ displayRefreshRate = configs.getActiveMode()->getFps();
EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
- configs.setCurrentModeId(kModeId90);
- displayRefreshRate = configs.getCurrentRefreshRate().getFps();
+ configs.setActiveModeId(kModeId90);
+ 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/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index df4a9c4..e2e3d7b 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -21,8 +21,6 @@
#include <log/log.h>
#include <thread>
-#include "DisplayHardware/DisplayMode.h"
-#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
#include "mock/MockTimeStats.h"
@@ -35,29 +33,15 @@
class RefreshRateStatsTest : public testing::Test {
protected:
- static inline const auto CONFIG_ID_0 = DisplayModeId(0);
- static inline const auto CONFIG_ID_1 = DisplayModeId(1);
- static inline const auto CONFIG_GROUP_0 = 0;
- static constexpr int64_t VSYNC_90 = 11111111;
- static constexpr int64_t VSYNC_60 = 16666667;
-
RefreshRateStatsTest();
~RefreshRateStatsTest();
- void init(const DisplayModes& configs) {
- mRefreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
-
- const auto currFps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
- mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, currFps,
- /*currentPowerMode=*/PowerMode::OFF);
+ void resetStats(Fps fps) {
+ mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, fps, PowerMode::OFF);
}
mock::TimeStats mTimeStats;
- std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
std::unique_ptr<RefreshRateStats> mRefreshRateStats;
-
- DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod);
};
RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -72,20 +56,10 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
-DisplayModePtr RefreshRateStatsTest::createDisplayMode(DisplayModeId modeId, int32_t group,
- int64_t vsyncPeriod) {
- return DisplayMode::Builder(static_cast<hal::HWConfigId>(modeId.value()))
- .setId(modeId)
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
- .setGroup(group)
- .build();
-}
-
namespace {
-TEST_F(RefreshRateStatsTest, oneConfigTest) {
- init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
+TEST_F(RefreshRateStatsTest, oneMode) {
+ resetStats(90_Hz);
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
@@ -102,8 +76,7 @@
EXPECT_LT(screenOff, times.get("ScreenOff")->get());
EXPECT_FALSE(times.contains("90.00 Hz"));
- const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
- mRefreshRateStats->setRefreshRate(config0Fps);
+ mRefreshRateStats->setRefreshRate(90_Hz);
mRefreshRateStats->setPowerMode(PowerMode::ON);
screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
@@ -121,20 +94,18 @@
EXPECT_LT(screenOff, times.get("ScreenOff")->get());
EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
- mRefreshRateStats->setRefreshRate(config0Fps);
+ mRefreshRateStats->setRefreshRate(90_Hz);
screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- // Because the power mode is not PowerMode::ON, switching the config
- // does not update refresh rates that come from the config.
+ // Stats are not updated while the screen is off.
EXPECT_LT(screenOff, times.get("ScreenOff")->get());
EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
}
-TEST_F(RefreshRateStatsTest, twoConfigsTest) {
- init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90),
- createDisplayMode(CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60)});
+TEST_F(RefreshRateStatsTest, twoModes) {
+ resetStats(90_Hz);
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
@@ -153,9 +124,7 @@
EXPECT_FALSE(times.contains("60.00 Hz"));
EXPECT_FALSE(times.contains("90.00 Hz"));
- const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
- const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_1).getFps();
- mRefreshRateStats->setRefreshRate(config0Fps);
+ mRefreshRateStats->setRefreshRate(90_Hz);
mRefreshRateStats->setPowerMode(PowerMode::ON);
screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
@@ -165,8 +134,7 @@
ASSERT_TRUE(times.contains("90.00 Hz"));
EXPECT_LT(0ms, times.get("90.00 Hz")->get());
- // When power mode is normal, time for configs updates.
- mRefreshRateStats->setRefreshRate(config1Fps);
+ mRefreshRateStats->setRefreshRate(60_Hz);
auto ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -176,7 +144,7 @@
ASSERT_TRUE(times.contains("60.00 Hz"));
EXPECT_LT(0ms, times.get("60.00 Hz")->get());
- mRefreshRateStats->setRefreshRate(config0Fps);
+ mRefreshRateStats->setRefreshRate(90_Hz);
auto sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -185,7 +153,7 @@
EXPECT_LT(ninety, times.get("90.00 Hz")->get());
EXPECT_EQ(sixty, times.get("60.00 Hz")->get());
- mRefreshRateStats->setRefreshRate(config1Fps);
+ mRefreshRateStats->setRefreshRate(60_Hz);
ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -194,10 +162,9 @@
EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
EXPECT_LT(sixty, times.get("60.00 Hz")->get());
- // Because the power mode is not PowerMode::ON, switching the config
- // does not update refresh rates that come from the config.
+ // Stats are not updated while the screen is off.
mRefreshRateStats->setPowerMode(PowerMode::DOZE);
- mRefreshRateStats->setRefreshRate(config0Fps);
+ mRefreshRateStats->setRefreshRate(90_Hz);
sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -206,7 +173,7 @@
EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
EXPECT_EQ(sixty, times.get("60.00 Hz")->get());
- mRefreshRateStats->setRefreshRate(config1Fps);
+ mRefreshRateStats->setRefreshRate(60_Hz);
screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index a992a91..aab2795 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -24,12 +24,15 @@
#include "Scheduler/RefreshRateConfigs.h"
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockDisplayMode.h"
#include "mock/MockEventThread.h"
#include "mock/MockLayer.h"
#include "mock/MockSchedulerCallback.h"
namespace android::scheduler {
+using android::mock::createDisplayMode;
+
using testing::_;
using testing::Return;
@@ -55,21 +58,11 @@
SchedulerTest();
- const DisplayModePtr mode60 = DisplayMode::Builder(0)
- .setId(DisplayModeId(0))
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod((60_Hz).getPeriodNsecs())
- .setGroup(0)
- .build();
- const DisplayModePtr mode120 = DisplayMode::Builder(1)
- .setId(DisplayModeId(1))
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod((120_Hz).getPeriodNsecs())
- .setGroup(0)
- .build();
+ static inline const DisplayModePtr kMode60 = createDisplayMode(DisplayModeId(0), 60_Hz);
+ static inline const DisplayModePtr kMode120 = createDisplayMode(DisplayModeId(1), 120_Hz);
std::shared_ptr<RefreshRateConfigs> mConfigs =
- std::make_shared<RefreshRateConfigs>(DisplayModes{mode60}, mode60->getId());
+ std::make_shared<RefreshRateConfigs>(makeModes(kMode60), kMode60->getId());
mock::SchedulerCallback mSchedulerCallback;
TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback};
@@ -172,7 +165,7 @@
constexpr uint32_t kDisplayArea = 999'999;
mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
- EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0);
+ EXPECT_CALL(mSchedulerCallback, requestDisplayMode(_, _)).Times(0);
mScheduler->chooseRefreshRateForContent();
}
@@ -182,7 +175,7 @@
ASSERT_EQ(1u, mScheduler->layerHistorySize());
mScheduler->setRefreshRateConfigs(
- std::make_shared<RefreshRateConfigs>(DisplayModes{mode60, mode120}, mode60->getId()));
+ std::make_shared<RefreshRateConfigs>(makeModes(kMode60, kMode120), kMode60->getId()));
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
@@ -221,12 +214,12 @@
}
MATCHER(Is120Hz, "") {
- return isApproxEqual(arg.getFps(), 120_Hz);
+ return isApproxEqual(arg->getFps(), 120_Hz);
}
TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
mScheduler->setRefreshRateConfigs(
- std::make_shared<RefreshRateConfigs>(DisplayModes{mode60, mode120}, mode60->getId()));
+ std::make_shared<RefreshRateConfigs>(makeModes(kMode60, kMode120), kMode60->getId()));
const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true));
@@ -239,11 +232,11 @@
constexpr uint32_t kDisplayArea = 999'999;
mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
- EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1);
+ EXPECT_CALL(mSchedulerCallback, requestDisplayMode(Is120Hz(), _)).Times(1);
mScheduler->chooseRefreshRateForContent();
// No-op if layer requirements have not changed.
- EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0);
+ EXPECT_CALL(mSchedulerCallback, requestDisplayMode(_, _)).Times(0);
mScheduler->chooseRefreshRateForContent();
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 3205952..32d57b5 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -43,13 +43,11 @@
mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
{
- DisplayModes modes = {kDisplayMode60, kDisplayMode90, kDisplayMode120,
- kDisplayMode90DifferentResolution};
- const DisplayModeId activeModeId = kDisplayModeId60;
- auto configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, activeModeId);
+ DisplayModes modes = makeModes(kMode60, kMode90, kMode120, kMode90_4K);
+ auto configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60);
mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
- .setDisplayModes(modes, activeModeId, std::move(configs))
+ .setDisplayModes(std::move(modes), kModeId60, std::move(configs))
.inject();
}
@@ -68,49 +66,18 @@
sp<DisplayDevice> mDisplay;
mock::EventThread* mAppEventThread;
- const DisplayModeId kDisplayModeId60 = DisplayModeId(0);
- const DisplayModePtr kDisplayMode60 =
- DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value()))
- .setId(kDisplayModeId60)
- .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
- .setVsyncPeriod((60_Hz).getPeriodNsecs())
- .setGroup(0)
- .setHeight(1000)
- .setWidth(1000)
- .build();
+ static constexpr DisplayModeId kModeId60{0};
+ static constexpr DisplayModeId kModeId90{1};
+ static constexpr DisplayModeId kModeId120{2};
+ static constexpr DisplayModeId kModeId90_4K{3};
- const DisplayModeId kDisplayModeId90 = DisplayModeId(1);
- const DisplayModePtr kDisplayMode90 =
- DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value()))
- .setId(kDisplayModeId90)
- .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
- .setVsyncPeriod((90_Hz).getPeriodNsecs())
- .setGroup(1)
- .setHeight(1000)
- .setWidth(1000)
- .build();
+ static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz, 0);
+ static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz, 1);
+ static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz, 2);
- const DisplayModeId kDisplayModeId120 = DisplayModeId(2);
- const DisplayModePtr kDisplayMode120 =
- DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value()))
- .setId(kDisplayModeId120)
- .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
- .setVsyncPeriod((120_Hz).getPeriodNsecs())
- .setGroup(2)
- .setHeight(1000)
- .setWidth(1000)
- .build();
-
- const DisplayModeId kDisplayModeId90DifferentResolution = DisplayModeId(3);
- const DisplayModePtr kDisplayMode90DifferentResolution =
- DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90DifferentResolution.value()))
- .setId(kDisplayModeId90DifferentResolution)
- .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
- .setVsyncPeriod((90_Hz).getPeriodNsecs())
- .setGroup(3)
- .setHeight(2000)
- .setWidth(2000)
- .build();
+ static constexpr ui::Size kResolution4K{3840, 2160};
+ static inline const DisplayModePtr kMode90_4K =
+ createDisplayMode(kModeId90_4K, 90_Hz, 3, kResolution4K);
};
void DisplayModeSwitchingTest::setupScheduler(
@@ -145,39 +112,39 @@
TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) {
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
mFlinger.onActiveDisplayChanged(mDisplay);
- mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
- kDisplayModeId90.value(), false, 0.f, 120.f, 0.f, 120.f);
+ mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(),
+ false, 0.f, 120.f, 0.f, 120.f);
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90);
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
// Verify that next commit will call setActiveConfigWithConstraints in HWC
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
EXPECT_CALL(*mComposer,
setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
- hal::HWConfigId(kDisplayModeId90.value()), _, _))
+ hal::HWConfigId(kModeId90.value()), _, _))
.WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
mFlinger.commit();
Mock::VerifyAndClearExpectations(mComposer);
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
// Verify that the next commit will complete the mode change and send
// a onModeChanged event to the framework.
- EXPECT_CALL(*mAppEventThread, onModeChanged(kDisplayMode90));
+ EXPECT_CALL(*mAppEventThread, onModeChanged(kMode90));
mFlinger.commit();
Mock::VerifyAndClearExpectations(mAppEventThread);
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90);
}
TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired) {
@@ -185,27 +152,27 @@
mFlinger.onActiveDisplayChanged(mDisplay);
- mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
- kDisplayModeId90.value(), true, 0.f, 120.f, 0.f, 120.f);
+ mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(),
+ true, 0.f, 120.f, 0.f, 120.f);
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90);
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
// Verify that next commit will call setActiveConfigWithConstraints in HWC
// and complete the mode change.
const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
EXPECT_CALL(*mComposer,
setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
- hal::HWConfigId(kDisplayModeId90.value()), _, _))
+ hal::HWConfigId(kModeId90.value()), _, _))
.WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
- EXPECT_CALL(*mAppEventThread, onModeChanged(kDisplayMode90));
+ EXPECT_CALL(*mAppEventThread, onModeChanged(kMode90));
mFlinger.commit();
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90);
}
TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) {
@@ -213,72 +180,72 @@
// is still being processed the later call will be respected.
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
mFlinger.onActiveDisplayChanged(mDisplay);
- mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
- kDisplayModeId90.value(), false, 0.f, 120.f, 0.f, 120.f);
+ mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(),
+ false, 0.f, 120.f, 0.f, 120.f);
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
EXPECT_CALL(*mComposer,
setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
- hal::HWConfigId(kDisplayModeId90.value()), _, _))
+ hal::HWConfigId(kModeId90.value()), _, _))
.WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
mFlinger.commit();
- mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
- kDisplayModeId120.value(), false, 0.f, 180.f, 0.f, 180.f);
+ mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId120.value(),
+ false, 0.f, 180.f, 0.f, 180.f);
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId120);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId120);
EXPECT_CALL(*mComposer,
setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
- hal::HWConfigId(kDisplayModeId120.value()), _, _))
+ hal::HWConfigId(kModeId120.value()), _, _))
.WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
mFlinger.commit();
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId120);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId120);
mFlinger.commit();
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId120);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId120);
}
TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefreshRequired) {
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
mFlinger.onActiveDisplayChanged(mDisplay);
- mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
- kDisplayModeId90DifferentResolution.value(), false, 0.f,
- 120.f, 0.f, 120.f);
+ mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90_4K.value(),
+ false, 0.f, 120.f, 0.f, 120.f);
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90DifferentResolution);
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90_4K);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
// Verify that next commit will call setActiveConfigWithConstraints in HWC
// and complete the mode change.
const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
EXPECT_CALL(*mComposer,
setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
- hal::HWConfigId(
- kDisplayModeId90DifferentResolution.value()),
- _, _))
+ hal::HWConfigId(kModeId90_4K.value()), _, _))
.WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
EXPECT_CALL(*mAppEventThread, onHotplugReceived(mDisplay->getPhysicalId(), true));
// Misc expecations. We don't need to enforce these method calls, but since the helper methods
// already set expectations we should add new ones here, otherwise the test will fail.
- EXPECT_CALL(*mConsumer, setDefaultBufferSize(2000, 2000)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mConsumer,
+ setDefaultBufferSize(static_cast<uint32_t>(kResolution4K.getWidth()),
+ static_cast<uint32_t>(kResolution4K.getHeight())))
+ .WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(hal::Error::NONE));
@@ -296,7 +263,7 @@
mDisplay = mFlinger.getDisplay(displayToken);
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90DifferentResolution);
+ ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90_4K);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 38dceb9..a0e078b 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -240,19 +240,17 @@
ASSERT_TRUE(hwcDisplayId);
mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId);
DisplayModePtr activeMode = DisplayMode::Builder(Case::Display::HWC_ACTIVE_CONFIG_ID)
- .setWidth(Case::Display::WIDTH)
- .setHeight(Case::Display::HEIGHT)
+ .setResolution(Case::Display::RESOLUTION)
.setVsyncPeriod(DEFAULT_VSYNC_PERIOD)
.setDpiX(DEFAULT_DPI)
.setDpiY(DEFAULT_DPI)
.setGroup(0)
.build();
- DisplayModes modes{activeMode};
state.physical = {.id = *displayId,
.type = *connectionType,
.hwcDisplayId = *hwcDisplayId,
- .supportedModes = modes,
- .activeMode = activeMode};
+ .supportedModes = makeModes(activeMode),
+ .activeMode = std::move(activeMode)};
}
state.isSecure = static_cast<bool>(Case::Display::SECURE);
@@ -270,8 +268,7 @@
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());
- EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
- EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
+ EXPECT_EQ(Case::Display::RESOLUTION, device->getSize());
EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
EXPECT_EQ(Case::HdrSupport::HDR10_PLUS_SUPPORTED, device->hasHDR10PlusSupport());
EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support());
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index fe0564e..bf2465f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -45,6 +45,7 @@
#include "SurfaceInterceptor.h"
#include "TestableScheduler.h"
#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockDisplayMode.h"
#include "mock/MockFrameTimeline.h"
#include "mock/MockFrameTracer.h"
#include "mock/MockSchedulerCallback.h"
@@ -227,31 +228,24 @@
if (std::holds_alternative<RefreshRateConfigsPtr>(modesVariant)) {
configs = std::move(std::get<RefreshRateConfigsPtr>(modesVariant));
} else {
- DisplayModes modes = {DisplayMode::Builder(0)
- .setId(DisplayModeId(0))
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(16'666'667)
- .setGroup(0)
- .build()};
+ constexpr DisplayModeId kModeId60{0};
+ DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz));
if (std::holds_alternative<TwoDisplayModes>(modesVariant)) {
- modes.emplace_back(DisplayMode::Builder(1)
- .setId(DisplayModeId(1))
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(11'111'111)
- .setGroup(0)
- .build());
+ constexpr DisplayModeId kModeId90{1};
+ modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz));
}
- configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, DisplayModeId(0));
+ configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60);
}
- const auto currFps = configs->getCurrentRefreshRate().getFps();
- mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps);
+ const auto fps = configs->getActiveMode()->getFps();
+ mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
+
mFlinger->mRefreshRateStats =
- std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
+ std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, fps,
hal::PowerMode::OFF);
using Callback = scheduler::ISchedulerCallback;
@@ -400,12 +394,12 @@
return mFlinger->setPowerModeInternal(display, mode);
}
- auto renderScreenImplLocked(const RenderArea& renderArea,
+ auto renderScreenImpl(const RenderArea& renderArea,
SurfaceFlinger::TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer,
bool forSystem, bool regionSampling) {
ScreenCaptureResults captureResults;
- return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem,
+ return mFlinger->renderScreenImpl(renderArea, traverseLayers, buffer, forSystem,
regionSampling, false /* grayscale */,
captureResults);
}
@@ -572,8 +566,7 @@
class FakeHwcDisplayInjector {
public:
static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000;
- static constexpr int32_t DEFAULT_WIDTH = 1920;
- static constexpr int32_t DEFAULT_HEIGHT = 1280;
+ static constexpr ui::Size DEFAULT_RESOLUTION{1920, 1280};
static constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'667;
static constexpr int32_t DEFAULT_CONFIG_GROUP = 7;
static constexpr int32_t DEFAULT_DPI = 320;
@@ -589,17 +582,12 @@
return *this;
}
- auto& setWidth(int32_t width) {
- mWidth = width;
+ auto& setResolution(ui::Size resolution) {
+ mResolution = resolution;
return *this;
}
- auto& setHeight(int32_t height) {
- mHeight = height;
- return *this;
- }
-
- auto& setVsyncPeriod(int32_t vsyncPeriod) {
+ auto& setVsyncPeriod(nsecs_t vsyncPeriod) {
mVsyncPeriod = vsyncPeriod;
return *this;
}
@@ -660,18 +648,20 @@
EXPECT_CALL(*composer,
getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<3>(mWidth), Return(hal::Error::NONE)));
+ .WillRepeatedly(DoAll(SetArgPointee<3>(mResolution.getWidth()),
+ Return(hal::Error::NONE)));
EXPECT_CALL(*composer,
getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::HEIGHT,
_))
- .WillRepeatedly(DoAll(SetArgPointee<3>(mHeight), Return(hal::Error::NONE)));
+ .WillRepeatedly(DoAll(SetArgPointee<3>(mResolution.getHeight()),
+ Return(hal::Error::NONE)));
EXPECT_CALL(*composer,
getDisplayAttribute(mHwcDisplayId, mActiveConfig,
hal::Attribute::VSYNC_PERIOD, _))
- .WillRepeatedly(
- DoAll(SetArgPointee<3>(mVsyncPeriod), Return(hal::Error::NONE)));
+ .WillRepeatedly(DoAll(SetArgPointee<3>(static_cast<int32_t>(mVsyncPeriod)),
+ Return(hal::Error::NONE)));
EXPECT_CALL(*composer,
getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_X, _))
@@ -708,9 +698,8 @@
const bool mIsPrimary;
hal::HWDisplayId mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
- int32_t mWidth = DEFAULT_WIDTH;
- int32_t mHeight = DEFAULT_HEIGHT;
- int32_t mVsyncPeriod = DEFAULT_VSYNC_PERIOD;
+ ui::Size mResolution = DEFAULT_RESOLUTION;
+ nsecs_t mVsyncPeriod = DEFAULT_VSYNC_PERIOD;
int32_t mDpiX = DEFAULT_DPI;
int32_t mDpiY = DEFAULT_DPI;
int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
@@ -723,12 +712,12 @@
class FakeDisplayDeviceInjector {
public:
FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
- std::shared_ptr<compositionengine::Display> compositionDisplay,
+ std::shared_ptr<compositionengine::Display> display,
std::optional<ui::DisplayConnectionType> connectionType,
std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
: mFlinger(flinger),
mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(),
- mDisplayToken, compositionDisplay),
+ mDisplayToken, display),
mHwcDisplayId(hwcDisplayId) {
mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
@@ -805,49 +794,52 @@
}
sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS {
+ const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
+
auto& modes = mCreationArgs.supportedModes;
auto& activeModeId = mCreationArgs.activeModeId;
- if (!mCreationArgs.refreshRateConfigs) {
- if (modes.empty()) {
- activeModeId = DisplayModeId(0);
- modes.emplace_back(
- DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
- .setId(activeModeId)
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
- .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
- .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
- .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI)
- .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI)
- .setGroup(0)
- .build());
- }
+ if (displayId && !mCreationArgs.refreshRateConfigs) {
+ if (const auto physicalId = PhysicalDisplayId::tryCast(*displayId)) {
+ if (modes.empty()) {
+ constexpr DisplayModeId kModeId{0};
+ DisplayModePtr mode =
+ DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
+ .setId(kModeId)
+ .setPhysicalDisplayId(*physicalId)
+ .setResolution(FakeHwcDisplayInjector::DEFAULT_RESOLUTION)
+ .setVsyncPeriod(
+ FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
+ .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI)
+ .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI)
+ .setGroup(FakeHwcDisplayInjector::DEFAULT_CONFIG_GROUP)
+ .build();
- mCreationArgs.refreshRateConfigs =
- std::make_shared<scheduler::RefreshRateConfigs>(modes, activeModeId);
+ modes = ftl::init::map(kModeId, std::move(mode));
+ activeModeId = kModeId;
+ }
+
+ mCreationArgs.refreshRateConfigs =
+ std::make_shared<scheduler::RefreshRateConfigs>(modes, activeModeId);
+ }
}
DisplayDeviceState state;
if (const auto type = mCreationArgs.connectionType) {
- const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
LOG_ALWAYS_FATAL_IF(!displayId);
const auto physicalId = PhysicalDisplayId::tryCast(*displayId);
LOG_ALWAYS_FATAL_IF(!physicalId);
LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
- const auto it = std::find_if(modes.begin(), modes.end(),
- [&activeModeId](const DisplayModePtr& mode) {
- return mode->getId() == activeModeId;
- });
- LOG_ALWAYS_FATAL_IF(it == modes.end());
+ const auto activeMode = modes.get(activeModeId);
+ LOG_ALWAYS_FATAL_IF(!activeMode);
state.physical = {.id = *physicalId,
.type = *type,
.hwcDisplayId = *mHwcDisplayId,
.deviceProductInfo = {},
.supportedModes = modes,
- .activeMode = *it};
+ .activeMode = activeMode->get()};
}
state.isSecure = mCreationArgs.isSecure;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 996f835..c1d41bb 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -160,6 +160,7 @@
Error(Display, std::optional<DisplayDecorationSupport>*));
MOCK_METHOD2(setIdleTimerEnabled, Error(Display, std::chrono::milliseconds));
MOCK_METHOD2(hasDisplayIdleTimerCapability, Error(Display, bool*));
+ MOCK_METHOD2(getPhysicalDisplayOrientation, Error(Display, AidlTransform*));
};
} // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h
new file mode 100644
index 0000000..a83ecbc
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.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 "DisplayHardware/DisplayMode.h"
+
+namespace android::mock {
+
+inline DisplayModePtr createDisplayMode(
+ DisplayModeId modeId, Fps refreshRate, int32_t group = 0,
+ ui::Size resolution = ui::Size(1920, 1080),
+ PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(0)) {
+ return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
+ .setId(modeId)
+ .setPhysicalDisplayId(displayId)
+ .setVsyncPeriod(refreshRate.getPeriodNsecs())
+ .setGroup(group)
+ .setResolution(resolution)
+ .build();
+}
+
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index d9faa06..ac2ab199c 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -101,6 +101,8 @@
(override));
MOCK_METHOD(hal::Error, setIdleTimerEnabled, (std::chrono::milliseconds), (override));
MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (), (const override));
+ MOCK_METHOD(hal::Error, getPhysicalDisplayOrientation, (Hwc2::AidlTransform *),
+ (const override));
};
class Layer : public HWC2::Layer {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index c90b8ed..5267586 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -23,17 +23,15 @@
namespace android::scheduler::mock {
struct SchedulerCallback final : ISchedulerCallback {
- MOCK_METHOD(void, scheduleComposite, (FrameHint), (override));
MOCK_METHOD(void, setVsyncEnabled, (bool), (override));
- MOCK_METHOD(void, changeRefreshRate, (const RefreshRate&, DisplayModeEvent), (override));
+ MOCK_METHOD(void, requestDisplayMode, (DisplayModePtr, DisplayModeEvent), (override));
MOCK_METHOD(void, kernelTimerChanged, (bool), (override));
MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override));
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
- void scheduleComposite(FrameHint) override {}
void setVsyncEnabled(bool) override {}
- void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {}
+ void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override {}
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() override {}
};
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 60c0cb5..7664518 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -924,9 +924,8 @@
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
std::vector<VkExtensionProperties> loader_extensions;
- loader_extensions.push_back({
- VK_KHR_SURFACE_EXTENSION_NAME,
- VK_KHR_SURFACE_SPEC_VERSION});
+ loader_extensions.push_back(
+ {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION});
loader_extensions.push_back(
{VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME,
VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION});
@@ -936,9 +935,9 @@
loader_extensions.push_back({
VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION});
- loader_extensions.push_back({
- VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
- VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION});
+ loader_extensions.push_back(
+ {VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
+ VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION});
loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME,
VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION});
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 0be4403..45bc4c9 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -719,7 +719,7 @@
bool wide_color_support = false;
uint64_t consumer_usage = 0;
- bool swapchain_ext =
+ bool colorspace_ext =
instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
if (surface_handle == VK_NULL_HANDLE) {
ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
@@ -748,7 +748,7 @@
consumer_usage = surface.consumer_usage;
}
- wide_color_support = wide_color_support && swapchain_ext;
+ wide_color_support = wide_color_support && colorspace_ext;
AHardwareBuffer_Desc desc = {};
desc.width = 1;
@@ -762,7 +762,7 @@
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
- if (swapchain_ext) {
+ if (colorspace_ext) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
}