Merge "Merge ColorSpaceAgnosticChanged property in a transactioin" 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 77bed0e..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
@@ -765,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
@@ -775,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();
@@ -848,8 +826,8 @@
const android::os::ReconcileSdkDataArgs& args) {
// Locking is performed depeer in the callstack.
- return reconcileSdkData(args.uuid, args.packageName, args.sdkPackageNames, args.randomSuffixes,
- args.userId, args.appId, args.previousAppId, args.seInfo, args.flags);
+ return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
+ args.previousAppId, args.seInfo, args.flags);
}
/**
@@ -863,17 +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
@@ -882,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;
}
@@ -905,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);
@@ -944,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);
@@ -967,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;
@@ -2152,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) {
@@ -2259,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;
@@ -2285,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);
}
@@ -2427,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(
@@ -2663,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);
@@ -3590,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 1f0fc9c..e6be5d8 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -183,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;
@@ -211,8 +216,7 @@
binder::Status createSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
const std::string& packageName,
int32_t userId, int32_t appId,
- int32_t previousAppId,
- const std::string& seInfo, int32_t flags);
+ int32_t flags);
binder::Status clearSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
const std::string& packageName,
int32_t userId, int32_t flags);
@@ -221,8 +225,7 @@
int32_t userId, int32_t flags);
binder::Status reconcileSdkData(const std::optional<std::string>& uuid,
const std::string& packageName,
- const std::vector<std::string>& sdkPackageNames,
- const std::vector<std::string>& randomSuffixes, int32_t userId,
+ const std::vector<std::string>& subDirNames, int32_t userId,
int32_t appId, int32_t previousAppId, const std::string& seInfo,
int flags);
binder::Status restoreconSdkDataLocked(const std::optional<std::string>& uuid,
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3f0fb6d..8ccab4c 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -30,6 +30,9 @@
},
{
"name": "CtsCompilationTestCases"
+ },
+ {
+ "name": "SdkSandboxStorageHostTest"
}
]
}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index e08e9b6..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 04558d5..38cb370 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -45,7 +45,7 @@
#include "utils.h"
using android::base::StringPrintf;
-namespace fs = std::filesystem;
+using std::filesystem::is_empty;
namespace android {
std::string get_package_name(uid_t uid) {
@@ -79,12 +79,15 @@
namespace installd {
static constexpr const char* kTestUuid = "TEST";
-static constexpr const char* kTestPath = "/data/local/tmp";
+static const std::string kTestPath = "/data/local/tmp";
static constexpr const uid_t kNobodyUid = 9999;
static constexpr const uid_t kSystemUid = 1000;
static constexpr const int32_t kTestUserId = 0;
static constexpr const uid_t kTestAppId = 19999;
static constexpr const int FLAG_STORAGE_SDK = InstalldNativeService::FLAG_STORAGE_SDK;
+static constexpr const int FLAG_CLEAR_CACHE_ONLY = InstalldNativeService::FLAG_CLEAR_CACHE_ONLY;
+static constexpr const int FLAG_CLEAR_CODE_CACHE_ONLY =
+ InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY;
const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
const gid_t kTestCacheGid = multiuser_get_cache_gid(kTestUserId, kTestAppId);
@@ -111,7 +114,7 @@
}
static std::string get_full_path(const std::string& path) {
- return StringPrintf("%s/%s", kTestPath, path.c_str());
+ return StringPrintf("%s/%s", kTestPath.c_str(), path.c_str());
}
static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
@@ -169,10 +172,9 @@
}
static bool exists_renamed_deleted_dir(const std::string& rootDirectory) {
- return find_file((std::string(kTestPath) + rootDirectory).c_str(),
- [](const std::string& name, bool is_dir) {
- return is_dir && is_renamed_deleted_dir(name);
- });
+ return find_file((kTestPath + rootDirectory).c_str(), [](const std::string& name, bool is_dir) {
+ return is_dir && is_renamed_deleted_dir(name);
+ });
}
class ServiceTest : public testing::Test {
@@ -992,16 +994,12 @@
}
android::os::ReconcileSdkDataArgs reconcileSdkDataArgs(
- std::string packageName, std::vector<std::string> codeNames,
- std::vector<std::string> randomSuffixes) {
+ const std::string& packageName, const std::vector<std::string>& subDirNames) {
android::os::ReconcileSdkDataArgs args;
args.uuid = kTestUuid;
args.packageName = packageName;
- for (const auto& codeName : codeNames) {
- args.sdkPackageNames.push_back(codeName);
- }
- for (const auto& randomSuffix : randomSuffixes) {
- args.randomSuffixes.push_back(randomSuffix);
+ for (const auto& subDirName : subDirNames) {
+ args.subDirNames.push_back(subDirName);
}
args.userId = kTestUserId;
args.appId = kTestAppId;
@@ -1051,22 +1049,12 @@
const std::string fooCePath = "misc_ce/0/sdksandbox/com.foo";
CheckFileAccess(fooCePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
- CheckFileAccess(fooCePath + "/shared", kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
- CheckFileAccess(fooCePath + "/shared/cache", kTestSdkSandboxUid, kTestCacheGid,
- S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(fooCePath + "/shared/code_cache", kTestSdkSandboxUid, kTestCacheGid,
- S_IFDIR | S_ISGID | 0771);
const std::string fooDePath = "misc_de/0/sdksandbox/com.foo";
CheckFileAccess(fooDePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
- CheckFileAccess(fooDePath + "/shared", kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
- CheckFileAccess(fooDePath + "/shared/cache", kTestSdkSandboxUid, kTestCacheGid,
- S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(fooDePath + "/shared/code_cache", kTestSdkSandboxUid, kTestCacheGid,
- S_IFDIR | S_ISGID | 0771);
}
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutSdkFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlag) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
@@ -1078,7 +1066,7 @@
ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
}
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutSdkFlagDeletesExisting) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlagDeletesExisting) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
// Create the app user data.
@@ -1092,7 +1080,7 @@
ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
}
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutDeFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutDeFlag) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_SDK;
@@ -1107,7 +1095,7 @@
ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
}
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutCeFlag) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutCeFlag) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.flags = FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
@@ -1124,102 +1112,58 @@
TEST_F(SdkSandboxDataTest, ReconcileSdkData) {
android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar", "baz"}, {"random1", "random2"});
+ reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
// Create the sdk data.
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
const std::string barCePath = "misc_ce/0/sdksandbox/com.foo/bar@random1";
- CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
+ CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
CheckFileAccess(barCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
CheckFileAccess(barCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
const std::string bazCePath = "misc_ce/0/sdksandbox/com.foo/baz@random2";
- CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
+ CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
CheckFileAccess(bazCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
CheckFileAccess(bazCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
const std::string barDePath = "misc_de/0/sdksandbox/com.foo/bar@random1";
- CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
+ CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
CheckFileAccess(barDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
CheckFileAccess(barDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
const std::string bazDePath = "misc_de/0/sdksandbox/com.foo/baz@random2";
- CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 0700);
+ CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
CheckFileAccess(bazDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
CheckFileAccess(bazDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
S_IFDIR | S_ISGID | 0771);
}
-TEST_F(SdkSandboxDataTest, ReconcileSdkData_PackageNameCannotUseRandomSuffixSeparator) {
- android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar@illegal"}, {"random1"});
-
- // Create the sdksandbox data.
- auto status = service->reconcileSdkData(args);
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_ILLEGAL_ARGUMENT);
- ASSERT_EQ(status.exceptionMessage(), "Package name bar@illegal is malformed");
-}
-
-TEST_F(SdkSandboxDataTest, ReconcileSdkData_NotEnoughRandomSuffix) {
- android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar", "baz"}, {"random1"});
-
- // Create the sdksandbox data.
- auto status = service->reconcileSdkData(args);
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_ILLEGAL_ARGUMENT);
- ASSERT_EQ(status.exceptionMessage(), "Not enough random suffix. Required 2, received 1.");
-}
-
-TEST_F(SdkSandboxDataTest, ReconcileSdkData_DirectoryNotCreatedIfAlreadyExistsIgnoringSuffix) {
- android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar", "baz"}, {"random1", "random2"});
-
- // Create the sdksandbox data.
- ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
-
- // Retry with different random suffix
- args.randomSuffixes[0] = "r10";
- args.randomSuffixes[1] = "r20";
-
- // Create the sdksandbox data again
- ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
-
- // Previous directories from first attempt should exist
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar@random1", kTestSdkSandboxUid, kNobodyUid,
- S_IFDIR | 0700);
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
- S_IFDIR | 0700);
- // No new directories should be created on second attempt
- ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/bar@r10"));
- ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo/bar@r20"));
-}
-
TEST_F(SdkSandboxDataTest, ReconcileSdkData_ExtraCodeDirectoriesAreDeleted) {
android::os::ReconcileSdkDataArgs args =
- reconcileSdkDataArgs("com.foo", {"bar", "baz"}, {"random1", "random2"});
+ reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
// Create the sdksandbox data.
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
// Retry with different package name
- args.sdkPackageNames[0] = "bar.diff";
+ args.subDirNames[0] = "bar.diff@random1";
// Create the sdksandbox data again
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
// New directoris should exist
CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar.diff@random1", kTestSdkSandboxUid, kNobodyUid,
- S_IFDIR | 0700);
+ S_IFDIR | S_ISGID | 0700);
CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
- S_IFDIR | 0700);
+ S_IFDIR | S_ISGID | 0700);
// Directory for old unreferred sdksandbox package name should be removed
ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/bar@random1"));
}
@@ -1270,130 +1214,90 @@
void createTestSdkData(const std::string& packageName, std::vector<std::string> sdkNames) {
const auto& cePackagePath = "/data/local/tmp/misc_ce/0/sdksandbox/" + packageName;
const auto& dePackagePath = "/data/local/tmp/misc_de/0/sdksandbox/" + packageName;
- ASSERT_TRUE(mkdirs(cePackagePath + "/shared/cache", 0700));
- ASSERT_TRUE(mkdirs(cePackagePath + "shared/code_cache", 0700));
- ASSERT_TRUE(mkdirs(dePackagePath + "/shared/cache", 0700));
- ASSERT_TRUE(mkdirs(dePackagePath + "/shared/code_cache", 0700));
- std::ofstream{cePackagePath + "/shared/cache/cachedTestData.txt"};
- for (auto sdkName : sdkNames) {
- ASSERT_TRUE(mkdirs(cePackagePath + "/" + sdkName + "/cache", 0700));
- ASSERT_TRUE(mkdirs(dePackagePath + "/" + sdkName + "/cache", 0700));
- ASSERT_TRUE(mkdirs(cePackagePath + "/" + sdkName + "/code_cache", 0700));
- ASSERT_TRUE(mkdirs(dePackagePath + "/" + sdkName + "/code_cache", 0700));
- std::ofstream{cePackagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
- std::ofstream{cePackagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
- std::ofstream{dePackagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
- std::ofstream{dePackagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
+ ASSERT_TRUE(mkdirs(cePackagePath, 0700));
+ ASSERT_TRUE(mkdirs(dePackagePath, 0700));
+ const std::vector<std::string> packagePaths = {cePackagePath, dePackagePath};
+ for (const auto& packagePath : packagePaths) {
+ for (auto sdkName : sdkNames) {
+ ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/cache", 0700));
+ ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/code_cache", 0700));
+ std::ofstream{packagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
+ std::ofstream{packagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
+ }
}
}
};
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(
- service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_CE | (InstalldNativeService::FLAG_CLEAR_CACHE_ONLY),
- result.ceDataInode));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/shared/cache")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk1/cache")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk2/cache")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_CE | FLAG_CLEAR_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCodeCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(
- service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_CE |
- (InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY),
- result.ceDataInode));
- ASSERT_TRUE(fs::is_empty(
- fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/shared/code_cache")));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk1/code_cache")));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk2/code_cache")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_CE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data
ASSERT_BINDER_SUCCESS(
- service->clearAppData(args.uuid, args.packageName, args.userId,
+ service->clearAppData(kTestUuid, "com.foo", 0,
FLAG_STORAGE_DE | (InstalldNativeService::FLAG_CLEAR_CACHE_ONLY),
- result.ceDataInode));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/shared/cache")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk1/cache")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk2/cache")));
+ -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCodeCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(
- service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_DE |
- (InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY),
- result.ceDataInode));
- ASSERT_TRUE(fs::is_empty(
- fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/shared/code_cache")));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk1/code_cache")));
- ASSERT_TRUE(
- fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk2/code_cache")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_DE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndWithoutAnyCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_CE, result.ceDataInode));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/shared")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk1")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/sdk2")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_CE, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
}
TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndWithoutAnyCacheFlag) {
- android::os::CreateAppDataResult result;
- android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.packageName = "com.foo";
- // Create the app user data.
- ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
- createTestSdkData("com.foo", {"sdk1", "sdk2"});
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
// Clear the app user data.
- ASSERT_BINDER_SUCCESS(service->clearAppData(args.uuid, args.packageName, args.userId,
- FLAG_STORAGE_DE, result.ceDataInode));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/shared")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk1")));
- ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk2")));
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_DE, -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
}
class DestroyUserDataTest : public SdkSandboxDataTest {};
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 38c1c05..910cd63 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -690,11 +690,11 @@
create_data_misc_sdk_sandbox_package_path(nullptr, true, 10, "com.foo"));
EXPECT_EQ("/data/misc_ce/0/sdksandbox/com.foo/shared",
- create_data_misc_sdk_sandbox_shared_path(nullptr, true, 0, "com.foo"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 0, "com.foo", "shared"));
EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/shared",
- create_data_misc_sdk_sandbox_shared_path(nullptr, true, 10, "com.foo"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "shared"));
EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/bar@random",
- create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "bar", "random"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "bar@random"));
// De data paths
EXPECT_EQ("/data/misc_de/0/sdksandbox",
@@ -707,12 +707,11 @@
create_data_misc_sdk_sandbox_package_path(nullptr, false, 10, "com.foo"));
EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo/shared",
- create_data_misc_sdk_sandbox_shared_path(nullptr, false, 0, "com.foo"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 0, "com.foo", "shared"));
EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/shared",
- create_data_misc_sdk_sandbox_shared_path(nullptr, false, 10, "com.foo"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "shared"));
EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/bar@random",
- create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "bar",
- "random"));
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "bar@random"));
}
TEST_F(UtilsTest, WaitChild) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 8cfd123..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 b14a838..4a01d81 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -25,9 +25,10 @@
#include <binder/IServiceManager.h>
#include <binder/Stability.h>
#include <cutils/atomic.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <utils/String8.h>
-#include <utils/threads.h>
+#include <utils/Thread.h>
#include "Static.h"
#include "binder_module.h"
diff --git a/libs/binder/Static.h b/libs/binder/Static.h
index 83524e8..8444fe7 100644
--- a/libs/binder/Static.h
+++ b/libs/binder/Static.h
@@ -17,8 +17,6 @@
// All static variables go here, to control initialization and
// destruction order in the library.
-#include <utils/threads.h>
-
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 8deb2fe..19ad5e6 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -18,7 +18,6 @@
#include <binder/IBinder.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
#include <map>
#include <unordered_map>
diff --git a/libs/binder/include/binder/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 0deee73..675585e 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -18,11 +18,10 @@
#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
#include <utils/String16.h>
#include <utils/String8.h>
-#include <utils/threads.h>
-
#include <pthread.h>
// ---------------------------------------------------------------------------
diff --git a/libs/binder/include_activitymanager/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
index 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/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 467e51e..5d6206d 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -1086,7 +1086,7 @@
{
$( #[$attr:meta] )*
$enum:ident : [$backing:ty; $size:expr] {
- $( $name:ident = $value:expr, )*
+ $( $( #[$value_attr:meta] )* $name:ident = $value:expr, )*
}
} => {
$( #[$attr] )*
@@ -1094,7 +1094,7 @@
#[allow(missing_docs)]
pub struct $enum(pub $backing);
impl $enum {
- $( #[allow(missing_docs)] pub const $name: Self = Self($value); )*
+ $( $( #[$value_attr] )* #[allow(missing_docs)] pub const $name: Self = Self($value); )*
#[inline(always)]
#[allow(missing_docs)]
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index d58e839..432da5d 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -233,7 +233,9 @@
}
fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
- self.stability = parcel.read()?;
+ if self.stability != parcel.read()? {
+ return Err(StatusCode::BAD_VALUE);
+ }
let data_size: i32 = parcel.read()?;
if data_size < 0 {
diff --git a/libs/binder/tests/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/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..52a22a7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1421,7 +1421,7 @@
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
- const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& frameNumber,
+ const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& optFrameNumber,
ReleaseBufferCallback callback) {
layer_state_t* s = getLayerState(sc);
if (!s) {
@@ -1433,10 +1433,9 @@
std::shared_ptr<BufferData> bufferData = std::make_shared<BufferData>();
bufferData->buffer = buffer;
- if (frameNumber) {
- bufferData->frameNumber = *frameNumber;
- bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged;
- }
+ uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber);
+ bufferData->frameNumber = frameNumber;
+ bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged;
if (fence) {
bufferData->acquireFence = *fence;
bufferData->flags |= BufferData::BufferDataChange::fenceChanged;
@@ -2320,9 +2319,11 @@
}
status_t SurfaceComposerClient::addWindowInfosListener(
- const sp<WindowInfosListener>& windowInfosListener) {
+ const sp<WindowInfosListener>& windowInfosListener,
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) {
return WindowInfosListenerReporter::getInstance()
- ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService());
+ ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService(),
+ outInitialInfo);
}
status_t SurfaceComposerClient::removeWindowInfosListener(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 6529a4e..063dda5 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -280,5 +280,18 @@
return this;
}
+uint64_t SurfaceControl::resolveFrameNumber(const std::optional<uint64_t>& frameNumber) {
+ if (frameNumber.has_value()) {
+ auto ret = frameNumber.value();
+ // Set the fallback to something far enough ahead that in the unlikely event of mixed
+ // "real" frame numbers and fallback frame numbers, we still won't collide in any
+ // meaningful capacity
+ mFallbackFrameNumber = ret + 100;
+ return ret;
+ } else {
+ return mFallbackFrameNumber++;
+ }
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index 4112f74..cfc7dbc 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -31,7 +31,8 @@
status_t WindowInfosListenerReporter::addWindowInfosListener(
const sp<WindowInfosListener>& windowInfosListener,
- const sp<ISurfaceComposer>& surfaceComposer) {
+ const sp<ISurfaceComposer>& surfaceComposer,
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) {
status_t status = OK;
{
std::scoped_lock lock(mListenersMutex);
@@ -42,6 +43,11 @@
if (status == OK) {
mWindowInfosListeners.insert(windowInfosListener);
}
+
+ if (outInitialInfo != nullptr) {
+ outInitialInfo->first = mLastWindowInfos;
+ outInitialInfo->second = mLastDisplayInfos;
+ }
}
return status;
@@ -55,6 +61,10 @@
std::scoped_lock lock(mListenersMutex);
if (mWindowInfosListeners.size() == 1) {
status = surfaceComposer->removeWindowInfosListener(this);
+ // Clear the last stored state since we're disabling updates and don't want to hold
+ // stale values
+ mLastWindowInfos.clear();
+ mLastDisplayInfos.clear();
}
if (status == OK) {
@@ -75,6 +85,9 @@
for (auto listener : mWindowInfosListeners) {
windowInfosListeners.insert(listener);
}
+
+ mLastWindowInfos = windowInfos;
+ mLastDisplayInfos = displayInfos;
}
for (auto listener : windowInfosListeners) {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index c8ac166..9d03f58 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -696,7 +696,10 @@
static status_t removeTunnelModeEnabledListener(
const sp<gui::ITunnelModeEnabledListener>& listener);
- status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
+ status_t addWindowInfosListener(
+ const sp<gui::WindowInfosListener>& windowInfosListener,
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo =
+ nullptr);
status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
protected:
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 9ee4636..1690e44 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <optional>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -98,6 +99,8 @@
sp<SurfaceControl> getParentingLayer();
+ uint64_t resolveFrameNumber(const std::optional<uint64_t>& frameNumber);
+
private:
// can't be copied
SurfaceControl& operator = (SurfaceControl& rhs);
@@ -124,6 +127,7 @@
uint32_t mHeight;
PixelFormat mFormat;
uint32_t mCreateFlags;
+ uint64_t mFallbackFrameNumber = 100;
};
}; // namespace android
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 96bd0b1..3b4aed4 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -34,15 +34,19 @@
const std::vector<gui::DisplayInfo>&,
const sp<gui::IWindowInfosReportedListener>&) override;
- status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
- const sp<ISurfaceComposer>&);
+ status_t addWindowInfosListener(
+ const sp<gui::WindowInfosListener>& windowInfosListener, const sp<ISurfaceComposer>&,
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo);
status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
- const sp<ISurfaceComposer>&);
+ const sp<ISurfaceComposer>& surfaceComposer);
void reconnect(const sp<ISurfaceComposer>&);
private:
std::mutex mListenersMutex;
std::unordered_set<sp<gui::WindowInfosListener>, SpHash<gui::WindowInfosListener>>
mWindowInfosListeners GUARDED_BY(mListenersMutex);
+
+ std::vector<gui::WindowInfo> mLastWindowInfos GUARDED_BY(mListenersMutex);
+ std::vector<gui::DisplayInfo> mLastDisplayInfos GUARDED_BY(mListenersMutex);
};
} // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 0c3236c..cb7e94c 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -1083,6 +1083,34 @@
checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
+TEST_F(BLASTBufferQueueTest, SyncNextTransactionOverwrite) {
+ std::mutex mutex;
+ std::condition_variable callbackReceivedCv;
+ bool receivedCallback = false;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ ASSERT_EQ(nullptr, adapter.getTransactionReadyCallback());
+ auto callback = [&](Transaction*) {
+ std::unique_lock<std::mutex> lock(mutex);
+ receivedCallback = true;
+ callbackReceivedCv.notify_one();
+ };
+ adapter.syncNextTransaction(callback);
+ ASSERT_NE(nullptr, adapter.getTransactionReadyCallback());
+
+ auto callback2 = [](Transaction*) {};
+ adapter.syncNextTransaction(callback2);
+
+ std::unique_lock<std::mutex> lock(mutex);
+ if (!receivedCallback) {
+ ASSERT_NE(callbackReceivedCv.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive callback";
+ }
+
+ ASSERT_TRUE(receivedCallback);
+}
+
// This test will currently fail because the old surfacecontrol will steal the last presented buffer
// until the old surface control is destroyed. This is not necessarily a bug but to document a
// limitation with the update API and to test any changes to make the api more robust. The current
diff --git a/libs/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/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index b467b35..5e5618b 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -654,10 +654,14 @@
colorTransform *=
mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
parameters.layerDimmingRatio, 1.f));
+ const auto targetBuffer = parameters.layer.source.buffer.buffer;
+ const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
+ const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
parameters.display.maxLuminance,
parameters.display.currentLuminanceNits,
- parameters.layer.source.buffer.maxLuminanceNits);
+ parameters.layer.source.buffer.maxLuminanceNits,
+ hardwareBuffer);
}
return parameters.shader;
}
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index a46329d..d479606 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -44,7 +44,8 @@
const shaders::LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
const mat4& colorTransform, float maxDisplayLuminance,
- float currentDisplayLuminanceNits, float maxLuminance) {
+ float currentDisplayLuminanceNits, float maxLuminance,
+ AHardwareBuffer* buffer) {
ATRACE_CALL();
SkRuntimeShaderBuilder effectBuilder(runtimeEffect);
@@ -52,7 +53,7 @@
const auto uniforms =
shaders::buildLinearEffectUniforms(linearEffect, colorTransform, maxDisplayLuminance,
- currentDisplayLuminanceNits, maxLuminance);
+ currentDisplayLuminanceNits, maxLuminance, buffer);
for (const auto& uniform : uniforms) {
effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
@@ -63,4 +64,4 @@
} // namespace skia
} // namespace renderengine
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h
index e0a556b..26bae3b 100644
--- a/libs/renderengine/skia/filters/LinearEffect.h
+++ b/libs/renderengine/skia/filters/LinearEffect.h
@@ -40,11 +40,14 @@
// * The current luminance of the physical display in nits
// * The max luminance is provided as the max luminance for the buffer, either from the SMPTE 2086
// or as the max light level from the CTA 861.3 standard.
+// * An AHardwareBuffer for implementations that support gralloc4 metadata for
+// communicating any HDR metadata.
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader,
const shaders::LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
const mat4& colorTransform, float maxDisplayLuminance,
- float currentDisplayLuminanceNits, float maxLuminance);
+ float currentDisplayLuminanceNits, float maxLuminance,
+ AHardwareBuffer* buffer);
} // namespace skia
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index add7a94..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/shaders/Android.bp b/libs/shaders/Android.bp
index 1cd143e..2f8bf49 100644
--- a/libs/shaders/Android.bp
+++ b/libs/shaders/Android.bp
@@ -30,9 +30,11 @@
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.common@1.2",
+ "libnativewindow",
],
static_libs: [
+ "libarect",
"libmath",
"libtonemap",
"libui-types",
diff --git a/libs/shaders/include/shaders/shaders.h b/libs/shaders/include/shaders/shaders.h
index 43828cc..4ec7594 100644
--- a/libs/shaders/include/shaders/shaders.h
+++ b/libs/shaders/include/shaders/shaders.h
@@ -101,6 +101,7 @@
const mat4& colorTransform,
float maxDisplayLuminance,
float currentDisplayLuminanceNits,
- float maxLuminance);
+ float maxLuminance,
+ AHardwareBuffer* buffer = nullptr);
} // namespace android::shaders
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index 03da3ec..0d77519 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -476,7 +476,8 @@
const mat4& colorTransform,
float maxDisplayLuminance,
float currentDisplayLuminanceNits,
- float maxLuminance) {
+ float maxLuminance,
+ AHardwareBuffer* buffer) {
std::vector<tonemap::ShaderUniform> uniforms;
if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
uniforms.push_back({.name = "in_rgbToXyz", .value = buildUniformValue<mat4>(mat4())});
@@ -504,7 +505,8 @@
// This will be the case for eg screenshots in addition to
// uncalibrated displays
.contentMaxLuminance =
- maxLuminance > 0 ? maxLuminance : maxDisplayLuminance};
+ maxLuminance > 0 ? maxLuminance : maxDisplayLuminance,
+ .buffer = buffer};
for (const auto uniform : tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata)) {
uniforms.push_back(uniform);
@@ -513,4 +515,4 @@
return uniforms;
}
-} // namespace android::shaders
\ No newline at end of file
+} // namespace android::shaders
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
index 99d1b22..dc55586 100644
--- a/libs/tonemap/Android.bp
+++ b/libs/tonemap/Android.bp
@@ -30,9 +30,11 @@
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
"liblog",
+ "libnativewindow",
],
static_libs: [
+ "libarect",
"libmath",
],
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
index b9abf8c..e380323 100644
--- a/libs/tonemap/include/tonemap/tonemap.h
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -17,6 +17,7 @@
#pragma once
#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <android/hardware_buffer.h>
#include <math/vec3.h>
#include <string>
@@ -44,8 +45,27 @@
struct Metadata {
// The maximum luminance of the display in nits
float displayMaxLuminance = 0.0;
+
// The maximum luminance of the content in nits
float contentMaxLuminance = 0.0;
+
+ // Reference to an AHardwareBuffer.
+ // Devices that support gralloc 4.0 and higher may attach metadata onto a
+ // particular frame's buffer, including metadata used by HDR-standards like
+ // SMPTE 2086 or SMPTE 2094-40.
+ // Note that this parameter may be optional if there is no hardware buffer
+ // available, for instance if the source content is generated from a GL
+ // texture that does not have associated metadata. As such, implementations
+ // must support nullptr.
+ AHardwareBuffer* buffer = nullptr;
+};
+
+// Utility class containing pre-processed conversions for a particular color
+struct Color {
+ // RGB color in linear space
+ vec3 linearRGB;
+ // CIE 1931 XYZ representation of the color
+ vec3 xyz;
};
class ToneMapper {
@@ -108,14 +128,15 @@
// described by destinationDataspace. To compute the gain, the input colors are provided by
// linearRGB, which is the RGB colors in linear space. The colors in XYZ space are also
// provided. Metadata is also provided for helping to compute the tonemapping curve.
- virtual double lookupTonemapGain(
+ using Gain = double;
+ virtual std::vector<Gain> lookupTonemapGain(
aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
- vec3 linearRGB, vec3 xyz, const Metadata& metadata) = 0;
+ const std::vector<Color>& colors, const Metadata& metadata) = 0;
};
// Retrieves a tonemapper instance.
// This instance is globally constructed.
ToneMapper* getToneMapper();
-} // namespace android::tonemap
\ No newline at end of file
+} // namespace android::tonemap
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
index d519482..26a1d79 100644
--- a/libs/tonemap/tests/Android.bp
+++ b/libs/tonemap/tests/Android.bp
@@ -32,6 +32,7 @@
],
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
+ "libnativewindow",
],
static_libs: [
"libmath",
diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp
index bc0a884..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 06ad6a8..6bfac6c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1032,6 +1032,21 @@
}
}
}
+
+ // If a new up event comes in, and the pending event with same key code has been asked
+ // to try again later because of the policy. We have to reset the intercept key wake up
+ // time for it may have been handled in the policy and could be dropped.
+ if (keyEntry.action == AKEY_EVENT_ACTION_UP && mPendingEvent &&
+ mPendingEvent->type == EventEntry::Type::KEY) {
+ KeyEntry& pendingKey = static_cast<KeyEntry&>(*mPendingEvent);
+ if (pendingKey.keyCode == keyEntry.keyCode &&
+ pendingKey.interceptKeyResult ==
+ KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
+ pendingKey.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
+ pendingKey.interceptKeyWakeupTime = 0;
+ needWake = true;
+ }
+ }
break;
}
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index dff5894..d9822ce 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -274,7 +274,6 @@
public:
explicit QueuedInputListener(InputListenerInterface& innerListener);
- virtual ~QueuedInputListener();
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
virtual void notifyKey(const NotifyKeyArgs* args) override;
@@ -289,7 +288,7 @@
private:
InputListenerInterface& mInnerListener;
- std::vector<NotifyArgs*> mArgsQueue;
+ std::vector<std::unique_ptr<NotifyArgs>> mArgsQueue;
};
} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 9633932..838e6aa 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -289,6 +289,13 @@
ASSERT_EQ(token, *receivedToken);
}
+ /**
+ * Set policy timeout. A value of zero means next key will not be intercepted.
+ */
+ void setInterceptKeyTimeout(std::chrono::milliseconds timeout) {
+ mInterceptKeyTimeout = timeout;
+ }
+
private:
std::mutex mLock;
std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
@@ -311,6 +318,8 @@
sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;
+ std::chrono::milliseconds mInterceptKeyTimeout = 0ms;
+
// All three ANR-related callbacks behave the same way, so we use this generic function to wait
// for a specific container to become non-empty. When the container is non-empty, return the
// first entry from the container and erase it.
@@ -429,12 +438,20 @@
return true;
}
- void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {}
+ void interceptKeyBeforeQueueing(const KeyEvent* inputEvent, uint32_t&) override {
+ if (inputEvent->getAction() == AKEY_EVENT_ACTION_UP) {
+ // Clear intercept state when we handled the event.
+ mInterceptKeyTimeout = 0ms;
+ }
+ }
void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {}
nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*, uint32_t) override {
- return 0;
+ nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count();
+ // Clear intercept state so we could dispatch the event in next wake.
+ mInterceptKeyTimeout = 0ms;
+ return delay;
}
bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t, KeyEvent*) override {
@@ -2182,6 +2199,50 @@
0 /*expectedFlags*/);
}
+TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFocusable(true);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ const std::chrono::milliseconds interceptKeyTimeout = 50ms;
+ const nsecs_t injectTime = keyArgs.eventTime;
+ mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
+ mDispatcher->notifyKey(&keyArgs);
+ // The dispatching time should be always greater than or equal to intercept key timeout.
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+ ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
+ std::chrono::nanoseconds(interceptKeyTimeout).count());
+}
+
+TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFocusable(true);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mFakePolicy->setInterceptKeyTimeout(150ms);
+ mDispatcher->notifyKey(&keyDown);
+ mDispatcher->notifyKey(&keyUp);
+
+ // Window should receive key event immediately when same key up.
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+}
+
/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index aef55d4..4e67a63 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -684,8 +684,10 @@
visibleNonShadowRegion.intersect(outputState.layerStackSpace.getContent()));
outputLayerState.shadowRegion = shadowRegion;
outputLayerState.outputSpaceBlockingRegionHint =
- layerFEState->compositionType == Composition::DISPLAY_DECORATION ? transparentRegion
- : Region();
+ layerFEState->compositionType == Composition::DISPLAY_DECORATION
+ ? outputState.transform.transform(
+ transparentRegion.intersect(outputState.layerStackSpace.getContent()))
+ : Region();
}
void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 6749427..da1f7e4 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -61,6 +61,9 @@
dumpVal(out, "shadowRegion", shadowRegion);
out.append(" ");
+ dumpVal(out, "outputSpaceBlockingRegionHint", outputSpaceBlockingRegionHint);
+
+ out.append(" ");
dumpVal(out, "forceClientComposition", forceClientComposition);
dumpVal(out, "clearClientTarget", clearClientTarget);
dumpVal(out, "displayFrame", displayFrame);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 54eb8f8..66a9ef7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -1310,6 +1310,7 @@
static const Region kLowerHalfBoundsNoRotation;
static const Region kFullBounds90Rotation;
static const Region kTransparentRegionHint;
+ static const Region kTransparentRegionHint90Rotation;
StrictMock<OutputPartialMock> mOutput;
LayerFESet mGeomSnapshots;
@@ -1328,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));
@@ -1779,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()
*/
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 81747d5..66beff2 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -618,15 +618,15 @@
}
}
-void SurfaceFrame::tracePredictions(int64_t displayFrameToken) const {
+void SurfaceFrame::tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedSurfaceFrameStartEvent = event->set_expected_surface_frame_start();
@@ -644,8 +644,8 @@
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedSurfaceFrameEndEvent = event->set_frame_end();
@@ -654,14 +654,14 @@
});
}
-void SurfaceFrame::traceActuals(int64_t displayFrameToken) const {
+void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
// Actual start time is not yet available, so use expected start instead
if (mPredictionState == PredictionState::Expired) {
// If prediction is expired, we can't use the predicted start time. Instead, just use a
@@ -669,11 +669,12 @@
// frame in the trace.
nsecs_t endTime =
(mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime);
- packet->set_timestamp(
- static_cast<uint64_t>(endTime - kPredictionExpiredStartTimeDelta));
+ const auto timestamp = endTime - kPredictionExpiredStartTimeDelta;
+ packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
} else {
- packet->set_timestamp(static_cast<uint64_t>(
- mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime));
+ const auto timestamp =
+ mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime;
+ packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
}
auto* event = packet->set_frame_timeline_event();
@@ -706,11 +707,11 @@
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
if (mPresentState == PresentState::Dropped) {
- packet->set_timestamp(static_cast<uint64_t>(mDropTime));
+ packet->set_timestamp(static_cast<uint64_t>(mDropTime + monoBootOffset));
} else {
- packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
+ packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime + monoBootOffset));
}
auto* event = packet->set_frame_timeline_event();
@@ -723,7 +724,7 @@
/**
* TODO(b/178637512): add inputEventId to the perfetto trace.
*/
-void SurfaceFrame::trace(int64_t displayFrameToken) const {
+void SurfaceFrame::trace(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID ||
displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
// No packets can be traced with a missing token.
@@ -732,9 +733,9 @@
if (getPredictionState() != PredictionState::Expired) {
// Expired predictions have zeroed timestamps. This cannot be used in any meaningful way in
// a trace.
- tracePredictions(displayFrameToken);
+ tracePredictions(displayFrameToken, monoBootOffset);
}
- traceActuals(displayFrameToken);
+ traceActuals(displayFrameToken, monoBootOffset);
}
namespace impl {
@@ -760,8 +761,9 @@
}
FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
- JankClassificationThresholds thresholds)
- : mMaxDisplayFrames(kDefaultMaxDisplayFrames),
+ JankClassificationThresholds thresholds, bool useBootTimeClock)
+ : mUseBootTimeClock(useBootTimeClock),
+ mMaxDisplayFrames(kDefaultMaxDisplayFrames),
mTimeStats(std::move(timeStats)),
mSurfaceFlingerPid(surfaceFlingerPid),
mJankClassificationThresholds(thresholds) {
@@ -1016,14 +1018,16 @@
}
}
-void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid,
+ nsecs_t monoBootOffset) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedDisplayFrameStartEvent = event->set_expected_display_frame_start();
@@ -1037,8 +1041,9 @@
// Expected timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerPredictions.endTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerPredictions.endTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedDisplayFrameEndEvent = event->set_frame_end();
@@ -1047,14 +1052,16 @@
});
}
-void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid,
+ nsecs_t monoBootOffset) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerActuals.startTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerActuals.startTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* actualDisplayFrameStartEvent = event->set_actual_display_frame_start();
@@ -1075,8 +1082,9 @@
// Actual timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerActuals.presentTime));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerActuals.presentTime + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* actualDisplayFrameEndEvent = event->set_frame_end();
@@ -1085,7 +1093,7 @@
});
}
-void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const {
if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
// DisplayFrame should not have an invalid token.
ALOGE("Cannot trace DisplayFrame with invalid token");
@@ -1095,12 +1103,12 @@
if (mPredictionState == PredictionState::Valid) {
// Expired and unknown predictions have zeroed timestamps. This cannot be used in any
// meaningful way in a trace.
- tracePredictions(surfaceFlingerPid);
+ tracePredictions(surfaceFlingerPid, monoBootOffset);
}
- traceActuals(surfaceFlingerPid);
+ traceActuals(surfaceFlingerPid, monoBootOffset);
for (auto& surfaceFrame : mSurfaceFrames) {
- surfaceFrame->trace(mToken);
+ surfaceFrame->trace(mToken, monoBootOffset);
}
}
@@ -1164,6 +1172,12 @@
}
void FrameTimeline::flushPendingPresentFences() {
+ // Perfetto is using boottime clock to void drifts when the device goes
+ // to suspend.
+ const auto monoBootOffset = mUseBootTimeClock
+ ? (systemTime(SYSTEM_TIME_BOOTTIME) - systemTime(SYSTEM_TIME_MONOTONIC))
+ : 0;
+
for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
const auto& pendingPresentFence = mPendingPresentFences[i];
nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
@@ -1175,7 +1189,7 @@
}
auto& displayFrame = pendingPresentFence.second;
displayFrame->onPresent(signalTime, mPreviousPresentTime);
- displayFrame->trace(mSurfaceFlingerPid);
+ displayFrame->trace(mSurfaceFlingerPid, monoBootOffset);
mPreviousPresentTime = signalTime;
mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 36d6290..a2305af 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -204,8 +204,9 @@
std::string miniDump() const;
// Emits a packet for perfetto tracing. The function body will be executed only if tracing is
// enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
- // DisplayFrame at the trace processor side.
- void trace(int64_t displayFrameToken) const;
+ // DisplayFrame at the trace processor side. monoBootOffset is the difference
+ // between SYSTEM_TIME_BOOTTIME and SYSTEM_TIME_MONOTONIC.
+ void trace(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
// Getter functions used only by FrameTimelineTests and SurfaceFrame internally
TimelineItem getActuals() const;
@@ -225,8 +226,8 @@
std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
private:
- void tracePredictions(int64_t displayFrameToken) const;
- void traceActuals(int64_t displayFrameToken) const;
+ void tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
+ void traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
void classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
nsecs_t& deadlineDelta) REQUIRES(mMutex);
@@ -369,8 +370,9 @@
// Dumpsys interface - dumps all data irrespective of jank
void dumpAll(std::string& result, nsecs_t baseTime) const;
// Emits a packet for perfetto tracing. The function body will be executed only if tracing
- // is enabled.
- void trace(pid_t surfaceFlingerPid) const;
+ // is enabled. monoBootOffset is the difference between SYSTEM_TIME_BOOTTIME
+ // and SYSTEM_TIME_MONOTONIC.
+ void trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const;
// Sets the token, vsyncPeriod, predictions and SF start time.
void onSfWakeUp(int64_t token, Fps refreshRate, std::optional<TimelineItem> predictions,
nsecs_t wakeUpTime);
@@ -401,8 +403,8 @@
private:
void dump(std::string& result, nsecs_t baseTime) const;
- void tracePredictions(pid_t surfaceFlingerPid) const;
- void traceActuals(pid_t surfaceFlingerPid) const;
+ void tracePredictions(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const;
+ void traceActuals(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const;
void classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync,
nsecs_t previousPresentTime);
@@ -442,7 +444,7 @@
};
FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
- JankClassificationThresholds thresholds = {});
+ JankClassificationThresholds thresholds = {}, bool useBootTimeClock = true);
~FrameTimeline() = default;
frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
@@ -484,6 +486,7 @@
TokenManager mTokenManager;
TraceCookieCounter mTraceCookieCounter;
mutable std::mutex mMutex;
+ const bool mUseBootTimeClock;
uint32_t mMaxDisplayFrames;
std::shared_ptr<TimeStats> mTimeStats;
const pid_t mSurfaceFlingerPid;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 0fb16f2..48a9bc5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2007 The Android Open Source Project
*
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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 425b78b..bd831ff 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5436,7 +5436,9 @@
/*
* Dump flag/property manager state
*/
- mFlagManager->dump(result);
+ if (mFlagManager != nullptr) {
+ mFlagManager->dump(result);
+ }
result.append(mTimeStats->miniDump());
result.append("\n");
@@ -6499,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
@@ -6640,7 +6629,7 @@
renderArea->render([&] {
renderEngineResultFuture =
- renderScreenImplLocked(*renderArea, traverseLayers, buffer,
+ renderScreenImpl(*renderArea, traverseLayers, buffer,
canCaptureBlackoutContent, regionSampling, grayscale,
captureResults);
});
@@ -6673,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,
@@ -6697,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();
@@ -6715,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 fa65803..81afa9b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -375,6 +375,7 @@
friend class MonitoredProducer;
friend class RefreshRateOverlay;
friend class RegionSamplingThread;
+ friend class LayerRenderArea;
friend class LayerTracing;
// For unit tests
@@ -863,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/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/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 834a560..f1efa92 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -66,9 +66,10 @@
}
void SetUp() override {
+ constexpr bool kUseBootTimeClock = true;
mTimeStats = std::make_shared<mock::TimeStats>();
mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid,
- kTestThresholds);
+ kTestThresholds, !kUseBootTimeClock);
mFrameTimeline->registerDataSource();
mTokenManager = &mFrameTimeline->mTokenManager;
mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
diff --git a/services/surfaceflinger/tests/unittests/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/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});
}