Merge "SF: fix frame timeline timestamp" into tm-dev
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/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0e9ce89..24b201f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2418,7 +2418,7 @@
// Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
// of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
// will kill the HAL and grab whatever it dumped in time.
- constexpr size_t timeout_sec = 30;
+ constexpr size_t timeout_sec = 45;
if (dumpstate_hal_handle_aidl != nullptr) {
DoDumpstateBoardAidl(dumpstate_hal_handle_aidl, dumpstate_fds, options_->bugreport_mode,
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 6d3a2fe..7bad351 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -726,8 +726,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 +745,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
@@ -756,8 +755,7 @@
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
- for (int i = 0; i < 2; i++) {
- int currentFlag = storageFlags[i];
+ for (int currentFlag : storageFlags) {
if ((flags & currentFlag) == 0) {
continue;
}
@@ -766,7 +764,7 @@
// /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
@@ -776,27 +774,6 @@
if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM)) {
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();
@@ -847,11 +824,10 @@
binder::Status InstalldNativeService::reconcileSdkData(
const android::os::ReconcileSdkDataArgs& args) {
- ENFORCE_UID(AID_SYSTEM);
// 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);
}
/**
@@ -865,16 +841,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
@@ -883,16 +857,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;
}
@@ -906,37 +873,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);
@@ -945,19 +897,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);
@@ -968,7 +912,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;
@@ -1772,6 +1716,36 @@
}
}
+ // Copy sdk data for all known users
+ for (auto userId : users) {
+ LOCK_USER();
+
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+
+ const auto from = create_data_misc_sdk_sandbox_package_path(from_uuid, isCeData, userId,
+ package_name);
+ if (access(from.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << from;
+ continue;
+ }
+ const auto to = create_data_misc_sdk_sandbox_path(to_uuid, isCeData, userId);
+
+ const int rc = copy_directory_recursive(from.c_str(), to.c_str());
+ if (rc != 0) {
+ res = error(rc, "Failed copying " + from + " to " + to);
+ goto fail;
+ }
+ }
+
+ if (!restoreconSdkDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+ appId, seInfo)
+ .isOk()) {
+ res = error("Failed to restorecon");
+ goto fail;
+ }
+ }
// We let the framework scan the new location and persist that before
// deleting the data in the old location; this ordering ensures that
// we can recover from things like battery pulls.
@@ -1799,6 +1773,18 @@
}
}
}
+ for (auto userId : users) {
+ LOCK_USER();
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+ const auto to = create_data_misc_sdk_sandbox_package_path(to_uuid, isCeData, userId,
+ package_name);
+ if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
+ }
return res;
}
@@ -1833,6 +1819,11 @@
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
+ auto sdk_sandbox_de_path =
+ create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+ if (delete_dir_contents_and_dir(sdk_sandbox_de_path, true) != 0) {
+ res = error("Failed to delete " + sdk_sandbox_de_path);
+ }
if (uuid_ == nullptr) {
path = create_data_misc_legacy_path(userId);
if (delete_dir_contents_and_dir(path, true) != 0) {
@@ -1849,6 +1840,11 @@
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
+ auto sdk_sandbox_ce_path =
+ create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+ if (delete_dir_contents_and_dir(sdk_sandbox_ce_path, true) != 0) {
+ res = error("Failed to delete " + sdk_sandbox_ce_path);
+ }
path = findDataMediaPath(uuid, userId);
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
@@ -2101,6 +2097,13 @@
stats->dataSize += space;
}
+ 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) {
@@ -2208,8 +2211,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;
@@ -2234,6 +2246,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);
}
@@ -2376,6 +2393,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(
@@ -2612,6 +2642,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);
@@ -3131,6 +3168,49 @@
return res;
}
+binder::Status InstalldNativeService::restoreconSdkDataLocked(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+
+ binder::Status res = ok();
+
+ // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
+ unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgName = packageName.c_str();
+ const char* seinfo = seInfo.c_str();
+
+ uid_t uid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+ const auto packagePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgName);
+ if (access(packagePath.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << packagePath;
+ continue;
+ }
+ const auto subDirHandler = [&packagePath, &seinfo, &uid, &seflags,
+ &res](const std::string& subDir) {
+ const auto& fullpath = packagePath + "/" + subDir;
+ if (selinux_android_restorecon_pkgdir(fullpath.c_str(), seinfo, uid, seflags) < 0) {
+ res = error("restorecon failed for " + fullpath);
+ }
+ };
+ const auto ec = foreach_subdir(packagePath, subDirHandler);
+ if (ec != 0) {
+ res = error("Failed to restorecon for subdirs of " + packagePath);
+ }
+ }
+ return res;
+}
+
binder::Status InstalldNativeService::createOatDir(const std::string& packageName,
const std::string& oatDir,
const std::string& instructionSet) {
@@ -3496,5 +3576,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 55b0511..e6be5d8 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -63,9 +63,7 @@
binder::Status restoreconAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
const std::string& seInfo);
- binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
- const std::string& packageName, int32_t userId,
- int32_t flags, int32_t appId, const std::string& seInfo);
+
binder::Status migrateAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags);
binder::Status clearAppData(const std::optional<std::string>& uuid,
@@ -185,6 +183,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;
@@ -206,24 +209,28 @@
int32_t flags, int32_t appId, int32_t previousAppId,
const std::string& seInfo, int32_t targetSdkVersion,
int64_t* _aidl_return);
+ binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo);
- 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,
- int32_t appId, int32_t previousAppId, const std::string& seInfo,
- int flags);
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);
binder::Status destroySdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
const std::string& packageName,
int32_t userId, int32_t flags);
+ binder::Status reconcileSdkData(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ 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,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo);
};
} // namespace installd
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..2b5a35e 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -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 4423045..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 {
@@ -987,21 +989,17 @@
args.userId = kTestUserId;
args.appId = kTestAppId;
args.seInfo = "default";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
return args;
}
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;
@@ -1045,29 +1043,18 @@
TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
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;
@@ -1079,10 +1066,9 @@
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");
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
@@ -1094,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;
@@ -1109,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;
@@ -1126,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"));
}
@@ -1232,7 +1174,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
// Destroy the app user data.
@@ -1246,7 +1187,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
// Destroy the app user data.
@@ -1260,7 +1200,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
// Destroy the app user data.
@@ -1275,136 +1214,116 @@
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";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
- // 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";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
- // 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";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
- // 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";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
- // 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";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
- // 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) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ 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 {};
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithCeFlag) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"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")));
+ // Destroy user data
+ ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_CE));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithDeFlag) {
+ 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));
+ // Destroy user data
+ ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_DE));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
}
} // namespace installd
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..123e3d4 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -223,28 +223,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) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 54d77f9..cb30993 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);
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/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/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index e1cbc19..8132d46 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -18,10 +18,13 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/memfd.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
@@ -34,6 +37,24 @@
// ---------------------------------------------------------------------------
+#ifdef __BIONIC__
+static int memfd_create_region(const char* name, size_t size) {
+ int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (fd == -1) {
+ ALOGE("%s: memfd_create(%s, %zd) failed: %s\n", __func__, name, size, strerror(errno));
+ return -1;
+ }
+
+ if (ftruncate(fd, size) == -1) {
+ ALOGE("%s, ftruncate(%s, %zd) failed for memfd creation: %s\n", __func__, name, size,
+ strerror(errno));
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+#endif
+
MemoryHeapBase::MemoryHeapBase()
: mFD(-1), mSize(0), mBase(MAP_FAILED),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
@@ -45,15 +66,36 @@
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
const size_t pagesize = getpagesize();
- size = ((size + pagesize-1) & ~(pagesize-1));
- int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
- ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
- if (fd >= 0) {
- if (mapfd(fd, true, size) == NO_ERROR) {
- if (flags & READ_ONLY) {
- ashmem_set_prot_region(fd, PROT_READ);
- }
+ size = ((size + pagesize - 1) & ~(pagesize - 1));
+ int fd = -1;
+ if (mFlags & FORCE_MEMFD) {
+#ifdef __BIONIC__
+ ALOGV("MemoryHeapBase: Attempting to force MemFD");
+ fd = memfd_create_region(name ? name : "MemoryHeapBase", size);
+ if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
+ const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) |
+ ((mFlags & MEMFD_ALLOW_SEALING) ? 0 : F_SEAL_SEAL);
+ if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
+ ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error %s", name,
+ SEAL_FLAGS, strerror(errno));
+ munmap(mBase, mSize);
+ mBase = nullptr;
+ mSize = 0;
+ close(fd);
}
+ return;
+#else
+ mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING);
+#endif
+ }
+ if (mFlags & MEMFD_ALLOW_SEALING) {
+ LOG_ALWAYS_FATAL("Invalid Flags. MEMFD_ALLOW_SEALING only valid with FORCE_MEMFD.");
+ }
+ fd = ashmem_create_region(name ? name : "MemoryHeapBase", size);
+ ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno));
+ if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
+ if (mFlags & READ_ONLY) {
+ ashmem_set_prot_region(fd, PROT_READ);
}
}
@@ -61,6 +103,9 @@
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
+ if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
+ LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
+ }
int open_flags = O_RDWR;
if (flags & NO_CACHING)
open_flags |= O_SYNC;
@@ -80,6 +125,9 @@
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
+ if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
+ LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
+ }
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 504c6c2..a217a15 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1862,6 +1862,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 baa817c..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"
@@ -409,6 +410,28 @@
return 0;
}
+#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
+bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
+ static const char* const names[] = {
+ [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
+ DRIVER_FEATURES_PATH "oneway_spam_detection",
+ };
+ int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
+ char on;
+ if (fd == -1) {
+ ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
+ names[static_cast<int>(feature)], strerror(errno));
+ return false;
+ }
+ if (read(fd, &on, sizeof(on)) == -1) {
+ ALOGE("%s: error reading to %s: %s", __func__,
+ names[static_cast<int>(feature)], strerror(errno));
+ return false;
+ }
+ close(fd);
+ return on == '1';
+}
+
status_t ProcessState::enableOnewaySpamDetection(bool enable) {
uint32_t enableDetection = enable ? 1 : 0;
if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) {
@@ -452,7 +475,9 @@
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
if (result == -1) {
- ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+ ALOGE_IF(ProcessState::isDriverFeatureEnabled(
+ ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),
+ "Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
return fd;
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index e79cb86..d40778a 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -853,10 +853,16 @@
}
if (session->mConnections.mOutgoing.size() == 0) {
- ALOGE("Session has no client connections. This is required for an RPC server to make "
- "any non-nested (e.g. oneway or on another thread) calls. Use: %d. Server "
- "connections: %zu",
- static_cast<int>(use), session->mConnections.mIncoming.size());
+ ALOGE("Session has no outgoing connections. This is required for an RPC server to make "
+ "any non-nested (e.g. oneway or on another thread) calls. Use code request "
+ "reason: %d. Incoming connections: %zu. %s.",
+ static_cast<int>(use), session->mConnections.mIncoming.size(),
+ (session->server()
+ ? "This is a server session, so see RpcSession::setMaxIncomingThreads "
+ "for the corresponding client"
+ : "This is a client session, so see RpcSession::setMaxOutgoingThreads "
+ "for this client or RpcServer::setMaxThreads for the corresponding "
+ "server"));
return WOULD_BLOCK;
}
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/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index ea40db8..bb55831 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -56,8 +56,16 @@
static const int DUMP_FLAG_PROTO = 1 << 4;
/**
- * Retrieve an existing service, blocking for a few seconds
- * if it doesn't yet exist.
+ * Retrieve an existing service, blocking for a few seconds if it doesn't yet exist. This
+ * does polling. A more efficient way to make sure you unblock as soon as the service is
+ * available is to use waitForService or to use service notifications.
+ *
+ * Warning: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with isDeclared).
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index dd76943..15dd28f 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -34,7 +34,21 @@
// memory won't be mapped locally, but will be mapped in the remote
// process.
DONT_MAP_LOCALLY = 0x00000100,
- NO_CACHING = 0x00000200
+ NO_CACHING = 0x00000200,
+ // Bypass ashmem-libcutils to create a memfd shared region.
+ // Ashmem-libcutils will eventually migrate to memfd.
+ // Memfd has security benefits and supports file sealing.
+ // Calling process will need to modify selinux permissions to
+ // open access to tmpfs files. See audioserver for examples.
+ // This is only valid for size constructor.
+ // For host compilation targets, memfd is stubbed in favor of /tmp
+ // files so sealing is not enforced.
+ FORCE_MEMFD = 0x00000400,
+ // Default opt-out of sealing behavior in memfd to avoid potential DOS.
+ // Clients of shared files can seal at anytime via syscall, leading to
+ // TOC/TOU issues if additional seals prevent access from the creating
+ // process. Alternatively, seccomp fcntl().
+ MEMFD_ALLOW_SEALING = 0x00000800
};
/*
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 cf8d8e4..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>
// ---------------------------------------------------------------------------
@@ -91,6 +90,12 @@
*/
size_t getThreadPoolMaxThreadCount() const;
+ enum class DriverFeature {
+ ONEWAY_SPAM_DETECTION,
+ };
+ // Determine whether a feature is supported by the binder driver.
+ static bool isDriverFeatureEnabled(const DriverFeature feature);
+
private:
static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);
diff --git a/libs/binder/include_activitymanager/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
index b772b80..abc7f1d 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/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 2a66941..dfa8ea2 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -53,11 +53,19 @@
/**
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
- * for calling AIBinder_decStrong).
+ * for calling AIBinder_decStrong). This does polling. A more efficient way to make sure you
+ * unblock as soon as the service is available is to use AIBinder_waitForService.
*
* WARNING: when using this API across an APEX boundary, do not use with unstable
* AIDL services. TODO(b/139325195)
*
+ * WARNING: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with AServiceManager_isDeclared).
+ *
* \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
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/Android.bp b/libs/binder/tests/Android.bp
index ff55d6e..a3533d8 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -99,6 +99,7 @@
"binderParcelUnitTest.cpp",
"binderBinderUnitTest.cpp",
"binderStatusUnitTest.cpp",
+ "binderMemoryHeapBaseUnitTest.cpp",
],
shared_libs: [
"libbinder",
diff --git a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
new file mode 100644
index 0000000..21cb70b
--- /dev/null
+++ b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/MemoryHeapBase.h>
+#include <cutils/ashmem.h>
+#include <fcntl.h>
+
+#include <gtest/gtest.h>
+using namespace android;
+#ifdef __BIONIC__
+TEST(MemoryHeapBase, ForceMemfdRespected) {
+ auto mHeap = sp<MemoryHeapBase>::make(10, MemoryHeapBase::FORCE_MEMFD, "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_FALSE(ashmem_valid(fd));
+ EXPECT_NE(fcntl(fd, F_GET_SEALS), -1);
+}
+
+TEST(MemoryHeapBase, MemfdSealed) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL);
+}
+
+TEST(MemoryHeapBase, MemfdUnsealed) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), 0);
+}
+
+TEST(MemoryHeapBase, MemfdSealedProtected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL | F_SEAL_FUTURE_WRITE);
+}
+
+TEST(MemoryHeapBase, MemfdUnsealedProtected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_FUTURE_WRITE);
+}
+
+#else
+TEST(MemoryHeapBase, HostMemfdExpected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::READ_ONLY,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ void* ptr = mHeap->getBase();
+ EXPECT_NE(ptr, MAP_FAILED);
+ EXPECT_TRUE(ashmem_valid(fd));
+ EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
+}
+
+TEST(MemoryHeapBase,HostMemfdException) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ void* ptr = mHeap->getBase();
+ EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
+ EXPECT_TRUE(ashmem_valid(fd));
+ EXPECT_NE(ptr, MAP_FAILED);
+}
+
+#endif
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/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_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 749bf21..633626c 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,18 @@
#include <binder/Parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
+#include <functional>
+
namespace android {
/**
* 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,
+ std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader = nullptr);
} // 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..be39bb9
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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) {
+ while (provider.remaining_bytes() > 0) {
+ uint32_t code = provider.ConsumeIntegral<uint32_t>();
+ uint32_t flags = provider.ConsumeIntegral<uint32_t>();
+ Parcel data;
+
+ std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
+ provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+ fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()),
+ [&binder](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(binder->getInterfaceDescriptor());
+ }
+ });
+
+ Parcel reply;
+ (void)binder->transact(code, data, &reply, flags);
+ }
+}
+
+} // 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_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 8bf04cc..cfabc1e 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -34,15 +34,26 @@
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,
+ std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader) {
if (provider.ConsumeBool()) {
auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
CHECK_EQ(OK, session->addNullDebuggingClient());
p->markForRpc(session);
+
+ writeHeader(p, provider);
+
fillRandomParcelData(p, std::move(provider));
return;
}
+ writeHeader(p, provider);
+
while (provider.remaining_bytes() > 0) {
auto fillFunc = provider.PickValueInArray<const std::function<void()>>({
// write data
@@ -85,9 +96,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/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 1513eca..45a6d47 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -31,6 +31,7 @@
#include <android-base/unique_fd.h>
#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
+#include <cutils/android_filesystem_config.h>
#include <libbpf.h>
namespace android {
@@ -219,6 +220,7 @@
uint32_t totalFreqsCount = totalTimes.size();
std::vector<uint64_t> allUidTimes(totalFreqsCount, 0);
for (auto const &[uid, uidTimes]: *allUid) {
+ if (uid == AID_SDK_SANDBOX) continue;
for (uint32_t freqIdx = 0; freqIdx < uidTimes[policyIdx].size(); ++freqIdx) {
allUidTimes[std::min(freqIdx, totalFreqsCount - 1)] += uidTimes[policyIdx][freqIdx];
}
@@ -646,5 +648,55 @@
}
}
+void *forceSwitchWithUid(void *uidPtr) {
+ if (!uidPtr) return nullptr;
+ setuid(*(uint32_t *)uidPtr);
+
+ // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ return nullptr;
+}
+
+TEST_F(TimeInStateTest, SdkSandboxUid) {
+ // Find an unused app UID and its corresponding SDK sandbox uid.
+ uint32_t appUid = AID_APP_START, sandboxUid;
+ {
+ auto times = getUidsCpuFreqTimes();
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
+ for (const auto &kv : *times) {
+ if (kv.first > AID_APP_END) break;
+ appUid = std::max(appUid, kv.first);
+ }
+ appUid++;
+ sandboxUid = appUid + (AID_SDK_SANDBOX_PROCESS_START - AID_APP_START);
+ }
+
+ // Create a thread to run with the fake sandbox uid.
+ pthread_t thread;
+ ASSERT_EQ(pthread_create(&thread, NULL, &forceSwitchWithUid, &sandboxUid), 0);
+ pthread_join(thread, NULL);
+
+ // Confirm we recorded stats for appUid and AID_SDK_SANDBOX but not sandboxUid
+ auto allTimes = getUidsCpuFreqTimes();
+ ASSERT_TRUE(allTimes.has_value());
+ ASSERT_FALSE(allTimes->empty());
+ ASSERT_NE(allTimes->find(appUid), allTimes->end());
+ ASSERT_NE(allTimes->find(AID_SDK_SANDBOX), allTimes->end());
+ ASSERT_EQ(allTimes->find(sandboxUid), allTimes->end());
+
+ auto allConcurrentTimes = getUidsConcurrentTimes();
+ ASSERT_TRUE(allConcurrentTimes.has_value());
+ ASSERT_FALSE(allConcurrentTimes->empty());
+ ASSERT_NE(allConcurrentTimes->find(appUid), allConcurrentTimes->end());
+ ASSERT_NE(allConcurrentTimes->find(AID_SDK_SANDBOX), allConcurrentTimes->end());
+ ASSERT_EQ(allConcurrentTimes->find(sandboxUid), allConcurrentTimes->end());
+
+ ASSERT_TRUE(clearUidTimes(appUid));
+}
+
} // namespace bpf
} // namespace android
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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 27856ce..efa73df 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2320,9 +2320,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/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/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/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/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/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index add7a94..ec1bd47 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;
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
index b9abf8c..9fba642 100644
--- a/libs/tonemap/include/tonemap/tonemap.h
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -48,6 +48,14 @@
float contentMaxLuminance = 0.0;
};
+// 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 {
public:
virtual ~ToneMapper() {}
@@ -108,14 +116,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/tonemap.cpp b/libs/tonemap/tonemap.cpp
index bc0a884..c4f46bd 100644
--- a/libs/tonemap/tonemap.cpp
+++ b/libs/tonemap/tonemap.cpp
@@ -236,136 +236,143 @@
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);
+ 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 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;
- if (targetNits < x0) {
+ // 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;
- }
+ } 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;
}
};
@@ -427,8 +434,6 @@
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;
@@ -548,95 +553,99 @@
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;
+ for (const auto [linearRGB, _] : colors) {
+ double maxRGB = std::max({linearRGB.r, linearRGB.g, linearRGB.b});
- double x2 = x1 + (x3 - x1) * 4.0 / 17.0;
- double y2 = maxOutLumi * 0.9;
+ if (maxRGB <= 0.0) {
+ gains.push_back(1.0);
+ continue;
+ }
- const double greyNorm1 = OETF_ST2084(x1);
- const double greyNorm2 = OETF_ST2084(x2);
- const double greyNorm3 = OETF_ST2084(x3);
+ const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
+ const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
- double slope2 = (y2 - y1) / (greyNorm2 - greyNorm1);
- double slope3 = (y3 - y2) / (greyNorm3 - greyNorm2);
-
- 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);
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:
+ case kTransferHLG:
+ targetNits = maxRGB;
+ break;
+ default:
+ targetNits = maxRGB * metadata.displayMaxLuminance / 1000.0;
+ break;
+ }
+ break;
+ default:
+ targetNits = maxRGB;
+ break;
+ }
+
+ gains.push_back(targetNits / maxRGB);
}
-
- return targetNits / maxRGB;
+ return gains;
}
};
@@ -658,4 +667,4 @@
return sToneMapper.get();
}
-} // namespace android::tonemap
\ No newline at end of file
+} // namespace android::tonemap
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 bfdd22c..06ad6a8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -160,10 +160,7 @@
// when an application takes too long to respond and the user has pressed an app switch key.
constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
-// Amount of time to allow for an event to be dispatched (measured since its eventTime)
-// before considering it stale and dropping it.
-const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL // 10sec
- * HwTimeoutMultiplier();
+const std::chrono::duration STALE_EVENT_TIMEOUT = std::chrono::seconds(10) * HwTimeoutMultiplier();
// Log a warning when an event takes longer than this to process, even if an ANR does not occur.
constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
@@ -364,10 +361,6 @@
first->applicationInfo.token == second->applicationInfo.token;
}
-bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
- return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
-}
-
std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
std::shared_ptr<EventEntry> eventEntry,
int32_t inputTargetFlags) {
@@ -568,6 +561,10 @@
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
+ : InputDispatcher(policy, STALE_EVENT_TIMEOUT) {}
+
+InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
+ std::chrono::nanoseconds staleEventTimeout)
: mPolicy(policy),
mPendingEvent(nullptr),
mLastDropReason(DropReason::NOT_DROPPED),
@@ -586,6 +583,7 @@
mMaximumObscuringOpacityForTouch(1.0f),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
+ mStaleEventTimeout(staleEventTimeout),
mLatencyAggregator(),
mLatencyTracker(&mLatencyAggregator) {
mLooper = new Looper(false);
@@ -943,6 +941,10 @@
}
}
+bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
+ return std::chrono::nanoseconds(currentTime - entry.eventTime) >= mStaleEventTimeout;
+}
+
/**
* Return true if the events preceding this incoming motion event should be dropped
* Return false otherwise (the default behaviour)
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index d3e171a..3c79c98 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -84,6 +84,8 @@
static constexpr bool kDefaultInTouchMode = true;
explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
+ explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
+ std::chrono::nanoseconds staleEventTimeout);
~InputDispatcher() override;
void dump(std::string& dump) override;
@@ -471,6 +473,11 @@
*/
std::optional<nsecs_t> mNoFocusedWindowTimeoutTime GUARDED_BY(mLock);
+ // Amount of time to allow for an event to be dispatched (measured since its eventTime)
+ // before considering it stale and dropping it.
+ const std::chrono::nanoseconds mStaleEventTimeout;
+ bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry);
+
bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock);
/**
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 470d2f6..9633932 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -65,6 +65,8 @@
// An arbitrary pid of the gesture monitor window
static constexpr int32_t MONITOR_PID = 2001;
+static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
+
struct PointF {
float x;
float y;
@@ -489,7 +491,7 @@
void SetUp() override {
mFakePolicy = new FakeInputDispatcherPolicy();
- mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy);
+ mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy, STALE_EVENT_TIMEOUT);
mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
// Start InputDispatcher thread
ASSERT_EQ(OK, mDispatcher->start());
@@ -4451,6 +4453,38 @@
ASSERT_TRUE(mDispatcher->waitForIdle());
}
+/**
+ * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
+ * there will not be an ANR.
+ */
+TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
+ mWindow->setFocusable(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+ mWindow->consumeFocusEvent(false);
+
+ KeyEvent event;
+ const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
+ std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
+
+ // Define a valid key down event that is stale (too old).
+ event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+ INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A,
+ AMETA_NONE, 1 /*repeatCount*/, eventTime, eventTime);
+
+ const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+
+ InputEventInjectionResult result =
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::WAIT_FOR_RESULT,
+ INJECT_EVENT_TIMEOUT, policyFlags);
+ ASSERT_EQ(InputEventInjectionResult::FAILED, result)
+ << "Injection should fail because the event is stale";
+
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ mFakePolicy->assertNotifyAnrWasNotCalled();
+ mWindow->assertNoEvents();
+}
+
// We have a focused application, but no focused window
// Make sure that we don't notify policy twice about the same ANR.
TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index df4db19..455a1e2 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -42,4 +42,7 @@
srcs: [
"LatencyTrackerFuzzer.cpp",
],
+ fuzz_config: {
+ cc: ["android-framework-input@google.com"],
+ },
}
diff --git a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
index 1100cad..6e5e14d 100644
--- a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
+++ b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
@@ -66,13 +66,13 @@
sp<IPower> hal = waitForVintfService<IPower>();
if (hal == nullptr) {
- ALOGI("Power HAL not available, skipping test...");
+ ALOGV("Power HAL not available, skipping test...");
return;
}
binder::Status ret = (*hal.*fn)(std::forward<Args1>(args1)...);
if (ret.exceptionCode() == binder::Status::Exception::EX_UNSUPPORTED_OPERATION) {
- ALOGI("Power HAL does not support this operation, skipping test...");
+ ALOGV("Power HAL does not support this operation, skipping test...");
return;
}
@@ -93,7 +93,7 @@
sp<IPower> pwHal = waitForVintfService<IPower>();
if (pwHal == nullptr) {
- ALOGI("Power HAL not available, skipping test...");
+ ALOGV("Power HAL not available, skipping test...");
return;
}
@@ -105,13 +105,13 @@
auto status = pwHal->createHintSession(1, 0, threadIds, durationNanos, &hal);
if (hal == nullptr) {
- ALOGI("Power HAL doesn't support session, skipping test...");
+ ALOGV("Power HAL doesn't support session, skipping test...");
return;
}
binder::Status ret = (*hal.*fn)(std::forward<Args1>(args1)...);
if (ret.exceptionCode() == binder::Status::Exception::EX_UNSUPPORTED_OPERATION) {
- ALOGI("Power HAL does not support this operation, skipping test...");
+ ALOGV("Power HAL does not support this operation, skipping test...");
return;
}
@@ -159,13 +159,13 @@
sp<IPower> hal = waitForVintfService<IPower>();
if (hal == nullptr) {
- ALOGI("Power HAL not available, skipping test...");
+ ALOGV("Power HAL not available, skipping test...");
return;
}
binder::Status ret = hal->createHintSession(tgid, uid, threadIds, durationNanos, &appSession);
if (ret.exceptionCode() == binder::Status::Exception::EX_UNSUPPORTED_OPERATION) {
- ALOGI("Power HAL does not support this operation, skipping test...");
+ ALOGV("Power HAL does not support this operation, skipping test...");
return;
}
diff --git a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
index 97e026b..167f3a6 100644
--- a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
+++ b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
@@ -51,7 +51,7 @@
sp<I> hal = I::getService();
if (hal == nullptr) {
- ALOGI("Power HAL HIDL not available, skipping test...");
+ ALOGV("Power HAL HIDL not available, skipping test...");
return;
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 0aca24a..0b23a5a 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -362,6 +362,8 @@
// composition.
if (!mBufferInfo.mFrameLatencyNeeded) return;
+ mAlreadyDisplayedThisCompose = false;
+
// Update mFrameEventHistory.
{
Mutex::Autolock lock(mFrameEventHistoryMutex);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e6a76e8..bcae8d9 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -75,17 +75,15 @@
// -----------------------------------------------------------------------
void BufferStateLayer::onLayerDisplayed(
std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
- // If a layer has been displayed again we may need to clear
- // the mLastClientComposition fence that we use for early release in setBuffer
- // (as we now have a new fence which won't pass through the client composition path in some cases
- // e.g. screenshot). We expect one call to onLayerDisplayed after receiving the GL comp fence
- // from a single composition cycle, and want to clear on the second call
- // (which we track with mLastClientCompositionDisplayed)
- if (mLastClientCompositionDisplayed) {
+ // If we are displayed on multiple displays in a single composition cycle then we would
+ // need to do careful tracking to enable the use of the mLastClientCompositionFence.
+ // For example we can only use it if all the displays are client comp, and we need
+ // to merge all the client comp fences. We could do this, but for now we just
+ // disable the optimization when a layer is composed on multiple displays.
+ if (mAlreadyDisplayedThisCompose) {
mLastClientCompositionFence = nullptr;
- mLastClientCompositionDisplayed = false;
- } else if (mLastClientCompositionFence) {
- mLastClientCompositionDisplayed = true;
+ } else {
+ mAlreadyDisplayedThisCompose = true;
}
// The previous release fence notifies the client that SurfaceFlinger is done with the previous
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 9302b7b..aefc014 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -41,10 +41,6 @@
"libtonemap",
"libtrace_proto",
"libaidlcommonsupport",
- "libprocessgroup",
- "libcgrouprc",
- "libjsoncpp",
- "libcgrouprc_format",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -72,7 +68,6 @@
"src/DisplayColorProfile.cpp",
"src/DisplaySurface.cpp",
"src/DumpHelpers.cpp",
- "src/HwcAsyncWorker.cpp",
"src/HwcBufferCache.cpp",
"src/LayerFECompositionState.cpp",
"src/Output.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index ca86f4c..c553fce 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -72,9 +72,6 @@
virtual void resizeBuffers(const ui::Size&) = 0;
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
-
- // Returns true if the render surface supports client composition prediction.
- virtual bool supportsCompositionStrategyPrediction() const;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 1555102..d8644a4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -35,7 +35,6 @@
#include <utils/Vector.h>
#include <ui/DisplayIdentification.h>
-#include "DisplayHardware/HWComposer.h"
namespace android {
@@ -55,7 +54,6 @@
namespace impl {
struct OutputCompositionState;
-struct GpuCompositionResult;
} // namespace impl
/**
@@ -264,9 +262,6 @@
// Latches the front-end layer state for each output layer
virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0;
- // Enables predicting composition strategy to run client composition earlier
- virtual void setPredictCompositionStrategy(bool) = 0;
-
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
@@ -283,22 +278,13 @@
virtual void updateColorProfile(const CompositionRefreshArgs&) = 0;
virtual void beginFrame() = 0;
virtual void prepareFrame() = 0;
-
- using GpuCompositionResult = compositionengine::impl::GpuCompositionResult;
- // Runs prepare frame in another thread while running client composition using
- // the previous frame's composition strategy.
- virtual GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) = 0;
virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0;
- virtual void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) = 0;
+ virtual void finishFrame(const CompositionRefreshArgs&) = 0;
virtual std::optional<base::unique_fd> composeSurfaces(
- const Region&, const compositionengine::CompositionRefreshArgs&,
- std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&) = 0;
+ const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) = 0;
virtual void postFramebuffer() = 0;
virtual void renderCachedSets(const CompositionRefreshArgs&) = 0;
- virtual std::optional<android::HWComposer::DeviceRequestedChanges>
- chooseCompositionStrategy() = 0;
- virtual void applyCompositionStrategy(
- const std::optional<android::HWComposer::DeviceRequestedChanges>& changes) = 0;
+ virtual void chooseCompositionStrategy() = 0;
virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
virtual std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
@@ -309,7 +295,6 @@
std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
virtual void setExpensiveRenderingExpected(bool enabled) = 0;
virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
- virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 9ee779c..daee83b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -100,9 +100,6 @@
// Debugging - gets the page flip count for the RenderSurface
virtual std::uint32_t getPageFlipCount() const = 0;
-
- // Returns true if the render surface supports client composition prediction.
- virtual bool supportsCompositionStrategyPrediction() const = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 3b8b06f..58d2530 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -22,7 +22,6 @@
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/RenderSurface.h>
-#include <compositionengine/impl/GpuCompositionResult.h>
#include <compositionengine/impl/Output.h>
#include <ui/PixelFormat.h>
#include <ui/Size.h>
@@ -52,14 +51,11 @@
void setReleasedLayers(const CompositionRefreshArgs&) override;
void setColorTransform(const CompositionRefreshArgs&) override;
void setColorProfile(const ColorProfile&) override;
-
- using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges;
- std::optional<DeviceRequestedChanges> chooseCompositionStrategy() override;
- void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override;
+ void chooseCompositionStrategy() override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
void setExpensiveRenderingExpected(bool) override;
- void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override;
+ void finishFrame(const CompositionRefreshArgs&) override;
// compositionengine::Display overrides
DisplayId getId() const override;
@@ -77,6 +73,7 @@
using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty;
+ virtual bool anyLayersRequireClientComposition() const;
virtual bool allLayersRequireClientComposition() const;
virtual void applyChangedTypesToLayers(const ChangedTypes&);
virtual void applyDisplayRequests(const DisplayRequests&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h
deleted file mode 100644
index 2b1f50f..0000000
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 <android-base/unique_fd.h>
-#include <ui/GraphicBuffer.h>
-
-namespace android::compositionengine::impl {
-
-struct GpuCompositionResult {
- // Composition ready fence.
- base::unique_fd fence{};
-
- // Buffer to be used for gpu composition. If gpu composition was not successful,
- // then we want to reuse the buffer instead of dequeuing another buffer.
- std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
-
- bool bufferAvailable() const { return buffer != nullptr; };
-};
-
-} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h
deleted file mode 100644
index 11c0054..0000000
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 <android-base/thread_annotations.h>
-#include <future>
-#include <optional>
-#include <thread>
-
-#include "DisplayHardware/HWComposer.h"
-
-namespace android::compositionengine::impl {
-
-// HWC Validate call may take multiple milliseconds to complete and can account for
-// a signification amount of time in the display hotpath. This helper class allows
-// us to run the hwc validate function on a real time thread if we can predict what
-// the composition strategy will be and if composition includes client composition.
-// While the hwc validate runs, client composition is kicked off with the prediction.
-// When the worker returns with a value, the composition continues if the prediction
-// was successful otherwise the client composition is re-executed.
-//
-// Note: This does not alter the sequence between HWC and surfaceflinger.
-class HwcAsyncWorker final {
-public:
- HwcAsyncWorker();
- ~HwcAsyncWorker();
- // Runs the provided function which calls hwc validate and returns the requested
- // device changes as a future.
- std::future<std::optional<android::HWComposer::DeviceRequestedChanges>> send(
- std::function<std::optional<android::HWComposer::DeviceRequestedChanges>()>);
-
-private:
- std::mutex mMutex;
- std::condition_variable mCv GUARDED_BY(mMutex);
- bool mDone GUARDED_BY(mMutex) = false;
- bool mTaskRequested GUARDED_BY(mMutex) = false;
- std::packaged_task<std::optional<android::HWComposer::DeviceRequestedChanges>()> mTask
- GUARDED_BY(mMutex);
- std::thread mThread;
- void run();
-};
-
-} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 0be5d01..a7a8e97 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -17,13 +17,9 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/Output.h>
#include <compositionengine/impl/ClientCompositionRequestCache.h>
-#include <compositionengine/impl/GpuCompositionResult.h>
-#include <compositionengine/impl/HwcAsyncWorker.h>
#include <compositionengine/impl/OutputCompositionState.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
#include <renderengine/DisplaySettings.h>
#include <renderengine/LayerSettings.h>
@@ -96,38 +92,25 @@
void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
void beginFrame() override;
void prepareFrame() override;
- GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) override;
void devOptRepaintFlash(const CompositionRefreshArgs&) override;
- void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override;
- std::optional<base::unique_fd> composeSurfaces(const Region&,
- const compositionengine::CompositionRefreshArgs&,
- std::shared_ptr<renderengine::ExternalTexture>,
- base::unique_fd&) override;
+ void finishFrame(const CompositionRefreshArgs&) override;
+ std::optional<base::unique_fd> composeSurfaces(
+ const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) override;
void postFramebuffer() override;
void renderCachedSets(const CompositionRefreshArgs&) override;
void cacheClientCompositionRequests(uint32_t) override;
- bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override;
- void setPredictCompositionStrategy(bool) override;
// Testing
const ReleasedLayers& getReleasedLayersForTest() const;
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
bool plannerEnabled() const { return mPlanner != nullptr; }
- virtual bool anyLayersRequireClientComposition() const;
- virtual void updateProtectedContentState();
- virtual bool dequeueRenderBuffer(base::unique_fd*,
- std::shared_ptr<renderengine::ExternalTexture>*);
- virtual std::future<std::optional<android::HWComposer::DeviceRequestedChanges>>
- chooseCompositionStrategyAsync();
protected:
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
std::optional<size_t> findCurrentOutputLayerForLayer(
const sp<compositionengine::LayerFE>&) const;
- using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges;
- std::optional<DeviceRequestedChanges> chooseCompositionStrategy() override;
- void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override{};
+ void chooseCompositionStrategy() override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
@@ -148,7 +131,6 @@
private:
void dirtyEntireOutput();
compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const;
- void finishPrepareFrame();
ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
compositionengine::Output::ColorProfile pickColorProfile(
const compositionengine::CompositionRefreshArgs&) const;
@@ -162,7 +144,6 @@
OutputLayer* mLayerRequestingBackgroundBlur = nullptr;
std::unique_ptr<ClientCompositionRequestCache> mClientCompositionRequestCache;
std::unique_ptr<planner::Planner> mPlanner;
- std::unique_ptr<HwcAsyncWorker> mHwComposerAsyncWorker;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index ade9b25..66dd825 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -37,8 +37,6 @@
#include <ui/Region.h>
#include <ui/Transform.h>
-#include "DisplayHardware/HWComposer.h"
-
namespace android {
namespace compositionengine::impl {
@@ -116,8 +114,6 @@
// Current target dataspace
ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
- std::optional<android::HWComposer::DeviceRequestedChanges> previousDeviceRequestedChanges{};
-
// The earliest time to send the present command to the HAL
std::chrono::steady_clock::time_point earliestPresentTime;
@@ -141,18 +137,6 @@
// This is slightly distinct from nits, in that nits cannot be passed to hw composer.
std::optional<float> displayBrightness = std::nullopt;
- enum class CompositionStrategyPredictionState : uint32_t {
- // Composition strategy prediction did not run for this frame.
- DISABLED = 0,
- // Composition strategy predicted successfully for this frame.
- SUCCESS = 1,
- // Composition strategy prediction failed for this frame.
- FAIL = 2,
- };
-
- CompositionStrategyPredictionState strategyPrediction =
- CompositionStrategyPredictionState::DISABLED;
-
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index e4cb113..a8a5380 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -63,7 +63,6 @@
void queueBuffer(base::unique_fd readyFence) override;
void onPresentDisplayCompleted() override;
void flip() override;
- bool supportsCompositionStrategyPrediction() const override;
// Debugging
void dump(std::string& result) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index 72e6f3b..d90cc90 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -41,7 +41,6 @@
MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
- MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 27303a8..b68b95d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -22,7 +22,6 @@
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
-#include <compositionengine/impl/GpuCompositionResult.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <gmock/gmock.h>
@@ -100,22 +99,16 @@
MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
- MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&));
- MOCK_METHOD0(chooseCompositionStrategy,
- std::optional<android::HWComposer::DeviceRequestedChanges>());
- MOCK_METHOD1(applyCompositionStrategy,
- void(const std::optional<android::HWComposer::DeviceRequestedChanges>&));
+ MOCK_METHOD0(chooseCompositionStrategy, void());
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD2(finishFrame,
- void(const compositionengine::CompositionRefreshArgs&, GpuCompositionResult&&));
+ MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD4(composeSurfaces,
+ MOCK_METHOD2(composeSurfaces,
std::optional<base::unique_fd>(
const Region&,
- const compositionengine::CompositionRefreshArgs& refreshArgs,
- std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
+ const compositionengine::CompositionRefreshArgs& refreshArgs));
MOCK_CONST_METHOD0(getSkipColorTransform, bool());
MOCK_METHOD0(postFramebuffer, void());
@@ -128,8 +121,6 @@
void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t));
- MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
- MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index e12aebb..fe858c2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -45,7 +45,6 @@
MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
- MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 09648c3..6a75283 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -221,12 +221,12 @@
setReleasedLayers(std::move(releasedLayers));
}
-std::optional<android::HWComposer::DeviceRequestedChanges> Display::chooseCompositionStrategy() {
+void Display::chooseCompositionStrategy() {
ATRACE_CALL();
ALOGV(__FUNCTION__);
if (mIsDisconnected) {
- return {};
+ return;
}
// Default to the base settings -- client composition only.
@@ -235,7 +235,7 @@
// If we don't have a HWC display, then we are done.
const auto halDisplayId = HalDisplayId::tryCast(mId);
if (!halDisplayId) {
- return {};
+ return;
}
// Get any composition changes requested by the HWC device, and apply them.
@@ -260,13 +260,8 @@
result != NO_ERROR) {
ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
strerror(-result));
- return {};
+ return;
}
-
- return changes;
-}
-
-void Display::applyCompositionStrategy(const std::optional<DeviceRequestedChanges>& changes) {
if (changes) {
applyChangedTypesToLayers(changes->changedTypes);
applyDisplayRequests(changes->displayRequests);
@@ -292,6 +287,12 @@
return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM);
}
+bool Display::anyLayersRequireClientComposition() const {
+ const auto layers = getOutputLayersOrderedByZ();
+ return std::any_of(layers.begin(), layers.end(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
bool Display::allLayersRequireClientComposition() const {
const auto layers = getOutputLayersOrderedByZ();
return std::all_of(layers.begin(), layers.end(),
@@ -389,8 +390,7 @@
}
}
-void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs,
- GpuCompositionResult&& result) {
+void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
@@ -400,7 +400,7 @@
return;
}
- impl::Output::finishFrame(refreshArgs, std::move(result));
+ impl::Output::finishFrame(refreshArgs);
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
index 28900af..db6d4f2 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
@@ -20,8 +20,4 @@
DisplaySurface::~DisplaySurface() = default;
-bool DisplaySurface::supportsCompositionStrategyPrediction() const {
- return true;
-}
-
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
deleted file mode 100644
index 497424a..0000000
--- a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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 <compositionengine/impl/HwcAsyncWorker.h>
-#include <processgroup/sched_policy.h>
-#include <pthread.h>
-#include <sched.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
-#include <system/thread_defs.h>
-
-#include <android-base/thread_annotations.h>
-#include <cutils/sched_policy.h>
-
-namespace android::compositionengine::impl {
-
-HwcAsyncWorker::HwcAsyncWorker() {
- mThread = std::thread(&HwcAsyncWorker::run, this);
- pthread_setname_np(mThread.native_handle(), "HwcAsyncWorker");
-}
-
-HwcAsyncWorker::~HwcAsyncWorker() {
- {
- std::scoped_lock lock(mMutex);
- mDone = true;
- mCv.notify_all();
- }
- if (mThread.joinable()) {
- mThread.join();
- }
-}
-std::future<std::optional<android::HWComposer::DeviceRequestedChanges>> HwcAsyncWorker::send(
- std::function<std::optional<android::HWComposer::DeviceRequestedChanges>()> task) {
- std::unique_lock<std::mutex> lock(mMutex);
- android::base::ScopedLockAssertion assumeLock(mMutex);
- mTask = std::packaged_task<std::optional<android::HWComposer::DeviceRequestedChanges>()>(
- [task = std::move(task)]() { return task(); });
- mTaskRequested = true;
- mCv.notify_one();
- return mTask.get_future();
-}
-
-void HwcAsyncWorker::run() {
- set_sched_policy(0, SP_FOREGROUND);
- struct sched_param param = {0};
- param.sched_priority = 2;
- sched_setscheduler(gettid(), SCHED_FIFO, ¶m);
-
- std::unique_lock<std::mutex> lock(mMutex);
- android::base::ScopedLockAssertion assumeLock(mMutex);
- while (!mDone) {
- mCv.wait(lock);
- if (mTaskRequested && mTask.valid()) {
- mTask();
- mTaskRequested = false;
- }
- }
-}
-
-} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 7e650a1..4e67a63 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -22,7 +22,6 @@
#include <compositionengine/LayerFE.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/RenderSurface.h>
-#include <compositionengine/impl/HwcAsyncWorker.h>
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
@@ -58,8 +57,7 @@
Output::~Output() = default;
namespace impl {
-using CompositionStrategyPredictionState =
- OutputCompositionState::CompositionStrategyPredictionState;
+
namespace {
template <typename T>
@@ -436,17 +434,9 @@
writeCompositionState(refreshArgs);
setColorTransform(refreshArgs);
beginFrame();
-
- GpuCompositionResult result;
- const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs);
- if (predictCompositionStrategy) {
- result = prepareFrameAsync(refreshArgs);
- } else {
- prepareFrame();
- }
-
+ prepareFrame();
devOptRepaintFlash(refreshArgs);
- finishFrame(refreshArgs, std::move(result));
+ finishFrame(refreshArgs);
postFramebuffer();
renderCachedSets(refreshArgs);
}
@@ -694,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&) {
@@ -961,64 +953,19 @@
ATRACE_CALL();
ALOGV(__FUNCTION__);
- auto& outputState = editState();
+ const auto& outputState = getState();
if (!outputState.isEnabled) {
return;
}
- auto changes = chooseCompositionStrategy();
- outputState.strategyPrediction = CompositionStrategyPredictionState::DISABLED;
- outputState.previousDeviceRequestedChanges = changes;
- if (changes) {
- applyCompositionStrategy(changes);
- }
- finishPrepareFrame();
-}
+ chooseCompositionStrategy();
-std::future<std::optional<android::HWComposer::DeviceRequestedChanges>>
-Output::chooseCompositionStrategyAsync() {
- return mHwComposerAsyncWorker->send([&]() { return chooseCompositionStrategy(); });
-}
-
-GpuCompositionResult Output::prepareFrameAsync(const CompositionRefreshArgs& refreshArgs) {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
- auto& state = editState();
- const auto& previousChanges = state.previousDeviceRequestedChanges;
- auto hwcResult = chooseCompositionStrategyAsync();
- applyCompositionStrategy(previousChanges);
- finishPrepareFrame();
-
- base::unique_fd bufferFence;
- std::shared_ptr<renderengine::ExternalTexture> buffer;
- updateProtectedContentState();
- const bool dequeueSucceeded = dequeueRenderBuffer(&bufferFence, &buffer);
- GpuCompositionResult compositionResult;
- if (dequeueSucceeded) {
- std::optional<base::unique_fd> optFd =
- composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence);
- if (optFd) {
- compositionResult.fence = std::move(*optFd);
- }
+ if (mPlanner) {
+ mPlanner->reportFinalPlan(getOutputLayersOrderedByZ());
}
- auto changes = hwcResult.valid() ? hwcResult.get() : std::nullopt;
- const bool predictionSucceeded = dequeueSucceeded && changes == previousChanges;
- state.strategyPrediction = predictionSucceeded ? CompositionStrategyPredictionState::SUCCESS
- : CompositionStrategyPredictionState::FAIL;
- if (!predictionSucceeded) {
- ATRACE_NAME("CompositionStrategyPredictionMiss");
- if (changes) {
- applyCompositionStrategy(changes);
- }
- finishPrepareFrame();
- // Track the dequeued buffer to reuse so we don't need to dequeue another one.
- compositionResult.buffer = buffer;
- } else {
- ATRACE_NAME("CompositionStrategyPredictionHit");
- }
- state.previousDeviceRequestedChanges = std::move(changes);
- return compositionResult;
+ mRenderSurface->prepareFrame(outputState.usesClientComposition,
+ outputState.usesDeviceComposition);
}
void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) {
@@ -1028,11 +975,7 @@
if (getState().isEnabled) {
if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) {
- base::unique_fd bufferFence;
- std::shared_ptr<renderengine::ExternalTexture> buffer;
- updateProtectedContentState();
- dequeueRenderBuffer(&bufferFence, &buffer);
- static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs, buffer, bufferFence));
+ static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs));
mRenderSurface->queueBuffer(base::unique_fd());
}
}
@@ -1044,33 +987,17 @@
prepareFrame();
}
-void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositionResult&& result) {
+void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
ATRACE_CALL();
ALOGV(__FUNCTION__);
- const auto& outputState = getState();
- if (!outputState.isEnabled) {
+
+ if (!getState().isEnabled) {
return;
}
- std::optional<base::unique_fd> optReadyFence;
- std::shared_ptr<renderengine::ExternalTexture> buffer;
- base::unique_fd bufferFence;
- if (outputState.strategyPrediction == CompositionStrategyPredictionState::SUCCESS) {
- optReadyFence = std::move(result.fence);
- } else {
- if (result.bufferAvailable()) {
- buffer = std::move(result.buffer);
- bufferFence = std::move(result.fence);
- } else {
- updateProtectedContentState();
- if (!dequeueRenderBuffer(&bufferFence, &buffer)) {
- return;
- }
- }
- // Repaint the framebuffer (if needed), getting the optional fence for when
- // the composition completes.
- optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence);
- }
+ // Repaint the framebuffer (if needed), getting the optional fence for when
+ // the composition completes.
+ auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs);
if (!optReadyFence) {
return;
}
@@ -1079,8 +1006,16 @@
mRenderSurface->queueBuffer(std::move(*optReadyFence));
}
-void Output::updateProtectedContentState() {
+std::optional<base::unique_fd> Output::composeSurfaces(
+ const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
const auto& outputState = getState();
+ OutputCompositionState& outputCompositionState = editState();
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ outputState.usesClientComposition};
+
auto& renderEngine = getCompositionEngine().getRenderEngine();
const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
@@ -1102,48 +1037,29 @@
} else if (!outputState.isSecure && renderEngine.isProtected()) {
renderEngine.useProtectedContext(false);
}
-}
-bool Output::dequeueRenderBuffer(base::unique_fd* bufferFence,
- std::shared_ptr<renderengine::ExternalTexture>* tex) {
- const auto& outputState = getState();
+ base::unique_fd fd;
+
+ std::shared_ptr<renderengine::ExternalTexture> tex;
// If we aren't doing client composition on this output, but do have a
// flipClientTarget request for this frame on this output, we still need to
// dequeue a buffer.
- if (outputState.usesClientComposition || outputState.flipClientTarget) {
- *tex = mRenderSurface->dequeueBuffer(bufferFence);
- if (*tex == nullptr) {
+ if (hasClientComposition || outputState.flipClientTarget) {
+ tex = mRenderSurface->dequeueBuffer(&fd);
+ if (tex == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
mName.c_str());
- return false;
+ return {};
}
}
- return true;
-}
-std::optional<base::unique_fd> Output::composeSurfaces(
- const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs,
- std::shared_ptr<renderengine::ExternalTexture> tex, base::unique_fd& fd) {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
- const auto& outputState = getState();
- const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
- outputState.usesClientComposition};
if (!hasClientComposition) {
setExpensiveRenderingExpected(false);
return base::unique_fd();
}
- if (tex == nullptr) {
- ALOGW("Buffer not valid for display [%s], bailing out of "
- "client composition for this frame",
- mName.c_str());
- return {};
- }
-
ALOGV("hasClientComposition");
renderengine::DisplaySettings clientCompositionDisplay;
@@ -1171,8 +1087,6 @@
outputState.usesDeviceComposition || getSkipColorTransform();
// Generate the client composition requests for the layers on this output.
- auto& renderEngine = getCompositionEngine().getRenderEngine();
- const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
std::vector<LayerFE*> clientCompositionLayersFE;
std::vector<LayerFE::LayerSettings> clientCompositionLayers =
generateClientCompositionRequests(supportsProtectedContent,
@@ -1180,19 +1094,16 @@
clientCompositionLayersFE);
appendRegionFlashRequests(debugRegion, clientCompositionLayers);
- OutputCompositionState& outputCompositionState = editState();
// Check if the client composition requests were rendered into the provided graphic buffer. If
// so, we can reuse the buffer and avoid client composition.
if (mClientCompositionRequestCache) {
if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(),
clientCompositionDisplay,
clientCompositionLayers)) {
- ATRACE_NAME("ClientCompositionCacheHit");
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
return base::unique_fd();
}
- ATRACE_NAME("ClientCompositionCacheMiss");
mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
clientCompositionLayers);
}
@@ -1444,13 +1355,12 @@
outputState.dirtyRegion.set(outputState.displaySpace.getBoundsAsRect());
}
-std::optional<android::HWComposer::DeviceRequestedChanges> Output::chooseCompositionStrategy() {
+void Output::chooseCompositionStrategy() {
// The base output implementation can only do client composition
auto& outputState = editState();
outputState.usesClientComposition = true;
outputState.usesDeviceComposition = false;
outputState.reusedClientComposition = false;
- return {};
}
bool Output::getSkipColorTransform() const {
@@ -1465,63 +1375,5 @@
return result;
}
-void Output::setPredictCompositionStrategy(bool predict) {
- if (predict) {
- mHwComposerAsyncWorker = std::make_unique<HwcAsyncWorker>();
- } else {
- mHwComposerAsyncWorker.reset(nullptr);
- }
-}
-
-bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
- if (!getState().isEnabled || !mHwComposerAsyncWorker) {
- ALOGV("canPredictCompositionStrategy disabled");
- return false;
- }
-
- if (!getState().previousDeviceRequestedChanges) {
- ALOGV("canPredictCompositionStrategy previous changes not available");
- return false;
- }
-
- if (!mRenderSurface->supportsCompositionStrategyPrediction()) {
- ALOGV("canPredictCompositionStrategy surface does not support");
- return false;
- }
-
- if (refreshArgs.devOptFlashDirtyRegionsDelay) {
- ALOGV("canPredictCompositionStrategy devOptFlashDirtyRegionsDelay");
- return false;
- }
-
- // If no layer uses clientComposition, then don't predict composition strategy
- // because we have less work to do in parallel.
- if (!anyLayersRequireClientComposition()) {
- ALOGV("canPredictCompositionStrategy no layer uses clientComposition");
- return false;
- }
-
- if (!refreshArgs.updatingOutputGeometryThisFrame) {
- return true;
- }
-
- ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
- return false;
-}
-
-bool Output::anyLayersRequireClientComposition() const {
- const auto layers = getOutputLayersOrderedByZ();
- return std::any_of(layers.begin(), layers.end(),
- [](const auto& layer) { return layer->requiresClientComposition(); });
-}
-
-void Output::finishPrepareFrame() {
- const auto& state = getState();
- if (mPlanner) {
- mPlanner->reportFinalPlan(getOutputLayersOrderedByZ());
- }
- mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition);
-}
-
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 7188281..482250a 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -18,19 +18,6 @@
#include <compositionengine/impl/OutputCompositionState.h>
namespace android::compositionengine::impl {
-using CompositionStrategyPredictionState =
- OutputCompositionState::CompositionStrategyPredictionState;
-
-std::string toString(CompositionStrategyPredictionState state) {
- switch (state) {
- case CompositionStrategyPredictionState::DISABLED:
- return "Disabled";
- case CompositionStrategyPredictionState::SUCCESS:
- return "Success";
- case CompositionStrategyPredictionState::FAIL:
- return "Fail";
- }
-}
void OutputCompositionState::dump(std::string& out) const {
out.append(" ");
@@ -69,7 +56,6 @@
dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
dumpVal(out, "displayBrightness", displayBrightness);
- dumpVal(out, "compositionStrategyPredictionState", toString(strategyPrediction));
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 3e983f3..723593d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -325,7 +325,8 @@
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
if (isHdrDataspace(state.dataspace) ||
- getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits) {
+ getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits ||
+ getOutput().getState().displayBrightnessNits == 0.f) {
state.dimmingRatio = 1.f;
state.whitePointNits = getOutput().getState().displayBrightnessNits;
} else {
@@ -506,9 +507,18 @@
to_string(error).c_str(), static_cast<int32_t>(error));
}
- // Don't dim cached layers
- const auto dimmingRatio =
- outputDependentState.overrideInfo.buffer ? 1.f : outputDependentState.dimmingRatio;
+ // Cached layers are not dimmed, which means that composer should attempt to dim.
+ // Note that if the dimming ratio is large, then this may cause the cached layer
+ // to kick back into GPU composition :(
+ // Also note that this assumes that there are no HDR layers that are able to be cached.
+ // Otherwise, this could cause HDR layers to be dimmed twice.
+ const auto dimmingRatio = outputDependentState.overrideInfo.buffer
+ ? (getOutput().getState().displayBrightnessNits != 0.f
+ ? std::clamp(getOutput().getState().sdrWhitePointNits /
+ getOutput().getState().displayBrightnessNits,
+ 0.f, 1.f)
+ : 1.f)
+ : outputDependentState.dimmingRatio;
if (auto error = hwcLayer->setBrightness(dimmingRatio); error != hal::Error::NONE) {
ALOGE("[%s] Failed to set brightness %f: %s (%d)", getLayerFE().getDebugName(),
@@ -788,6 +798,7 @@
}};
settings.sourceDataspace = getState().overrideInfo.dataspace;
settings.alpha = 1.0f;
+ settings.whitePointNits = getOutput().getState().sdrWhitePointNits;
return {static_cast<LayerFE::LayerSettings>(settings)};
}
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/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 5a3af7b..12c2c8e 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -289,9 +289,5 @@
return mTexture;
}
-bool RenderSurface::supportsCompositionStrategyPrediction() const {
- return mDisplaySurface->supportsCompositionStrategyPrediction();
-}
-
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 42c1263..aaca4fe 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -307,7 +307,12 @@
}
const auto& layerFE = mLayers[0].getState()->getOutputLayer()->getLayerFE();
- if (layerFE.getCompositionState()->forceClientComposition) {
+ const auto* compositionState = layerFE.getCompositionState();
+ if (compositionState->forceClientComposition) {
+ return false;
+ }
+
+ if (compositionState->blendMode != hal::BlendMode::NONE) {
return false;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 36b04d9..cd03235 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,9 +30,7 @@
#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
-#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
-
#include <ui/Rect.h>
#include <ui/StaticDisplayInfo.h>
@@ -200,22 +198,6 @@
std::shared_ptr<Display> mDisplay =
createPartialMockDisplay<Display>(mCompositionEngine,
getDisplayCreationArgsForPhysicalDisplay());
-
- android::HWComposer::DeviceRequestedChanges mDeviceRequestedChanges{
- {{nullptr, Composition::CLIENT}},
- hal::DisplayRequest::FLIP_CLIENT_TARGET,
- {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
- {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
- -1.f,
- };
-
- void chooseCompositionStrategy(Display* display) {
- std::optional<android::HWComposer::DeviceRequestedChanges> changes =
- display->chooseCompositionStrategy();
- if (changes) {
- display->applyCompositionStrategy(changes);
- }
- }
};
struct FullDisplayImplTestCommon : public DisplayTestCommon {
@@ -232,11 +214,6 @@
std::unique_ptr<compositionengine::OutputLayer>(mLayer2.outputLayer));
mDisplay->injectOutputLayerForTest(
std::unique_ptr<compositionengine::OutputLayer>(mLayer3.outputLayer));
- mResultWithBuffer.buffer = std::make_shared<
- renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
- 1ULL /* bufferId */,
- HAL_PIXEL_FORMAT_RGBA_8888,
- 0ULL /*usage*/);
}
Layer mLayer1;
@@ -245,8 +222,6 @@
StrictMock<HWC2::mock::Layer> hwc2LayerUnknown;
std::shared_ptr<Display> mDisplay =
createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
- impl::GpuCompositionResult mResultWithBuffer;
- impl::GpuCompositionResult mResultWithoutBuffer;
};
/*
@@ -579,7 +554,7 @@
createPartialMockDisplay<Display>(mCompositionEngine, args);
EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId()));
- chooseCompositionStrategy(gpuDisplay.get());
+ gpuDisplay->chooseCompositionStrategy();
auto& state = gpuDisplay->getState();
EXPECT_TRUE(state.usesClientComposition);
@@ -592,12 +567,11 @@
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _))
.WillOnce(Return(INVALID_OPERATION));
- chooseCompositionStrategy(mDisplay.get());
+ mDisplay->chooseCompositionStrategy();
auto& state = mDisplay->getState();
EXPECT_TRUE(state.usesClientComposition);
EXPECT_FALSE(state.usesDeviceComposition);
- EXPECT_FALSE(state.previousDeviceRequestedChanges.has_value());
}
TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
@@ -614,16 +588,10 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges),
- Return(NO_ERROR)));
- EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
- .Times(1);
- EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
- EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
- .Times(1);
+ .WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
- chooseCompositionStrategy(mDisplay.get());
+ mDisplay->chooseCompositionStrategy();
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -650,17 +618,11 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges),
- Return(NO_ERROR)));
- EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
- .Times(1);
- EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
- EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
- .Times(1);
+ .WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
mDisplay->setNextBrightness(kDisplayBrightness);
- chooseCompositionStrategy(mDisplay.get());
+ mDisplay->chooseCompositionStrategy();
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -669,6 +631,14 @@
}
TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
+ android::HWComposer::DeviceRequestedChanges changes{
+ {{nullptr, Composition::CLIENT}},
+ hal::DisplayRequest::FLIP_CLIENT_TARGET,
+ {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
+ {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
+ -1.f,
+ };
+
// Since two calls are made to anyLayersRequireClientComposition with different return
// values, use a Sequence to control the matching so the values are returned in a known
// order.
@@ -682,15 +652,13 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR)));
- EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
- .Times(1);
- EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
- EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
- .Times(1);
+ .WillOnce(DoAll(SetArgPointee<5>(changes), Return(NO_ERROR)));
+ EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
+ EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
+ EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
- chooseCompositionStrategy(mDisplay.get());
+ mDisplay->chooseCompositionStrategy();
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -954,7 +922,7 @@
mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- mDisplay->finishFrame({}, std::move(mResultWithBuffer));
+ mDisplay->finishFrame({});
}
TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) {
@@ -972,7 +940,7 @@
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer));
+ gpuDisplay->finishFrame({});
}
TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
@@ -989,7 +957,7 @@
gpuDisplay->editState().usesClientComposition = false;
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
- gpuDisplay->finishFrame({}, std::move(mResultWithBuffer));
+ gpuDisplay->finishFrame({});
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 719f15c..1f1dd1a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -133,6 +133,8 @@
status_t(PhysicalDisplayId,
std::optional<aidl::android::hardware::graphics::common::
DisplayDecorationSupport>* support));
+ MOCK_METHOD2(setIdleTimerEnabled, status_t(PhysicalDisplayId, std::chrono::milliseconds));
+ MOCK_METHOD1(hasDisplayIdleTimerCapability, bool(PhysicalDisplayId displayId));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index dda0822..8eb1946 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -657,7 +657,7 @@
EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
}
-TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsCorrectly) {
+TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsAndDimmingRatioCorrectly) {
mOutputState.sdrWhitePointNits = 200.f;
mOutputState.displayBrightnessNits = 800.f;
@@ -665,12 +665,15 @@
mLayerFEState.isColorspaceAgnostic = false;
mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(mOutputState.sdrWhitePointNits, mOutputLayer.getState().whitePointNits);
+ EXPECT_EQ(mOutputState.sdrWhitePointNits / mOutputState.displayBrightnessNits,
+ mOutputLayer.getState().dimmingRatio);
mLayerFEState.dataspace = ui::Dataspace::BT2020_ITU_PQ;
mLayerFEState.isColorspaceAgnostic = false;
mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(mOutputState.displayBrightnessNits, mOutputLayer.getState().whitePointNits);
+ EXPECT_EQ(1.f, mOutputLayer.getState().dimmingRatio);
}
TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
@@ -750,9 +753,10 @@
static constexpr bool kLayerGenericMetadata1Mandatory = true;
static constexpr bool kLayerGenericMetadata2Mandatory = true;
static constexpr float kWhitePointNits = 200.f;
+ static constexpr float kSdrWhitePointNits = 100.f;
static constexpr float kDisplayBrightnessNits = 400.f;
static constexpr float kLayerBrightness = kWhitePointNits / kDisplayBrightnessNits;
- static constexpr float kFullLayerBrightness = 1.f;
+ static constexpr float kOverrideLayerBrightness = kSdrWhitePointNits / kDisplayBrightnessNits;
static const half4 kColor;
static const Rect kDisplayFrame;
@@ -798,6 +802,7 @@
mLayerFEState.acquireFence = kFence;
mOutputState.displayBrightnessNits = kDisplayBrightnessNits;
+ mOutputState.sdrWhitePointNits = kSdrWhitePointNits;
EXPECT_CALL(mOutput, getDisplayColorProfile())
.WillRepeatedly(Return(&mDisplayColorProfile));
@@ -1117,7 +1122,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kFullLayerBrightness);
+ kOverrideSurfaceDamage, kOverrideLayerBrightness);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1133,7 +1138,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kFullLayerBrightness);
+ kOverrideSurfaceDamage, kOverrideLayerBrightness);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1149,7 +1154,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kFullLayerBrightness);
+ kOverrideSurfaceDamage, kOverrideLayerBrightness);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1165,7 +1170,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kFullLayerBrightness);
+ kOverrideSurfaceDamage, kOverrideLayerBrightness);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 0c5ea79..66a9ef7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -28,7 +28,6 @@
#include <gtest/gtest.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/impl/ExternalTexture.h>
-#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -74,9 +73,6 @@
constexpr OutputColorSetting kVendorSpecifiedOutputColorSetting =
static_cast<OutputColorSetting>(0x100);
-using CompositionStrategyPredictionState = android::compositionengine::impl::
- OutputCompositionState::CompositionStrategyPredictionState;
-
struct OutputPartialMockBase : public impl::Output {
// compositionengine::Output overrides
const OutputCompositionState& getState() const override { return mState; }
@@ -993,7 +989,7 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_METHOD0(chooseCompositionStrategy, std::optional<DeviceRequestedChanges>());
+ MOCK_METHOD0(chooseCompositionStrategy, void());
};
OutputPrepareFrameTest() {
@@ -1024,7 +1020,6 @@
EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
mOutput.prepareFrame();
- EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED);
}
// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
@@ -1040,134 +1035,6 @@
EXPECT_TRUE(mOutput->getState().usesClientComposition);
EXPECT_FALSE(mOutput->getState().usesDeviceComposition);
- EXPECT_EQ(mOutput->getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED);
-}
-
-struct OutputPrepareFrameAsyncTest : public testing::Test {
- struct OutputPartialMock : public OutputPartialMockBase {
- // Sets up the helper functions called by the function under test to use
- // mock implementations.
- MOCK_METHOD0(chooseCompositionStrategy, std::optional<DeviceRequestedChanges>());
- MOCK_METHOD0(updateProtectedContentState, void());
- MOCK_METHOD2(dequeueRenderBuffer,
- bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
- MOCK_METHOD0(chooseCompositionStrategyAsync,
- std::future<std::optional<android::HWComposer::DeviceRequestedChanges>>());
- MOCK_METHOD4(composeSurfaces,
- std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&,
- std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
- };
-
- OutputPrepareFrameAsyncTest() {
- mOutput.setDisplayColorProfileForTest(
- std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
- mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
- }
-
- StrictMock<mock::CompositionEngine> mCompositionEngine;
- mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
- mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
- StrictMock<OutputPartialMock> mOutput;
- CompositionRefreshArgs mRefreshArgs;
-};
-
-TEST_F(OutputPrepareFrameAsyncTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
- mOutput.editState().isEnabled = true;
- mOutput.editState().usesClientComposition = false;
- mOutput.editState().usesDeviceComposition = true;
- mOutput.editState().previousDeviceRequestedChanges =
- std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
- std::promise<std::optional<android::HWComposer::DeviceRequestedChanges>> p;
- p.set_value(mOutput.editState().previousDeviceRequestedChanges);
-
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
- EXPECT_CALL(mOutput, updateProtectedContentState());
- EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
- EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
- EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); });
- EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
-
- impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
- EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::SUCCESS);
- EXPECT_FALSE(result.bufferAvailable());
-}
-
-TEST_F(OutputPrepareFrameAsyncTest, skipCompositionOnDequeueFailure) {
- mOutput.editState().isEnabled = true;
- mOutput.editState().usesClientComposition = false;
- mOutput.editState().usesDeviceComposition = true;
- mOutput.editState().previousDeviceRequestedChanges =
- std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
- std::promise<std::optional<android::HWComposer::DeviceRequestedChanges>> p;
- p.set_value(mOutput.editState().previousDeviceRequestedChanges);
-
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
- EXPECT_CALL(mOutput, updateProtectedContentState());
- EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(false));
- EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
- EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); });
-
- impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
- EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
- EXPECT_FALSE(result.bufferAvailable());
-}
-
-// Tests that in the event of hwc error when choosing composition strategy, we would fall back
-// client composition
-TEST_F(OutputPrepareFrameAsyncTest, chooseCompositionStrategyFailureCallsPrepareFrame) {
- mOutput.editState().isEnabled = true;
- mOutput.editState().usesClientComposition = false;
- mOutput.editState().usesDeviceComposition = true;
- mOutput.editState().previousDeviceRequestedChanges =
- std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
- std::promise<std::optional<android::HWComposer::DeviceRequestedChanges>> p;
- p.set_value({});
- std::shared_ptr<renderengine::ExternalTexture> tex =
- std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- 2);
-
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
- EXPECT_CALL(mOutput, updateProtectedContentState());
- EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
- .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true)));
- EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
- EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); });
- EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
-
- impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
- EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
- EXPECT_TRUE(result.bufferAvailable());
-}
-
-TEST_F(OutputPrepareFrameAsyncTest, predictionMiss) {
- mOutput.editState().isEnabled = true;
- mOutput.editState().usesClientComposition = false;
- mOutput.editState().usesDeviceComposition = true;
- mOutput.editState().previousDeviceRequestedChanges =
- std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
- auto newDeviceRequestedChanges =
- std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
- newDeviceRequestedChanges->clientTargetBrightness = 5.f;
- std::promise<std::optional<android::HWComposer::DeviceRequestedChanges>> p;
- p.set_value(newDeviceRequestedChanges);
- std::shared_ptr<renderengine::ExternalTexture> tex =
- std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- 2);
-
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
- EXPECT_CALL(mOutput, updateProtectedContentState());
- EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
- .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true)));
- EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
- EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); });
- EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
-
- impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
- EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
- EXPECT_TRUE(result.bufferAvailable());
}
/*
@@ -1443,6 +1310,7 @@
static const Region kLowerHalfBoundsNoRotation;
static const Region kFullBounds90Rotation;
static const Region kTransparentRegionHint;
+ static const Region kTransparentRegionHint90Rotation;
StrictMock<OutputPartialMock> mOutput;
LayerFESet mGeomSnapshots;
@@ -1461,7 +1329,9 @@
const Region OutputEnsureOutputLayerIfVisibleTest::kFullBounds90Rotation =
Region(Rect(0, 0, 200, 100));
const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHint =
- Region(Rect(0, 0, 100, 100));
+ Region(Rect(25, 20, 50, 75));
+const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHint90Rotation =
+ Region(Rect(125, 25, 180, 50));
TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
@@ -1912,6 +1782,24 @@
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;
+
+ 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(kTransparentRegionHint90Rotation));
+}
+
/*
* Output::present()
*/
@@ -1928,14 +1816,10 @@
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
- MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&));
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD2(finishFrame,
- void(const compositionengine::CompositionRefreshArgs&,
- GpuCompositionResult&&));
+ MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD1(renderCachedSets, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
};
StrictMock<OutputPartialMock> mOutput;
@@ -1951,30 +1835,9 @@
EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
EXPECT_CALL(mOutput, beginFrame());
- EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(false));
EXPECT_CALL(mOutput, prepareFrame());
EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
- EXPECT_CALL(mOutput, finishFrame(Ref(args), _));
- EXPECT_CALL(mOutput, postFramebuffer());
- EXPECT_CALL(mOutput, renderCachedSets(Ref(args)));
-
- mOutput.present(args);
-}
-
-TEST_F(OutputPresentTest, predictingCompositionStrategyInvokesPrepareFrameAsync) {
- CompositionRefreshArgs args;
-
- InSequence seq;
- EXPECT_CALL(mOutput, updateColorProfile(Ref(args)));
- EXPECT_CALL(mOutput, updateCompositionState(Ref(args)));
- EXPECT_CALL(mOutput, planComposition());
- EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
- EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
- EXPECT_CALL(mOutput, beginFrame());
- EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(true));
- EXPECT_CALL(mOutput, prepareFrameAsync(Ref(args)));
- EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
- EXPECT_CALL(mOutput, finishFrame(Ref(args), _));
+ EXPECT_CALL(mOutput, finishFrame(Ref(args)));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, renderCachedSets(Ref(args)));
@@ -2872,15 +2735,11 @@
// Sets up the helper functions called by the function under test to use
// mock implementations.
MOCK_METHOD(Region, getDirtyRegion, (), (const));
- MOCK_METHOD4(composeSurfaces,
+ MOCK_METHOD2(composeSurfaces,
std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&,
- std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
+ const Region&, const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD0(prepareFrame, void());
- MOCK_METHOD0(updateProtectedContentState, void());
- MOCK_METHOD2(dequeueRenderBuffer,
- bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
};
OutputDevOptRepaintFlashTest() {
@@ -2937,9 +2796,7 @@
InSequence seq;
EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion));
- EXPECT_CALL(mOutput, updateProtectedContentState());
- EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _));
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs), _, _));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs)));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, prepareFrame());
@@ -2955,14 +2812,10 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_METHOD4(composeSurfaces,
+ MOCK_METHOD2(composeSurfaces,
std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&,
- std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
+ const Region&, const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD0(postFramebuffer, void());
- MOCK_METHOD0(updateProtectedContentState, void());
- MOCK_METHOD2(dequeueRenderBuffer,
- bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
};
OutputFinishFrameTest() {
@@ -2980,62 +2833,27 @@
TEST_F(OutputFinishFrameTest, ifNotEnabledDoesNothing) {
mOutput.mState.isEnabled = false;
- impl::GpuCompositionResult result;
- mOutput.finishFrame(mRefreshArgs, std::move(result));
+ mOutput.finishFrame(mRefreshArgs);
}
TEST_F(OutputFinishFrameTest, takesEarlyOutifComposeSurfacesReturnsNoFence) {
mOutput.mState.isEnabled = true;
- EXPECT_CALL(mOutput, updateProtectedContentState());
- EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _));
- impl::GpuCompositionResult result;
- mOutput.finishFrame(mRefreshArgs, std::move(result));
+ InSequence seq;
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _));
+
+ mOutput.finishFrame(mRefreshArgs);
}
TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) {
mOutput.mState.isEnabled = true;
InSequence seq;
- EXPECT_CALL(mOutput, updateProtectedContentState());
- EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _))
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _))
.WillOnce(Return(ByMove(base::unique_fd())));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
- impl::GpuCompositionResult result;
- mOutput.finishFrame(mRefreshArgs, std::move(result));
-}
-
-TEST_F(OutputFinishFrameTest, predictionSucceeded) {
- mOutput.mState.isEnabled = true;
- mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::SUCCESS;
- InSequence seq;
- EXPECT_CALL(*mRenderSurface, queueBuffer(_));
-
- impl::GpuCompositionResult result;
- mOutput.finishFrame(mRefreshArgs, std::move(result));
-}
-
-TEST_F(OutputFinishFrameTest, predictionFailedAndBufferIsReused) {
- mOutput.mState.isEnabled = true;
- mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::FAIL;
-
- InSequence seq;
-
- impl::GpuCompositionResult result;
- result.buffer =
- std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- 2);
-
- EXPECT_CALL(mOutput,
- composeSurfaces(RegionEq(Region::INVALID_REGION), _, result.buffer,
- Eq(ByRef(result.fence))))
- .WillOnce(Return(ByMove(base::unique_fd())));
- EXPECT_CALL(*mRenderSurface, queueBuffer(_));
- mOutput.finishFrame(mRefreshArgs, std::move(result));
+ mOutput.finishFrame(mRefreshArgs);
}
/*
@@ -3282,15 +3100,8 @@
struct ExecuteState : public CallOrderStateMachineHelper<TestType, ExecuteState> {
auto execute() {
- base::unique_fd fence;
- std::shared_ptr<renderengine::ExternalTexture> externalTexture;
- const bool success =
- getInstance()->mOutput.dequeueRenderBuffer(&fence, &externalTexture);
- if (success) {
- getInstance()->mReadyFence =
- getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs,
- externalTexture, fence);
- }
+ getInstance()->mReadyFence =
+ getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
return nextState<FenceCheckState>();
}
};
@@ -3851,11 +3662,7 @@
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
EXPECT_CALL(mRenderEngine, useProtectedContext(false));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) {
@@ -3863,11 +3670,7 @@
mLayer2.mLayerFEState.hasProtectedContent = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) {
@@ -3879,11 +3682,7 @@
EXPECT_CALL(mRenderEngine, useProtectedContext(false));
EXPECT_CALL(*mRenderSurface, setProtected(false));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) {
@@ -3905,11 +3704,7 @@
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) {
@@ -3919,11 +3714,7 @@
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) {
@@ -3934,11 +3725,7 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
EXPECT_CALL(mRenderEngine, useProtectedContext(true));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) {
@@ -3949,11 +3736,7 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
EXPECT_CALL(*mRenderSurface, setProtected(true));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) {
@@ -3964,11 +3747,7 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true));
EXPECT_CALL(mRenderEngine, useProtectedContext(true));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSurfacesTest {
@@ -3986,8 +3765,9 @@
TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDataspaceIsUsed) {
mOutput.mState.dataspace = kExpensiveOutputDataspace;
+ LayerFE::LayerSettings layerSettings;
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kExpensiveOutputDataspace, _))
- .WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>{layerSettings}));
// For this test, we also check the call order of key functions.
InSequence seq;
@@ -3997,11 +3777,7 @@
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur
@@ -4036,12 +3812,7 @@
mOutput.writeCompositionState(mRefreshArgs);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
-
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, mRefreshArgs);
}
TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotExpensive) {
@@ -4051,12 +3822,7 @@
mOutput.writeCompositionState(mRefreshArgs);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(0);
-
- base::unique_fd fd;
- std::shared_ptr<renderengine::ExternalTexture> tex;
- mOutput.updateProtectedContentState();
- mOutput.dequeueRenderBuffer(&fd, &tex);
- mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd);
+ mOutput.composeSurfaces(kDebugRegion, mRefreshArgs);
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 4ae921d..8a99e4e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -539,6 +539,8 @@
TEST_F(CachedSetTest, holePunch_requiresBuffer) {
CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
+ layerFECompositionState.blendMode = hal::BlendMode::NONE;
sp<mock::LayerFE> layerFE1 = mTestLayers[0]->layerFE;
CachedSet cachedSet(layer1);
@@ -549,7 +551,9 @@
TEST_F(CachedSetTest, holePunch_requiresRoundedCorners) {
CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
- mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ layerFECompositionState.blendMode = hal::BlendMode::NONE;
CachedSet cachedSet(layer1);
@@ -558,7 +562,9 @@
TEST_F(CachedSetTest, holePunch_requiresSingleLayer) {
CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
- mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ layerFECompositionState.blendMode = hal::BlendMode::NONE;
sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
EXPECT_CALL(*layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
@@ -575,7 +581,9 @@
mTestLayers[0]->layerState->update(&mTestLayers[0]->outputLayer);
CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
- mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ layerFECompositionState.blendMode = hal::BlendMode::NONE;
sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
CachedSet cachedSet(layer);
@@ -589,7 +597,22 @@
mTestLayers[0]->layerState->update(&mTestLayers[0]->outputLayer);
CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
- mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ layerFECompositionState.blendMode = hal::BlendMode::NONE;
+ sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
+
+ CachedSet cachedSet(layer);
+ EXPECT_CALL(*layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ EXPECT_FALSE(cachedSet.requiresHolePunch());
+}
+
+TEST_F(CachedSetTest, holePunch_requiresNoBlending) {
+ CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
+ auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ layerFECompositionState.blendMode = hal::BlendMode::PREMULTIPLIED;
sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
CachedSet cachedSet(layer);
@@ -600,7 +623,9 @@
TEST_F(CachedSetTest, requiresHolePunch) {
CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
- mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ layerFECompositionState.blendMode = hal::BlendMode::NONE;
sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
CachedSet cachedSet(layer);
@@ -614,6 +639,7 @@
sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ layerFECompositionState.blendMode = hal::BlendMode::NONE;
layerFECompositionState.forceClientComposition = true;
CachedSet cachedSet(layer);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 656ef9a..96c28c9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -633,6 +633,7 @@
auto& layerState3 = mTestLayers[2]->layerState;
const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
+ mTestLayers[2]->layerFECompositionState.blendMode = hal::BlendMode::NONE;
EXPECT_CALL(*mTestLayers[2]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
@@ -706,6 +707,7 @@
// a rounded updating layer
auto& layerState1 = mTestLayers[1]->layerState;
const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+ mTestLayers[1]->layerFECompositionState.blendMode = hal::BlendMode::NONE;
EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
@@ -777,6 +779,7 @@
// a rounded updating layer
auto& layerState1 = mTestLayers[1]->layerState;
const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+ mTestLayers[1]->layerFECompositionState.blendMode = hal::BlendMode::NONE;
EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 610d86f..45b98bb 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -91,7 +91,6 @@
static_cast<uint32_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers));
}
- mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy);
mCompositionDisplay->createDisplayColorProfile(
compositionengine::DisplayColorProfileCreationArgsBuilder()
.setHasWideColorGamut(args.hasWideColorGamut)
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 80e2d99..92592f7 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -248,6 +248,7 @@
case OptionalFeature::ExpectedPresentTime:
case OptionalFeature::DisplayBrightnessCommand:
case OptionalFeature::BootDisplayConfig:
+ case OptionalFeature::KernelIdleTimer:
return true;
}
}
@@ -475,6 +476,19 @@
return Error::NONE;
}
+Error AidlComposer::hasDisplayIdleTimerCapability(Display display, bool* outSupport) {
+ std::vector<AidlDisplayCapability> capabilities;
+ const auto status =
+ mAidlComposerClient->getDisplayCapabilities(translate<int64_t>(display), &capabilities);
+ if (!status.isOk()) {
+ ALOGE("getDisplayCapabilities failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *outSupport = std::find(capabilities.begin(), capabilities.end(),
+ AidlDisplayCapability::DISPLAY_IDLE_TIMER) != capabilities.end();
+ return Error::NONE;
+}
+
Error AidlComposer::getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
float* outMaxLuminance, float* outMaxAverageLuminance,
float* outMinLuminance) {
@@ -1100,5 +1114,17 @@
}
return Error::NONE;
}
+
+Error AidlComposer::setIdleTimerEnabled(Display displayId, std::chrono::milliseconds timeout) {
+ const auto status =
+ mAidlComposerClient->setIdleTimerEnabled(translate<int64_t>(displayId),
+ translate<int32_t>(timeout.count()));
+ if (!status.isOk()) {
+ ALOGE("setIdleTimerEnabled 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 80ca8da..6c0f636 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -100,6 +100,7 @@
std::vector<uint32_t>* outLayerRequestMasks) override;
Error getDozeSupport(Display display, bool* outSupport) override;
+ Error hasDisplayIdleTimerCapability(Display display, bool* outSupport) override;
Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
float* outMaxAverageLuminance, float* outMinLuminance) override;
@@ -220,6 +221,7 @@
Error getPreferredBootDisplayConfig(Display displayId, Config*) override;
Error getDisplayDecorationSupport(Display display,
std::optional<DisplayDecorationSupport>* support) override;
+ Error setIdleTimerEnabled(Display displayId, std::chrono::milliseconds timeout) override;
private:
// Many public functions above simply write a command into the command
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 23886d4..6abe7d1 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -93,6 +93,7 @@
// Whether setDisplayBrightness is able to be applied as part of a display command.
DisplayBrightnessCommand,
BootDisplayConfig,
+ KernelIdleTimer,
};
virtual bool isSupported(OptionalFeature) const = 0;
@@ -134,6 +135,7 @@
std::vector<uint32_t>* outLayerRequestMasks) = 0;
virtual Error getDozeSupport(Display display, bool* outSupport) = 0;
+ virtual Error hasDisplayIdleTimerCapability(Display display, bool* outSupport) = 0;
virtual Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
float* outMaxLuminance, float* outMaxAverageLuminance,
float* outMinLuminance) = 0;
@@ -274,6 +276,7 @@
Display display,
std::optional<::aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
+ virtual Error setIdleTimerEnabled(Display displayId, std::chrono::milliseconds timeout) = 0;
};
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index a1b663c..6501276 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -148,6 +148,12 @@
return mComposer.isSupported(android::Hwc2::Composer::OptionalFeature::RefreshRateSwitching);
}
+bool Display::hasDisplayIdleTimerCapability() const {
+ bool isCapabilitySupported = false;
+ return mComposer.hasDisplayIdleTimerCapability(mId, &isCapabilitySupported) == Error::NONE &&
+ isCapabilitySupported;
+}
+
Error Display::getChangedCompositionTypes(std::unordered_map<HWC2::Layer*, Composition>* outTypes) {
std::vector<Hwc2::Layer> layerIds;
std::vector<Composition> types;
@@ -588,6 +594,11 @@
return static_cast<Error>(error);
}
+Error Display::setIdleTimerEnabled(std::chrono::milliseconds timeout) {
+ const auto error = mComposer.setIdleTimerEnabled(mId, timeout);
+ return static_cast<Error>(error);
+}
+
// For use by Device
void Display::setConnected(bool connected) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 334d6ec..c03cede 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -91,6 +91,7 @@
virtual bool hasCapability(
aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0;
virtual bool isVsyncPeriodSwitchSupported() const = 0;
+ virtual bool hasDisplayIdleTimerCapability() const = 0;
virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0;
[[clang::warn_unused_result]] virtual hal::Error acceptChanges() = 0;
@@ -166,6 +167,8 @@
[[clang::warn_unused_result]] 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;
};
namespace impl {
@@ -242,6 +245,7 @@
hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
+ hal::Error setIdleTimerEnabled(std::chrono::milliseconds timeout) override;
// Other Display methods
hal::HWDisplayId getId() const override { return mId; }
@@ -250,6 +254,7 @@
bool hasCapability(aidl::android::hardware::graphics::composer3::DisplayCapability)
const override EXCLUDES(mDisplayCapabilitiesMutex);
bool isVsyncPeriodSwitchSupported() const override;
+ bool hasDisplayIdleTimerCapability() const override;
void onLayerDestroyed(hal::HWLayerId layerId) override;
private:
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index ed6e4b0..02b3772 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -971,6 +971,26 @@
}
}
+status_t HWComposer::setIdleTimerEnabled(PhysicalDisplayId displayId,
+ std::chrono::milliseconds timeout) {
+ ATRACE_CALL();
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto error = mDisplayData[displayId].hwcDisplay->setIdleTimerEnabled(timeout);
+ if (error == hal::Error::UNSUPPORTED) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == hal::Error::BAD_PARAMETER) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return NO_ERROR;
+}
+
+bool HWComposer::hasDisplayIdleTimerCapability(PhysicalDisplayId displayId) {
+ RETURN_IF_INVALID_DISPLAY(displayId, false);
+ return mDisplayData[displayId].hwcDisplay->hasDisplayIdleTimerCapability();
+}
+
void HWComposer::loadLayerMetadataSupport() {
mSupportedLayerGenericMetadata.clear();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index a8d439b..f9637f0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -267,16 +267,10 @@
PhysicalDisplayId,
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;
};
-static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs,
- const android::HWComposer::DeviceRequestedChanges& rhs) {
- return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests &&
- lhs.layerRequests == rhs.layerRequests &&
- lhs.clientTargetProperty == rhs.clientTargetProperty &&
- lhs.clientTargetBrightness == rhs.clientTargetBrightness;
-}
-
namespace impl {
class HWComposer final : public android::HWComposer {
@@ -410,6 +404,8 @@
PhysicalDisplayId,
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
+ status_t setIdleTimerEnabled(PhysicalDisplayId, std::chrono::milliseconds timeout) override;
+ bool hasDisplayIdleTimerCapability(PhysicalDisplayId) 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 f735bba..33adceb 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -236,6 +236,7 @@
case OptionalFeature::ExpectedPresentTime:
case OptionalFeature::DisplayBrightnessCommand:
case OptionalFeature::BootDisplayConfig:
+ case OptionalFeature::KernelIdleTimer:
return false;
}
}
@@ -487,6 +488,11 @@
return error;
}
+Error HidlComposer::hasDisplayIdleTimerCapability(Display, bool*) {
+ LOG_ALWAYS_FATAL("hasDisplayIdleTimerCapability should have never been called on this as "
+ "OptionalFeature::KernelIdleTimer is not supported on HIDL");
+}
+
Error HidlComposer::getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
float* outMaxLuminance, float* outMaxAverageLuminance,
float* outMinLuminance) {
@@ -1320,6 +1326,11 @@
return Error::UNSUPPORTED;
}
+Error HidlComposer::setIdleTimerEnabled(Display, std::chrono::milliseconds) {
+ LOG_ALWAYS_FATAL("setIdleTimerEnabled should have never been called on this as "
+ "OptionalFeature::KernelIdleTimer 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 c2b60cb..a1ea4f2 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -208,6 +208,7 @@
std::vector<uint32_t>* outLayerRequestMasks) override;
Error getDozeSupport(Display display, bool* outSupport) override;
+ Error hasDisplayIdleTimerCapability(Display display, bool* outSupport) override;
Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
float* outMaxAverageLuminance, float* outMinLuminance) override;
@@ -331,6 +332,7 @@
Display display,
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
+ Error setIdleTimerEnabled(Display displayId, std::chrono::milliseconds timeout) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index e21095a..307da41 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -89,9 +89,6 @@
virtual void dumpAsString(String8& result) const;
virtual void resizeBuffers(const ui::Size&) override;
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
- // Virtual display surface needs to prepare the frame based on composition type. Skip
- // any client composition prediction.
- virtual bool supportsCompositionStrategyPrediction() const override { return false; };
private:
enum Source : size_t {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2b5e337..48a9bc5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2007 The Android Open Source Project
*
@@ -1049,7 +1048,7 @@
mutable bool mDrawingStateModified = false;
sp<Fence> mLastClientCompositionFence;
- bool mLastClientCompositionDisplayed = false;
+ bool mAlreadyDisplayedThisCompose = false;
private:
virtual void setTransformHint(ui::Transform::RotationFlags) {}
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/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 15e30b3..65c8613 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -670,9 +670,9 @@
}
void RefreshRateConfigs::initializeIdleTimer() {
- if (mConfig.idleTimerTimeoutMs > 0) {
+ if (mConfig.idleTimerTimeout > 0ms) {
mIdleTimer.emplace(
- "IdleTimer", std::chrono::milliseconds(mConfig.idleTimerTimeoutMs),
+ "IdleTimer", mConfig.idleTimerTimeout,
[this] {
std::scoped_lock lock(mIdleTimerCallbacksMutex);
if (const auto callbacks = getIdleTimerCallbacks()) {
@@ -963,12 +963,24 @@
base::StringAppendF(&result, "Supports Frame Rate Override By Content: %s\n",
mSupportsFrameRateOverrideByContent ? "yes" : "no");
- base::StringAppendF(&result, "Idle timer: (%s) %s\n",
- mConfig.supportKernelIdleTimer ? "kernel" : "platform",
- mIdleTimer ? mIdleTimer->dump().c_str() : "off");
+ 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))");
+ }
+ } else {
+ base::StringAppendF(&result, "(platform)");
+ }
+ base::StringAppendF(&result, " %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : "off");
result.append("\n");
}
+std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() {
+ return mConfig.idleTimerTimeout;
+}
+
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 14583e3..30d3edd 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -272,6 +272,8 @@
// Returns a known frame rate that is the closest to frameRate
Fps findClosestKnownFrameRate(Fps frameRate) const;
+ enum class KernelIdleTimerController { Sysprop, HwcApi };
+
// Configuration flags.
struct Config {
bool enableFrameRateOverride = false;
@@ -282,17 +284,18 @@
int frameRateMultipleThreshold = 0;
// The Idle Timer timeout. 0 timeout means no idle timer.
- int32_t idleTimerTimeoutMs = 0;
+ std::chrono::milliseconds idleTimerTimeout = 0ms;
- // Whether to use idle timer callbacks that support the kernel timer.
- bool supportKernelIdleTimer = false;
+ // The controller representing how the kernel idle timer will be configured
+ // either on the HWC api or sysprop.
+ std::optional<KernelIdleTimerController> kernelIdleTimerController;
};
RefreshRateConfigs(const DisplayModes&, DisplayModeId,
Config config = {.enableFrameRateOverride = false,
.frameRateMultipleThreshold = 0,
- .idleTimerTimeoutMs = 0,
- .supportKernelIdleTimer = false});
+ .idleTimerTimeout = 0ms,
+ .kernelIdleTimerController = {}});
RefreshRateConfigs(const RefreshRateConfigs&) = delete;
RefreshRateConfigs& operator=(const RefreshRateConfigs&) = delete;
@@ -310,6 +313,7 @@
TurnOff, // Turn off the idle timer.
TurnOn // Turn on the idle timer.
};
+
// Checks whether kernel idle timer should be active depending the policy decisions around
// refresh rates.
KernelIdleTimerAction getIdleTimerAction() const;
@@ -332,7 +336,9 @@
Fps displayFrameRate, GlobalSignals) const
EXCLUDES(mLock);
- bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; }
+ std::optional<KernelIdleTimerController> kernelIdleTimerController() {
+ return mConfig.kernelIdleTimerController;
+ }
struct IdleTimerCallbacks {
struct Callbacks {
@@ -370,7 +376,7 @@
if (!mIdleTimer) {
return;
}
- if (kernelOnly && !mConfig.supportKernelIdleTimer) {
+ if (kernelOnly && !mConfig.kernelIdleTimerController.has_value()) {
return;
}
mIdleTimer->reset();
@@ -378,6 +384,8 @@
void dump(std::string& result) const EXCLUDES(mLock);
+ std::chrono::milliseconds getIdleTimerTimeout();
+
private:
friend struct TestableRefreshRateConfigs;
@@ -437,8 +445,8 @@
std::optional<IdleTimerCallbacks::Callbacks> getIdleTimerCallbacks() const
REQUIRES(mIdleTimerCallbacksMutex) {
if (!mIdleTimerCallbacks) return {};
- return mConfig.supportKernelIdleTimer ? mIdleTimerCallbacks->kernel
- : mIdleTimerCallbacks->platform;
+ return mConfig.kernelIdleTimerController.has_value() ? mIdleTimerCallbacks->kernel
+ : mIdleTimerCallbacks->platform;
}
// The list of refresh rates, indexed by display modes ID. This may change after this
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d1ac1d3..bd831ff 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -169,8 +169,8 @@
using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
-using CompositionStrategyPredictionState = android::compositionengine::impl::
- OutputCompositionState::CompositionStrategyPredictionState;
+using KernelIdleTimerController =
+ ::android::scheduler::RefreshRateConfigs::KernelIdleTimerController;
namespace android {
@@ -272,39 +272,33 @@
return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
}
-
-struct IdleTimerConfig {
- int32_t timeoutMs;
- bool supportKernelIdleTimer;
-};
-
-IdleTimerConfig getIdleTimerConfiguration(DisplayId displayId) {
- // TODO(adyabr): use ro.surface_flinger.* namespace
-
+std::chrono::milliseconds getIdleTimerTimeout(DisplayId displayId) {
const auto displayIdleTimerMsKey = [displayId] {
std::stringstream ss;
ss << "debug.sf.set_idle_timer_ms_" << displayId.value;
return ss.str();
}();
+ const int32_t displayIdleTimerMs = base::GetIntProperty(displayIdleTimerMsKey, 0);
+ if (displayIdleTimerMs > 0) {
+ return std::chrono::milliseconds(displayIdleTimerMs);
+ }
+
+ const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms", 0);
+ const int32_t millis = setIdleTimerMs ? setIdleTimerMs : sysprop::set_idle_timer_ms(0);
+ return std::chrono::milliseconds(millis);
+}
+
+bool getKernelIdleTimerSyspropConfig(DisplayId displayId) {
const auto displaySupportKernelIdleTimerKey = [displayId] {
std::stringstream ss;
ss << "debug.sf.support_kernel_idle_timer_" << displayId.value;
return ss.str();
}();
- const int32_t displayIdleTimerMs = base::GetIntProperty(displayIdleTimerMsKey, 0);
const auto displaySupportKernelIdleTimer =
base::GetBoolProperty(displaySupportKernelIdleTimerKey, false);
-
- if (displayIdleTimerMs > 0) {
- return {displayIdleTimerMs, displaySupportKernelIdleTimer};
- }
-
- const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms", 0);
- const int32_t millis = setIdleTimerMs ? setIdleTimerMs : sysprop::set_idle_timer_ms(0);
-
- return {millis, sysprop::support_kernel_idle_timer(false)};
+ return displaySupportKernelIdleTimer || sysprop::support_kernel_idle_timer(false);
}
} // namespace anonymous
@@ -482,9 +476,6 @@
property_get("debug.sf.disable_client_composition_cache", value, "0");
mDisableClientCompositionCache = atoi(value);
- property_get("debug.sf.predict_hwc_composition_strategy", value, "1");
- mPredictCompositionStrategy = atoi(value);
-
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -2272,24 +2263,24 @@
const bool prevFrameHadClientComposition = mHadClientComposition;
- mHadClientComposition = mHadDeviceComposition = mReusedClientComposition = false;
- TimeStats::ClientCompositionRecord clientCompositionRecord;
- for (const auto& [_, display] : displays) {
- const auto& state = display->getCompositionDisplay()->getState();
- mHadClientComposition |= state.usesClientComposition && !state.reusedClientComposition;
- mHadDeviceComposition |= state.usesDeviceComposition;
- mReusedClientComposition |= state.reusedClientComposition;
- clientCompositionRecord.predicted |=
- (state.strategyPrediction != CompositionStrategyPredictionState::DISABLED);
- clientCompositionRecord.predictionSucceeded |=
- (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS);
+ mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
+ const auto& state = pair.second->getCompositionDisplay()->getState();
+ return state.usesClientComposition && !state.reusedClientComposition;
+ });
+ mHadDeviceComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
+ const auto& state = pair.second->getCompositionDisplay()->getState();
+ return state.usesDeviceComposition;
+ });
+ mReusedClientComposition =
+ std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
+ const auto& state = pair.second->getCompositionDisplay()->getState();
+ return state.reusedClientComposition;
+ });
+ // Only report a strategy change if we move in and out of client composition
+ if (prevFrameHadClientComposition != mHadClientComposition) {
+ mTimeStats->incrementCompositionStrategyChanges();
}
- clientCompositionRecord.hadClientComposition = mHadClientComposition;
- clientCompositionRecord.reused = mReusedClientComposition;
- clientCompositionRecord.changed = prevFrameHadClientComposition != mHadClientComposition;
- mTimeStats->pushCompositionStrategyState(clientCompositionRecord);
-
// TODO: b/160583065 Enable skip validation when SF caches all client composition layers
const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition;
modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
@@ -2544,6 +2535,13 @@
}
mTimeStats->incrementTotalFrames();
+ if (mHadClientComposition) {
+ mTimeStats->incrementClientCompositionFrames();
+ }
+
+ if (mReusedClientComposition) {
+ mTimeStats->incrementClientCompositionReusedFrames();
+ }
mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
@@ -2827,14 +2825,15 @@
creationArgs.connectionType = physical->type;
creationArgs.supportedModes = physical->supportedModes;
creationArgs.activeModeId = physical->activeMode->getId();
- const auto [idleTimerTimeoutMs, supportKernelIdleTimer] =
- getIdleTimerConfiguration(compositionDisplay->getId());
+ const auto [kernelIdleTimerController, idleTimerTimeoutMs] =
+ getKernelIdleTimerProperties(compositionDisplay->getId());
+
scheduler::RefreshRateConfigs::Config config =
{.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
.frameRateMultipleThreshold =
base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0),
- .idleTimerTimeoutMs = idleTimerTimeoutMs,
- .supportKernelIdleTimer = supportKernelIdleTimer};
+ .idleTimerTimeout = idleTimerTimeoutMs,
+ .kernelIdleTimerController = kernelIdleTimerController};
creationArgs.refreshRateConfigs =
std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes,
creationArgs.activeModeId, config);
@@ -3408,7 +3407,7 @@
features);
{
auto configs = display->holdRefreshRateConfigs();
- if (configs->supportsKernelIdleTimer()) {
+ if (configs->kernelIdleTimerController().has_value()) {
features |= Feature::kKernelIdleTimer;
}
@@ -5437,7 +5436,9 @@
/*
* Dump flag/property manager state
*/
- mFlagManager->dump(result);
+ if (mFlagManager != nullptr) {
+ mFlagManager->dump(result);
+ }
result.append(mTimeStats->miniDump());
result.append("\n");
@@ -6146,6 +6147,47 @@
}));
}
+std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds>
+SurfaceFlinger::getKernelIdleTimerProperties(DisplayId displayId) {
+ const bool isKernelIdleTimerHwcSupported = getHwComposer().getComposer()->isSupported(
+ android::Hwc2::Composer::OptionalFeature::KernelIdleTimer);
+ const auto timeout = getIdleTimerTimeout(displayId);
+ if (isKernelIdleTimerHwcSupported) {
+ if (const auto id = PhysicalDisplayId::tryCast(displayId);
+ getHwComposer().hasDisplayIdleTimerCapability(*id)) {
+ // In order to decide if we can use the HWC api for idle timer
+ // we query DisplayCapability::DISPLAY_IDLE_TIMER directly on the composer
+ // without relying on hasDisplayCapability.
+ // hasDisplayCapability relies on DisplayCapabilities
+ // which are updated after we set the PowerMode::ON.
+ // DISPLAY_IDLE_TIMER is a display driver property
+ // and is available before the PowerMode::ON
+ return {KernelIdleTimerController::HwcApi, timeout};
+ }
+ return {std::nullopt, timeout};
+ }
+ if (getKernelIdleTimerSyspropConfig(displayId)) {
+ return {KernelIdleTimerController::Sysprop, timeout};
+ }
+
+ return {std::nullopt, timeout};
+}
+
+void SurfaceFlinger::updateKernelIdleTimer(std::chrono::milliseconds timeout,
+ KernelIdleTimerController controller,
+ PhysicalDisplayId displayId) {
+ switch (controller) {
+ case KernelIdleTimerController::HwcApi: {
+ getHwComposer().setIdleTimerEnabled(displayId, timeout);
+ break;
+ }
+ case KernelIdleTimerController::Sysprop: {
+ base::SetProperty(KERNEL_IDLE_TIMER_PROP, timeout > 0ms ? "true" : "false");
+ break;
+ }
+ }
+}
+
void SurfaceFlinger::toggleKernelIdleTimer() {
using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
@@ -6157,23 +6199,31 @@
// If the support for kernel idle timer is disabled for the active display,
// don't do anything.
- if (!display->refreshRateConfigs().supportsKernelIdleTimer()) {
+ const std::optional<KernelIdleTimerController> kernelIdleTimerController =
+ display->refreshRateConfigs().kernelIdleTimerController();
+ if (!kernelIdleTimerController.has_value()) {
return;
}
const KernelIdleTimerAction action = display->refreshRateConfigs().getIdleTimerAction();
+
switch (action) {
case KernelIdleTimerAction::TurnOff:
if (mKernelIdleTimerEnabled) {
ATRACE_INT("KernelIdleTimer", 0);
- base::SetProperty(KERNEL_IDLE_TIMER_PROP, "false");
+ std::chrono::milliseconds constexpr kTimerDisabledTimeout = 0ms;
+ updateKernelIdleTimer(kTimerDisabledTimeout, kernelIdleTimerController.value(),
+ display->getPhysicalId());
mKernelIdleTimerEnabled = false;
}
break;
case KernelIdleTimerAction::TurnOn:
if (!mKernelIdleTimerEnabled) {
ATRACE_INT("KernelIdleTimer", 1);
- base::SetProperty(KERNEL_IDLE_TIMER_PROP, "true");
+ const std::chrono::milliseconds timeout =
+ display->refreshRateConfigs().getIdleTimerTimeout();
+ updateKernelIdleTimer(timeout, kernelIdleTimerController.value(),
+ display->getPhysicalId());
mKernelIdleTimerEnabled = true;
}
break;
@@ -6451,19 +6501,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
@@ -6592,7 +6629,7 @@
renderArea->render([&] {
renderEngineResultFuture =
- renderScreenImplLocked(*renderArea, traverseLayers, buffer,
+ renderScreenImpl(*renderArea, traverseLayers, buffer,
canCaptureBlackoutContent, regionSampling, grayscale,
captureResults);
});
@@ -6625,7 +6662,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,
@@ -6649,7 +6686,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();
@@ -6667,7 +6719,7 @@
clientCompositionDisplay.clip = sourceCrop;
clientCompositionDisplay.orientation = rotation;
- clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
+ clientCompositionDisplay.outputDataspace = dataspace;
clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
const float colorSaturation = grayscale ? 0 : 1;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 86c8333..81afa9b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -344,11 +344,6 @@
void disableExpensiveRendering();
FloatRect getMaxDisplayBounds();
- // If set, composition engine tries to predict the composition strategy provided by HWC
- // based on the previous frame. If the strategy can be predicted, gpu composition will
- // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect.
- bool mPredictCompositionStrategy = false;
-
protected:
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -380,6 +375,7 @@
friend class MonitoredProducer;
friend class RefreshRateOverlay;
friend class RegionSamplingThread;
+ friend class LayerRenderArea;
friend class LayerTracing;
// For unit tests
@@ -467,6 +463,8 @@
};
using ActiveModeInfo = DisplayDevice::ActiveModeInfo;
+ using KernelIdleTimerController =
+ ::android::scheduler::RefreshRateConfigs::KernelIdleTimerController;
enum class BootStage {
BOOTLOADER,
@@ -690,6 +688,14 @@
void triggerOnFrameRateOverridesChanged() override;
// Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
void toggleKernelIdleTimer() REQUIRES(mStateLock);
+ // Get the controller and timeout that will help decide how the kernel idle timer will be
+ // configured and what value to use as the timeout.
+ std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds>
+ getKernelIdleTimerProperties(DisplayId) REQUIRES(mStateLock);
+ // Updates the kernel idle timer either through HWC or through sysprop
+ // depending on which controller is provided
+ void updateKernelIdleTimer(std::chrono::milliseconds timeoutMs, KernelIdleTimerController,
+ PhysicalDisplayId) REQUIRES(mStateLock);
// Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
// make calls to sys prop each time.
bool mKernelIdleTimerEnabled = false;
@@ -858,10 +864,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
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index e5a9dd4..b1a2bda 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -321,19 +321,22 @@
mTimeStats.missedFramesLegacy++;
}
-void TimeStats::pushCompositionStrategyState(const TimeStats::ClientCompositionRecord& record) {
- if (!mEnabled.load() || !record.hasInterestingData()) {
- return;
- }
+void TimeStats::incrementClientCompositionFrames() {
+ if (!mEnabled.load()) return;
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (record.changed) mTimeStats.compositionStrategyChangesLegacy++;
- if (record.hadClientComposition) mTimeStats.clientCompositionFramesLegacy++;
- if (record.reused) mTimeStats.clientCompositionReusedFramesLegacy++;
- if (record.predicted) mTimeStats.compositionStrategyPredictedLegacy++;
- if (record.predictionSucceeded) mTimeStats.compositionStrategyPredictionSucceededLegacy++;
+ mTimeStats.clientCompositionFramesLegacy++;
+}
+
+void TimeStats::incrementClientCompositionReusedFrames() {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStats.clientCompositionReusedFramesLegacy++;
}
void TimeStats::incrementRefreshRateSwitches() {
@@ -345,6 +348,15 @@
mTimeStats.refreshRateSwitchesLegacy++;
}
+void TimeStats::incrementCompositionStrategyChanges() {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStats.compositionStrategyChangesLegacy++;
+}
+
void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
if (!mEnabled.load()) return;
@@ -1050,10 +1062,8 @@
mTimeStats.missedFramesLegacy = 0;
mTimeStats.clientCompositionFramesLegacy = 0;
mTimeStats.clientCompositionReusedFramesLegacy = 0;
- mTimeStats.compositionStrategyChangesLegacy = 0;
- mTimeStats.compositionStrategyPredictedLegacy = 0;
- mTimeStats.compositionStrategyPredictionSucceededLegacy = 0;
mTimeStats.refreshRateSwitchesLegacy = 0;
+ mTimeStats.compositionStrategyChangesLegacy = 0;
mTimeStats.displayEventConnectionsCountLegacy = 0;
mTimeStats.displayOnTimeLegacy = 0;
mTimeStats.presentToPresentLegacy.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 7a159b8..77c7973 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -45,7 +45,7 @@
virtual ~TimeStats() = default;
// Process a pull request from statsd.
- virtual bool onPullAtom(const int atomId, std::string* pulledData) = 0;
+ virtual bool onPullAtom(const int atomId, std::string* pulledData);
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
@@ -53,8 +53,14 @@
virtual void incrementTotalFrames() = 0;
virtual void incrementMissedFrames() = 0;
+ virtual void incrementClientCompositionFrames() = 0;
+ virtual void incrementClientCompositionReusedFrames() = 0;
// Increments the number of times the display refresh rate changed.
virtual void incrementRefreshRateSwitches() = 0;
+ // Increments the number of changes in composition strategy
+ // The intention is to reflect the number of changes between hwc and gpu
+ // composition, where "gpu composition" may also include mixed composition.
+ virtual void incrementCompositionStrategyChanges() = 0;
// Records the most up-to-date count of display event connections.
// The stored count will be the maximum ever recoded.
virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
@@ -152,24 +158,6 @@
}
};
- struct ClientCompositionRecord {
- // Frame had client composition or mixed composition
- bool hadClientComposition = false;
- // Composition changed between hw composition and mixed/client composition
- bool changed = false;
- // Frame reused the client composition result from a previous frame
- bool reused = false;
- // Composition strategy predicted for frame
- bool predicted = false;
- // Composition strategy prediction succeeded
- bool predictionSucceeded = false;
-
- // Whether there is data we want to record.
- bool hasInterestingData() const {
- return hadClientComposition || changed || reused || predicted;
- }
- };
-
virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0;
// Clean up the layer record
virtual void onDestroy(int32_t layerId) = 0;
@@ -181,7 +169,6 @@
// Source of truth is RefrehRateStats.
virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
- virtual void pushCompositionStrategyState(const ClientCompositionRecord&) = 0;
};
namespace impl {
@@ -249,7 +236,10 @@
void incrementTotalFrames() override;
void incrementMissedFrames() override;
+ void incrementClientCompositionFrames() override;
+ void incrementClientCompositionReusedFrames() override;
void incrementRefreshRateSwitches() override;
+ void incrementCompositionStrategyChanges() override;
void recordDisplayEventConnectionCount(int32_t count) override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
@@ -285,8 +275,6 @@
void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
- void pushCompositionStrategyState(const ClientCompositionRecord&) override;
-
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index cf1ca65..69afa2a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -143,14 +143,6 @@
clientCompositionReusedFramesLegacy);
StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
- StringAppendF(&result, "compositionStrategyPredicted = %d\n",
- compositionStrategyPredictedLegacy);
- StringAppendF(&result, "compositionStrategyPredictionSucceeded = %d\n",
- compositionStrategyPredictionSucceededLegacy);
- StringAppendF(&result, "compositionStrategyPredictionFailed = %d\n",
- compositionStrategyPredictedLegacy -
- compositionStrategyPredictionSucceededLegacy);
-
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStatsLegacy) {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 237ae8d..438561c 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -178,8 +178,6 @@
Histogram frameDurationLegacy;
Histogram renderEngineTimingLegacy;
std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
- int32_t compositionStrategyPredictedLegacy = 0;
- int32_t compositionStrategyPredictionSucceededLegacy = 0;
std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
diff --git a/services/surfaceflinger/Tracing/LocklessStack.h b/services/surfaceflinger/Tracing/LocklessStack.h
new file mode 100644
index 0000000..20f2aa8
--- /dev/null
+++ b/services/surfaceflinger/Tracing/LocklessStack.h
@@ -0,0 +1,72 @@
+/*
+ * 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 <atomic>
+
+template <typename T>
+// Single consumer multi producer stack. We can understand the two operations independently to see
+// why they are without race condition.
+//
+// push is responsible for maintaining a linked list stored in mPush, and called from multiple
+// threads without lock. We can see that if two threads never observe the same value from
+// mPush.load, it just functions as a normal linked list. In the case where two threads observe the
+// same value, one of them has to execute the compare_exchange first. The one that doesn't execute
+// the compare exchange first, will receive false from compare_exchange. previousHead is updated (by
+// compare_exchange) to the most recent value of mPush, and we try again. It's relatively clear to
+// see that the process can repeat with an arbitrary number of threads.
+//
+// Pop is much simpler. If mPop is empty (as it begins) it atomically exchanges
+// the entire push list with null. This is safe, since the only other reader (push)
+// of mPush will retry if it changes in between it's read and atomic compare. We
+// then store the list and pop one element.
+//
+// If we already had something in the pop list we just pop directly.
+class LocklessStack {
+public:
+ class Entry {
+ public:
+ T* mValue;
+ std::atomic<Entry*> mNext;
+ Entry(T* value): mValue(value) {}
+ };
+ std::atomic<Entry*> mPush = nullptr;
+ std::atomic<Entry*> mPop = nullptr;
+ void push(T* value) {
+ Entry* entry = new Entry(value);
+ Entry* previousHead = mPush.load(/*std::memory_order_relaxed*/);
+ do {
+ entry->mNext = previousHead;
+ } while (!mPush.compare_exchange_weak(previousHead, entry)); /*std::memory_order_release*/
+ }
+ T* pop() {
+ Entry* popped = mPop.load(/*std::memory_order_acquire*/);
+ if (popped) {
+ // Single consumer so this is fine
+ mPop.store(popped->mNext/* , std::memory_order_release */);
+ auto value = popped->mValue;
+ delete popped;
+ return value;
+ } else {
+ Entry *grabbedList = mPush.exchange(nullptr/* , std::memory_order_acquire */);
+ if (!grabbedList) return nullptr;
+ mPop.store(grabbedList->mNext/* , std::memory_order_release */);
+ auto value = grabbedList->mValue;
+ delete grabbedList;
+ return value;
+ }
+ }
+};
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 1ec9577..d249b60 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -180,13 +180,13 @@
}
if (layer.what & layer_state_t::eReparent) {
- int32_t layerId = layer.parentSurfaceControlForChild
+ int64_t layerId = layer.parentSurfaceControlForChild
? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle())
: -1;
proto.set_parent_id(layerId);
}
if (layer.what & layer_state_t::eRelativeLayerChanged) {
- int32_t layerId = layer.relativeLayerSurfaceControl
+ int64_t layerId = layer.relativeLayerSurfaceControl
? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle())
: -1;
proto.set_relative_parent_id(layerId);
@@ -342,13 +342,13 @@
outState.merge(state);
if (state.what & layer_state_t::eReparent) {
- outState.parentId = proto.parent_id();
+ outState.parentId = static_cast<int32_t>(proto.parent_id());
}
if (state.what & layer_state_t::eRelativeLayerChanged) {
- outState.relativeParentId = proto.relative_parent_id();
+ outState.relativeParentId = static_cast<int32_t>(proto.relative_parent_id());
}
if (state.what & layer_state_t::eInputInfoChanged) {
- outState.inputCropId = proto.window_info_handle().crop_layer_id();
+ outState.inputCropId = static_cast<int32_t>(proto.window_info_handle().crop_layer_id());
}
if (state.what & layer_state_t::eBufferChanged) {
const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
@@ -364,7 +364,7 @@
}
void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) {
- layer.layerId = proto.layer_id();
+ layer.layerId = (int32_t)proto.layer_id();
layer.what |= proto.what();
layer.surface = mMapper->getLayerHandle(layer.layerId);
@@ -451,23 +451,25 @@
}
if (proto.what() & layer_state_t::eReparent) {
- int32_t layerId = proto.parent_id();
+ int64_t layerId = proto.parent_id();
if (layerId == -1) {
layer.parentSurfaceControlForChild = nullptr;
} else {
layer.parentSurfaceControlForChild =
new SurfaceControl(SurfaceComposerClient::getDefault(),
- mMapper->getLayerHandle(layerId), nullptr, layerId);
+ mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
+ nullptr, static_cast<int32_t>(layerId));
}
}
if (proto.what() & layer_state_t::eRelativeLayerChanged) {
- int32_t layerId = proto.relative_parent_id();
+ int64_t layerId = proto.relative_parent_id();
if (layerId == -1) {
layer.relativeLayerSurfaceControl = nullptr;
} else {
layer.relativeLayerSurfaceControl =
new SurfaceControl(SurfaceComposerClient::getDefault(),
- mMapper->getLayerHandle(layerId), nullptr, layerId);
+ mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
+ nullptr, static_cast<int32_t>(layerId));
}
layer.z = proto.z();
}
@@ -494,8 +496,9 @@
inputInfo.transform.set(transformProto.tx(), transformProto.ty());
inputInfo.replaceTouchableRegionWithCrop =
windowInfoProto.replace_touchable_region_with_crop();
- int32_t layerId = windowInfoProto.crop_layer_id();
- inputInfo.touchableRegionCropHandle = mMapper->getLayerHandle(layerId);
+ int64_t layerId = windowInfoProto.crop_layer_id();
+ inputInfo.touchableRegionCropHandle =
+ mMapper->getLayerHandle(static_cast<int32_t>(layerId));
layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
}
if (proto.what() & layer_state_t::eBackgroundColorChanged) {
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index 2f70b27..872a901 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -80,7 +80,8 @@
public:
virtual ~FlingerDataMapper() = default;
virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; }
- virtual int32_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
+ virtual int64_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
+ virtual int64_t getLayerId(BBinder* /* layerHandle */) const { return -1; }
virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; }
virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; }
virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
@@ -106,6 +107,7 @@
TransactionState fromProto(const proto::TransactionState&);
void mergeFromProto(const proto::LayerState&, TracingLayerState& outState);
void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+ std::unique_ptr<FlingerDataMapper> mMapper;
private:
proto::LayerState toProto(const layer_state_t&);
@@ -113,7 +115,6 @@
void fromProto(const proto::LayerState&, layer_state_t& out);
DisplayState fromProto(const proto::DisplayState&);
- std::unique_ptr<FlingerDataMapper> mMapper;
};
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index d5e837f..6381758 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -29,23 +29,16 @@
namespace android {
-class FlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
- std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
-
+// Keeps the binder address as the layer id so we can avoid holding the tracing lock in the
+// binder thread.
+class FlatDataMapper : public TransactionProtoParser::FlingerDataMapper {
public:
- FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
- : mLayerHandles(layerHandles) {}
-
- int32_t getLayerId(const sp<IBinder>& layerHandle) const override {
+ virtual int64_t getLayerId(const sp<IBinder>& layerHandle) const {
if (layerHandle == nullptr) {
return -1;
}
- auto it = mLayerHandles.find(layerHandle->localBinder());
- if (it == mLayerHandles.end()) {
- ALOGW("Could not find layer handle %p", layerHandle->localBinder());
- return -1;
- }
- return it->second;
+
+ return reinterpret_cast<int64_t>(layerHandle->localBinder());
}
void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
@@ -72,8 +65,33 @@
}
};
+class FlingerDataMapper : public FlatDataMapper {
+ std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
+
+public:
+ FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
+ : mLayerHandles(layerHandles) {}
+
+ int64_t getLayerId(const sp<IBinder>& layerHandle) const override {
+ if (layerHandle == nullptr) {
+ return -1;
+ }
+ return getLayerId(layerHandle->localBinder());
+ }
+
+ int64_t getLayerId(BBinder* localBinder) const {
+ auto it = mLayerHandles.find(localBinder);
+ if (it == mLayerHandles.end()) {
+ ALOGW("Could not find layer handle %p", localBinder);
+ return -1;
+ }
+ return it->second;
+ }
+};
+
TransactionTracing::TransactionTracing()
- : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)) {
+ : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)),
+ mLockfreeProtoParser(std::make_unique<FlatDataMapper>()) {
std::scoped_lock lock(mTraceLock);
mBuffer.setSize(mBufferSizeInBytes);
@@ -129,9 +147,9 @@
}
void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
- std::scoped_lock lock(mTraceLock);
- ATRACE_CALL();
- mQueuedTransactions[transaction.id] = mProtoParser.toProto(transaction);
+ proto::TransactionState* state =
+ new proto::TransactionState(mLockfreeProtoParser.toProto(transaction));
+ mTransactionQueue.push(state);
}
void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
@@ -182,6 +200,38 @@
std::scoped_lock lock(mTraceLock);
std::vector<std::string> removedEntries;
proto::TransactionTraceEntry entryProto;
+
+ while (auto incomingTransaction = mTransactionQueue.pop()) {
+ auto transaction = *incomingTransaction;
+ int32_t layerCount = transaction.layer_changes_size();
+ for (int i = 0; i < layerCount; i++) {
+ auto layer = transaction.mutable_layer_changes(i);
+ layer->set_layer_id(
+ mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(layer->layer_id())));
+ if ((layer->what() & layer_state_t::eReparent) && layer->parent_id() != -1) {
+ layer->set_parent_id(
+ mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
+ layer->parent_id())));
+ }
+
+ if ((layer->what() & layer_state_t::eRelativeLayerChanged) &&
+ layer->relative_parent_id() != -1) {
+ layer->set_relative_parent_id(
+ mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
+ layer->relative_parent_id())));
+ }
+
+ if (layer->has_window_info_handle() &&
+ layer->window_info_handle().crop_layer_id() != -1) {
+ auto input = layer->mutable_window_info_handle();
+ input->set_crop_layer_id(
+ mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
+ input->crop_layer_id())));
+ }
+ }
+ mQueuedTransactions[incomingTransaction->transaction_id()] = transaction;
+ delete incomingTransaction;
+ }
for (const CommittedTransactions& entry : committedTransactions) {
entryProto.set_elapsed_realtime_nanos(entry.timestamp);
entryProto.set_vsync_id(entry.vsyncId);
@@ -317,9 +367,9 @@
// Merge layer states to starting transaction state.
for (const proto::TransactionState& transaction : removedEntry.transactions()) {
for (const proto::LayerState& layerState : transaction.layer_changes()) {
- auto it = mStartingStates.find(layerState.layer_id());
+ auto it = mStartingStates.find((int32_t)layerState.layer_id());
if (it == mStartingStates.end()) {
- ALOGW("Could not find layer id %d", layerState.layer_id());
+ ALOGW("Could not find layer id %d", (int32_t)layerState.layer_id());
continue;
}
mProtoParser.mergeFromProto(layerState, it->second);
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index 95256c4..4c291f9 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -26,6 +26,7 @@
#include <thread>
#include "RingBuffer.h"
+#include "LocklessStack.h"
#include "TransactionProtoParser.h"
using namespace android::surfaceflinger;
@@ -78,6 +79,7 @@
size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE;
std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions
GUARDED_BY(mTraceLock);
+ LocklessStack<proto::TransactionState> mTransactionQueue;
nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
@@ -85,6 +87,9 @@
std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
+ // Parses the transaction to proto without holding any tracing locks so we can generate proto
+ // in the binder thread without any contention.
+ TransactionProtoParser mLockfreeProtoParser;
// We do not want main thread to block so main thread will try to acquire mMainThreadLock,
// otherwise will push data to temporary container.
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index fcf4499..4f99b19 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -70,7 +70,7 @@
// Keep insync with layer_state_t
message LayerState {
- int32 layer_id = 1;
+ int64 layer_id = 1;
// Changes are split into ChangesLsb and ChangesMsb. First 32 bits are in ChangesLsb
// and the next 32 bits are in ChangesMsb. This is needed because enums have to be
// 32 bits and there's no nice way to put 64bit constants into .proto files.
@@ -161,8 +161,8 @@
Matrix22 matrix = 11;
float corner_radius = 12;
uint32 background_blur_radius = 13;
- int32 parent_id = 14;
- int32 relative_parent_id = 15;
+ int64 parent_id = 14;
+ int64 relative_parent_id = 15;
float alpha = 16;
message Color3 {
@@ -233,7 +233,7 @@
bool focusable = 5;
bool has_wallpaper = 6;
float global_scale_factor = 7;
- int32 crop_layer_id = 8;
+ int64 crop_layer_id = 8;
bool replace_touchable_region_with_crop = 9;
RectProto touchable_region_crop = 10;
Transform transform = 11;
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/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index fe0564e..6780108 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -400,12 +400,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);
}
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 6ffc039..0ef8456 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -268,11 +268,8 @@
for (size_t i = 0; i < MISSED_FRAMES; i++) {
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
}
- TimeStats::ClientCompositionRecord record;
- record.hadClientComposition = true;
-
for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState(record));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
}
SFTimeStatsGlobalProto globalProto;
@@ -462,49 +459,19 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseClientCompositionStats) {
+TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
// this stat is not in the proto so verify by checking the string dump
- constexpr size_t COMPOSITION_STRATEGY_CHANGED_FRAMES = 1;
- constexpr size_t HAD_CLIENT_COMPOSITION_FRAMES = 2;
- constexpr size_t REUSED_CLIENT_COMPOSITION_FRAMES = 3;
- constexpr size_t COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES = 4;
- constexpr size_t COMPOSITION_STRATEGY_PREDICTED_FRAMES = 5;
+ constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- for (size_t i = 0; i <= COMPOSITION_STRATEGY_PREDICTED_FRAMES; i++) {
- TimeStats::ClientCompositionRecord record;
- record.hadClientComposition = i < HAD_CLIENT_COMPOSITION_FRAMES;
- record.changed = i < COMPOSITION_STRATEGY_CHANGED_FRAMES;
- record.reused = i < REUSED_CLIENT_COMPOSITION_FRAMES;
- record.predicted = i < COMPOSITION_STRATEGY_PREDICTED_FRAMES;
- record.predictionSucceeded = i < COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES;
- mTimeStats->pushCompositionStrategyState(record);
+ for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
}
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- std::string expected =
- "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGED_FRAMES);
- EXPECT_THAT(result, HasSubstr(expected));
-
- expected = "clientCompositionFrames = " + std::to_string(HAD_CLIENT_COMPOSITION_FRAMES);
- EXPECT_THAT(result, HasSubstr(expected));
-
- expected =
- "clientCompositionReusedFrames = " + std::to_string(REUSED_CLIENT_COMPOSITION_FRAMES);
- EXPECT_THAT(result, HasSubstr(expected));
-
- expected = "compositionStrategyPredicted = " +
- std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES);
- EXPECT_THAT(result, HasSubstr(expected));
-
- expected = "compositionStrategyPredictionSucceeded = " +
- std::to_string(COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES);
- EXPECT_THAT(result, HasSubstr(expected));
-
- expected = "compositionStrategyPredictionFailed = " +
- std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES -
- COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES);
- EXPECT_THAT(result, HasSubstr(expected));
+ const std::string expectedResult =
+ "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
}
TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) {
@@ -522,6 +489,21 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
+TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t COMPOSITION_STRATEGY_CHANGES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ for (size_t i = 0; i < COMPOSITION_STRATEGY_CHANGES; i++) {
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
+ }
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
TEST_F(TimeStatsTest, canAverageFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
mTimeStats->setPowerMode(PowerMode::ON);
@@ -854,7 +836,7 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({}));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
@@ -885,8 +867,9 @@
TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
// These stats are not in the proto so verify by checking the string dump.
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({}));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
mTimeStats->setPowerMode(PowerMode::ON);
mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
std::chrono::nanoseconds(5ms).count());
@@ -1049,10 +1032,8 @@
for (size_t i = 0; i < MISSED_FRAMES; i++) {
mTimeStats->incrementMissedFrames();
}
- TimeStats::ClientCompositionRecord record;
- record.hadClientComposition = true;
for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- mTimeStats->pushCompositionStrategyState(record);
+ mTimeStats->incrementClientCompositionFrames();
}
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index ab893a3..f5e3b77 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -81,7 +81,7 @@
sp<IBinder> getLayerHandle(int32_t id) const override {
return (id == 42) ? layerHandle : nullptr;
}
- int32_t getLayerId(const sp<IBinder>& handle) const override {
+ int64_t getLayerId(const sp<IBinder>& handle) const override {
return (handle == layerHandle) ? 42 : -1;
}
sp<IBinder> getDisplayHandle(int32_t id) const {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index a1aa7e8..996f835 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -76,6 +76,7 @@
MOCK_METHOD4(getDisplayRequests,
Error(Display, uint32_t*, std::vector<Layer>*, std::vector<uint32_t>*));
MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
+ MOCK_METHOD2(getKernelIdleTimerSupport, Error(Display, bool*));
MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
MOCK_METHOD1(getPerFrameMetadataKeys,
std::vector<IComposerClient::PerFrameMetadataKey>(Display));
@@ -157,6 +158,8 @@
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
MOCK_METHOD2(getDisplayDecorationSupport,
Error(Display, std::optional<DisplayDecorationSupport>*));
+ MOCK_METHOD2(setIdleTimerEnabled, Error(Display, std::chrono::milliseconds));
+ MOCK_METHOD2(hasDisplayIdleTimerCapability, Error(Display, bool*));
};
} // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 570ffeb..d9faa06 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -99,6 +99,8 @@
hal::Error, getDisplayDecorationSupport,
(std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> *),
(override));
+ MOCK_METHOD(hal::Error, setIdleTimerEnabled, (std::chrono::milliseconds), (override));
+ MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (), (const override));
};
class Layer : public HWC2::Layer {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 0dee800..0a69b56 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -33,7 +33,10 @@
MOCK_METHOD0(miniDump, std::string());
MOCK_METHOD0(incrementTotalFrames, void());
MOCK_METHOD0(incrementMissedFrames, void());
+ MOCK_METHOD0(incrementClientCompositionFrames, void());
+ MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
MOCK_METHOD0(incrementRefreshRateSwitches, void());
+ MOCK_METHOD0(incrementCompositionStrategyChanges, void());
MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
@@ -60,8 +63,6 @@
void(hardware::graphics::composer::V2_4::IComposerClient::PowerMode));
MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
- MOCK_METHOD(void, pushCompositionStrategyState,
- (const android::TimeStats::ClientCompositionRecord&), (override));
};
} // namespace android::mock
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});
}