Merge "Move sdk data to target volume when moving app data" into tm-dev
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 87a8eb7..77bed0e 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -458,8 +458,8 @@
return res;
}
-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
- if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid) {
+ if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
PLOG(ERROR) << "Failed to prepare " << path;
return -1;
}
@@ -599,9 +599,9 @@
}
}
-static binder::Status createAppDataDirs(const std::string& path,
- int32_t uid, int32_t* previousUid, int32_t cacheGid,
- const std::string& seInfo, mode_t targetMode) {
+static binder::Status createAppDataDirs(const std::string& path, int32_t uid, int32_t gid,
+ int32_t* previousUid, int32_t cacheGid,
+ const std::string& seInfo, mode_t targetMode) {
struct stat st{};
bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
@@ -625,9 +625,9 @@
}
// Prepare only the parent app directory
- if (prepare_app_dir(path, targetMode, uid) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+ if (prepare_app_dir(path, targetMode, uid, gid) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
return error("Failed to prepare " + path);
}
@@ -686,7 +686,7 @@
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
if (!status.isOk()) {
return status;
}
@@ -711,7 +711,7 @@
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
if (!status.isOk()) {
return status;
}
@@ -772,7 +772,7 @@
LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
#endif
- if (prepare_app_dir(packagePath, 0751, AID_SYSTEM)) {
+ if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM)) {
return error("Failed to prepare " + packagePath);
}
@@ -786,8 +786,8 @@
return exception(binder::Status::EX_ILLEGAL_STATE,
StringPrintf("cacheGid cannot be -1 for sdksandbox data"));
}
- auto status = createAppDataDirs(sharedPath, sdkSandboxUid, &previousSdkSandboxUid, cacheGid,
- seInfo, 0700);
+ auto status = createAppDataDirs(sharedPath, sdkSandboxUid, AID_NOBODY,
+ &previousSdkSandboxUid, cacheGid, seInfo, 0700);
if (!status.isOk()) {
return status;
}
@@ -966,8 +966,8 @@
}
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, &previousSandboxUid, cacheGid, seInfo,
- 0700);
+ auto status = createAppDataDirs(path, sandboxUid, AID_NOBODY, &previousSandboxUid,
+ cacheGid, seInfo, 0700);
if (!status.isOk()) {
res = status;
continue;
@@ -1874,6 +1874,11 @@
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
+ auto sdk_sandbox_de_path =
+ create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+ if (delete_dir_contents_and_dir(sdk_sandbox_de_path, true) != 0) {
+ res = error("Failed to delete " + sdk_sandbox_de_path);
+ }
if (uuid_ == nullptr) {
path = create_data_misc_legacy_path(userId);
if (delete_dir_contents_and_dir(path, true) != 0) {
@@ -1890,6 +1895,11 @@
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
+ auto sdk_sandbox_ce_path =
+ create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+ if (delete_dir_contents_and_dir(sdk_sandbox_ce_path, true) != 0) {
+ res = error("Failed to delete " + sdk_sandbox_ce_path);
+ }
path = findDataMediaPath(uuid, userId);
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 440bac7..04558d5 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -80,12 +80,14 @@
static constexpr const char* kTestUuid = "TEST";
static constexpr const char* 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;
const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+const gid_t kTestCacheGid = multiuser_get_cache_gid(kTestUserId, kTestAppId);
const uid_t kTestSdkSandboxUid = multiuser_get_sdk_sandbox_uid(kTestUserId, kTestAppId);
#define FLAG_FORCE InstalldNativeService::FLAG_FORCE
@@ -965,13 +967,13 @@
class SdkSandboxDataTest : public testing::Test {
public:
- void CheckFileAccess(const std::string& path, uid_t uid, mode_t mode) {
+ void CheckFileAccess(const std::string& path, uid_t uid, gid_t gid, mode_t mode) {
const auto fullPath = "/data/local/tmp/" + path;
ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath;
struct stat st;
ASSERT_EQ(0, stat(fullPath.c_str(), &st));
ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath;
- ASSERT_EQ(uid, st.st_gid) << "For path: " << fullPath;
+ ASSERT_EQ(gid, st.st_gid) << "For path: " << fullPath;
ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath;
}
@@ -985,7 +987,7 @@
args.userId = kTestUserId;
args.appId = kTestAppId;
args.seInfo = "default";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
return args;
}
@@ -1040,25 +1042,28 @@
}
};
-TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData) {
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
const std::string fooCePath = "misc_ce/0/sdksandbox/com.foo";
- CheckFileAccess(fooCePath, kSystemUid, S_IFDIR | 0751);
- CheckFileAccess(fooCePath + "/shared", kTestSdkSandboxUid, S_IFDIR | 0700);
- CheckFileAccess(fooCePath + "/shared/cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(fooCePath + "/shared/code_cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
+ 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, S_IFDIR | 0751);
- CheckFileAccess(fooDePath + "/shared", kTestSdkSandboxUid, S_IFDIR | 0700);
- CheckFileAccess(fooDePath + "/shared/cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(fooDePath + "/shared/code_cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
+ 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) {
@@ -1076,7 +1081,6 @@
TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkAppLevelData_WithoutSdkFlagDeletesExisting) {
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
@@ -1097,7 +1101,7 @@
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
// Only CE paths should exist
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
// DE paths should not exist
ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
@@ -1115,7 +1119,7 @@
ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
// Only DE paths should exist
- CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
+ CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
}
TEST_F(SdkSandboxDataTest, ReconcileSdkData) {
@@ -1126,24 +1130,32 @@
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
const std::string barCePath = "misc_ce/0/sdksandbox/com.foo/bar@random1";
- CheckFileAccess(barCePath, kTestSdkSandboxUid, S_IFDIR | 0700);
- CheckFileAccess(barCePath + "/cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(barCePath + "/code_cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 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, S_IFDIR | 0700);
- CheckFileAccess(bazCePath + "/cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(bazCePath + "/code_cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 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, S_IFDIR | 0700);
- CheckFileAccess(barDePath + "/cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(barDePath + "/code_cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 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, S_IFDIR | 0700);
- CheckFileAccess(bazDePath + "/cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
- CheckFileAccess(bazDePath + "/code_cache", kTestSdkSandboxUid, S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | 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) {
@@ -1181,8 +1193,10 @@
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
// Previous directories from first attempt should exist
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar@random1", kTestSdkSandboxUid, S_IFDIR | 0700);
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, S_IFDIR | 0700);
+ 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"));
@@ -1202,9 +1216,10 @@
ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
// New directoris should exist
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar.diff@random1", kTestSdkSandboxUid,
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar.diff@random1", kTestSdkSandboxUid, kNobodyUid,
S_IFDIR | 0700);
- CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, S_IFDIR | 0700);
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
+ S_IFDIR | 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"));
}
@@ -1215,7 +1230,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
// Destroy the app user data.
@@ -1229,7 +1243,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
// Destroy the app user data.
@@ -1243,7 +1256,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
// Destroy the app user data.
@@ -1280,7 +1292,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
createTestSdkData("com.foo", {"sdk1", "sdk2"});
@@ -1299,7 +1310,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
createTestSdkData("com.foo", {"sdk1", "sdk2"});
@@ -1321,7 +1331,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
createTestSdkData("com.foo", {"sdk1", "sdk2"});
@@ -1340,7 +1349,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
createTestSdkData("com.foo", {"sdk1", "sdk2"});
@@ -1362,7 +1370,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
createTestSdkData("com.foo", {"sdk1", "sdk2"});
@@ -1378,7 +1385,6 @@
android::os::CreateAppDataResult result;
android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
args.packageName = "com.foo";
- args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
// Create the app user data.
ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
createTestSdkData("com.foo", {"sdk1", "sdk2"});
@@ -1390,5 +1396,31 @@
ASSERT_TRUE(fs::is_empty(fs::path("/data/local/tmp/misc_de/0/sdksandbox/com.foo/sdk2")));
}
+class DestroyUserDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithCeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy user data
+ ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_CE));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy user data
+ ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_DE));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
} // namespace installd
} // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 7448308..63d87da 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -166,6 +166,7 @@
"-Wextra-semi",
"-Werror",
"-Wzero-as-null-pointer-constant",
+ "-Wreorder-init-list",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 0970ca5..01b25d3 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -19,6 +19,7 @@
#include <atomic>
#include <set>
+#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
@@ -281,9 +282,11 @@
err = pingBinder();
break;
case EXTENSION_TRANSACTION:
+ CHECK(reply != nullptr);
err = reply->writeStrongBinder(getExtension());
break;
case DEBUG_PID_TRANSACTION:
+ CHECK(reply != nullptr);
err = reply->writeInt32(getDebugPid());
break;
case SET_RPC_CLIENT_TRANSACTION: {
@@ -590,6 +593,7 @@
{
switch (code) {
case INTERFACE_TRANSACTION:
+ CHECK(reply != nullptr);
reply->writeString16(getInterfaceDescriptor());
return NO_ERROR;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 056ef0a..921e57c 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -72,29 +72,29 @@
e.cleanupCookie = cleanupCookie;
e.func = func;
- if (ssize_t idx = mObjects.indexOfKey(objectID); idx >= 0) {
+ if (mObjects.find(objectID) != mObjects.end()) {
ALOGI("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object "
"ID already in use",
objectID, this, object);
- return mObjects[idx].object;
+ return mObjects[objectID].object;
}
- mObjects.add(objectID, e);
+ mObjects.insert({objectID, e});
return nullptr;
}
void* BpBinder::ObjectManager::find(const void* objectID) const
{
- const ssize_t i = mObjects.indexOfKey(objectID);
- if (i < 0) return nullptr;
- return mObjects.valueAt(i).object;
+ auto i = mObjects.find(objectID);
+ if (i == mObjects.end()) return nullptr;
+ return i->second.object;
}
void* BpBinder::ObjectManager::detach(const void* objectID) {
- ssize_t idx = mObjects.indexOfKey(objectID);
- if (idx < 0) return nullptr;
- void* value = mObjects[idx].object;
- mObjects.removeItemsAt(idx, 1);
+ auto i = mObjects.find(objectID);
+ if (i == mObjects.end()) return nullptr;
+ void* value = i->second.object;
+ mObjects.erase(i);
return value;
}
@@ -102,10 +102,10 @@
{
const size_t N = mObjects.size();
ALOGV("Killing %zu objects in manager %p", N, this);
- for (size_t i=0; i<N; i++) {
- const entry_t& e = mObjects.valueAt(i);
+ for (auto i : mObjects) {
+ const entry_t& e = i.second;
if (e.func != nullptr) {
- e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
+ e.func(i.first, e.object, e.cleanupCookie);
}
}
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index bd974b0..9c7ff97 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -31,9 +31,10 @@
#include <binder/Parcel.h>
#include <log/log.h>
-#include <utils/KeyedVector.h>
#include <utils/threads.h>
+#include <map>
+
#define VERBOSE 0
namespace android {
@@ -63,7 +64,7 @@
void free_heap(const wp<IBinder>& binder);
Mutex mHeapCacheLock; // Protects entire vector below.
- KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+ std::map<wp<IBinder>, heap_info_t> mHeapCache;
// We do not use the copy-on-write capabilities of KeyedVector.
// TODO: Reimplemement based on standard C++ container?
};
@@ -434,9 +435,9 @@
sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
{
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info = mHeapCache.editValueAt(i);
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end()) {
+ heap_info_t& info = i->second;
ALOGD_IF(VERBOSE,
"found binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
binder.get(), info.heap.get(),
@@ -452,7 +453,7 @@
info.count = 1;
//ALOGD("adding binder=%p, heap=%p, count=%d",
// binder.get(), info.heap.get(), info.count);
- mHeapCache.add(binder, info);
+ mHeapCache.insert({binder, info});
return info.heap;
}
}
@@ -466,9 +467,9 @@
sp<IMemoryHeap> rel;
{
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info(mHeapCache.editValueAt(i));
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end()) {
+ heap_info_t& info = i->second;
if (--info.count == 0) {
ALOGD_IF(VERBOSE,
"removing binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
@@ -477,8 +478,8 @@
static_cast<BpMemoryHeap*>(info.heap.get())
->mHeapId.load(memory_order_relaxed),
info.count);
- rel = mHeapCache.valueAt(i).heap;
- mHeapCache.removeItemsAt(i);
+ rel = i->second.heap;
+ mHeapCache.erase(i);
}
} else {
ALOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
@@ -490,23 +491,23 @@
{
sp<IMemoryHeap> realHeap;
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
- else realHeap = interface_cast<IMemoryHeap>(binder);
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end())
+ realHeap = i->second.heap;
+ else
+ realHeap = interface_cast<IMemoryHeap>(binder);
return realHeap;
}
void HeapCache::dump_heaps()
{
Mutex::Autolock _l(mHeapCacheLock);
- int c = mHeapCache.size();
- for (int i=0 ; i<c ; i++) {
- const heap_info_t& info = mHeapCache.valueAt(i);
+ for (const auto& i : mHeapCache) {
+ const heap_info_t& info = i.second;
BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
- ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)",
- mHeapCache.keyAt(i).unsafe_get(),
- info.heap.get(), info.count,
- h->mHeapId.load(memory_order_relaxed), h->mBase, h->mSize);
+ ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)", i.first.unsafe_get(),
+ info.heap.get(), info.count, h->mHeapId.load(memory_order_relaxed), h->mBase,
+ h->mSize);
}
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 13f0a4c..f79075d 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1199,7 +1199,8 @@
case BR_DECREFS:
refs = (RefBase::weakref_type*)mIn.readPointer();
- obj = (BBinder*)mIn.readPointer();
+ // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
+ obj = (BBinder*)mIn.readPointer(); // consume
// NOTE: This assertion is not valid, because the object may no
// longer exist (thus the (BBinder*)cast above resulting in a different
// memory address).
@@ -1409,7 +1410,7 @@
uint32_t *async_received)
{
int ret = 0;
- binder_frozen_status_info info;
+ binder_frozen_status_info info = {};
info.pid = pid;
#if defined(__ANDROID__)
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6a138e3..504c6c2 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -63,7 +63,7 @@
// This macro should never be used at runtime, as a too large value
// of s could cause an integer overflow. Instead, you should always
// use the wrapper function pad_size()
-#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3)
+#define PAD_SIZE_UNSAFE(s) (((s) + 3) & ~3UL)
static size_t pad_size(size_t s) {
if (s > (std::numeric_limits<size_t>::max() - 3)) {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index baa817c..b14a838 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -409,6 +409,28 @@
return 0;
}
+#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
+bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
+ static const char* const names[] = {
+ [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
+ DRIVER_FEATURES_PATH "oneway_spam_detection",
+ };
+ int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
+ char on;
+ if (fd == -1) {
+ ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
+ names[static_cast<int>(feature)], strerror(errno));
+ return false;
+ }
+ if (read(fd, &on, sizeof(on)) == -1) {
+ ALOGE("%s: error reading to %s: %s", __func__,
+ names[static_cast<int>(feature)], strerror(errno));
+ return false;
+ }
+ close(fd);
+ return on == '1';
+}
+
status_t ProcessState::enableOnewaySpamDetection(bool enable) {
uint32_t enableDetection = enable ? 1 : 0;
if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) {
@@ -452,7 +474,9 @@
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
if (result == -1) {
- ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+ ALOGE_IF(ProcessState::isDriverFeatureEnabled(
+ ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),
+ "Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
return fd;
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index b84395e..e79cb86 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -152,8 +152,13 @@
}
status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
- return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
- // std::move'd from fd becomes -1 (!ok())
+ // Why passing raw fd? When fd is passed as reference, Clang analyzer sees that the variable
+ // `fd` is a moved-from object. To work-around the issue, unwrap the raw fd from the outer `fd`,
+ // pass the raw fd by value to the lambda, and then finally wrap it in unique_fd inside the
+ // lambda.
+ return setupClient([&, raw = fd.release()](const std::vector<uint8_t>& sessionId,
+ bool incoming) -> status_t {
+ unique_fd fd(raw);
if (!fd.ok()) {
fd = request();
if (!fd.ok()) return BAD_VALUE;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 4ddbce7..2e7084e 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -125,8 +125,8 @@
auto&& [it, inserted] = mNodeForAddress.insert({RpcWireAddress::toRaw(address),
BinderNode{
.binder = binder,
- .timesSent = 1,
.sentRef = binder,
+ .timesSent = 1,
}});
if (inserted) {
*outAddress = it->first;
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index c0454b6..8deb2fe 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -17,10 +17,10 @@
#pragma once
#include <binder/IBinder.h>
-#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
#include <utils/threads.h>
+#include <map>
#include <unordered_map>
#include <variant>
@@ -110,7 +110,7 @@
IBinder::object_cleanup_func func;
};
- KeyedVector<const void*, entry_t> mObjects;
+ std::map<const void*, entry_t> mObjects;
};
class PrivateAccessor {
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index ea40db8..bb55831 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -56,8 +56,16 @@
static const int DUMP_FLAG_PROTO = 1 << 4;
/**
- * Retrieve an existing service, blocking for a few seconds
- * if it doesn't yet exist.
+ * Retrieve an existing service, blocking for a few seconds if it doesn't yet exist. This
+ * does polling. A more efficient way to make sure you unblock as soon as the service is
+ * available is to use waitForService or to use service notifications.
+ *
+ * Warning: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with isDeclared).
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index cf8d8e4..0deee73 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -91,6 +91,12 @@
*/
size_t getThreadPoolMaxThreadCount() const;
+ enum class DriverFeature {
+ ONEWAY_SPAM_DETECTION,
+ };
+ // Determine whether a feature is supported by the binder driver.
+ static bool isDriverFeatureEnabled(const DriverFeature feature);
+
private:
static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 2c471c6..7ea9be7 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -268,7 +268,11 @@
const char* getMessage() const { return AStatus_getMessage(get()); }
std::string getDescription() const {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 30, *)) {
+#else
+ if (__ANDROID_API__ >= 30) {
+#endif
const char* cStr = AStatus_getDescription(get());
std::string ret = cStr;
AStatus_deleteDescription(cStr);
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 09411e7..b3bc7f4 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -256,7 +256,11 @@
// ourselves. The defaults are harmless.
AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
#ifdef HAS_BINDER_SHELL_COMMAND
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 30, *)) {
+#else
+ if (__ANDROID_API__ >= 30) {
+#endif
AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
}
#endif
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 972eca7..28819bb 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -51,7 +51,11 @@
AParcelableHolder(const AParcelableHolder& other)
: mParcel(AParcel_create()), mStability(other.mStability) {
// AParcelableHolder has been introduced in 31.
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
AParcel_getDataSize(other.mParcel.get()));
}
@@ -63,13 +67,21 @@
binder_status_t writeToParcel(AParcel* parcel) const {
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
int32_t size = AParcel_getDataSize(this->mParcel.get());
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
} else {
return STATUS_INVALID_OPERATION;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
int32_t size = AParcel_getDataSize(this->mParcel.get());
RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
} else {
@@ -79,7 +91,11 @@
}
binder_status_t readFromParcel(const AParcel* parcel) {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
} else {
return STATUS_INVALID_OPERATION;
@@ -99,7 +115,11 @@
return STATUS_BAD_VALUE;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
} else {
status = STATUS_INVALID_OPERATION;
@@ -115,7 +135,11 @@
if (this->mStability > T::_aidl_stability) {
return STATUS_BAD_VALUE;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
} else {
return STATUS_INVALID_OPERATION;
@@ -129,7 +153,11 @@
binder_status_t getParcelable(std::optional<T>* ret) const {
const std::string parcelableDesc(T::descriptor);
AParcel_setDataPosition(mParcel.get(), 0);
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
if (AParcel_getDataSize(mParcel.get()) == 0) {
*ret = std::nullopt;
return STATUS_OK;
@@ -153,7 +181,11 @@
}
void reset() {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
}
}
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 2a66941..dfa8ea2 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -53,11 +53,19 @@
/**
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
- * for calling AIBinder_decStrong).
+ * for calling AIBinder_decStrong). This does polling. A more efficient way to make sure you
+ * unblock as soon as the service is available is to use AIBinder_waitForService.
*
* WARNING: when using this API across an APEX boundary, do not use with unstable
* AIDL services. TODO(b/139325195)
*
+ * WARNING: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with AServiceManager_isDeclared).
+ *
* \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 1513eca..45a6d47 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -31,6 +31,7 @@
#include <android-base/unique_fd.h>
#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
+#include <cutils/android_filesystem_config.h>
#include <libbpf.h>
namespace android {
@@ -219,6 +220,7 @@
uint32_t totalFreqsCount = totalTimes.size();
std::vector<uint64_t> allUidTimes(totalFreqsCount, 0);
for (auto const &[uid, uidTimes]: *allUid) {
+ if (uid == AID_SDK_SANDBOX) continue;
for (uint32_t freqIdx = 0; freqIdx < uidTimes[policyIdx].size(); ++freqIdx) {
allUidTimes[std::min(freqIdx, totalFreqsCount - 1)] += uidTimes[policyIdx][freqIdx];
}
@@ -646,5 +648,55 @@
}
}
+void *forceSwitchWithUid(void *uidPtr) {
+ if (!uidPtr) return nullptr;
+ setuid(*(uint32_t *)uidPtr);
+
+ // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ return nullptr;
+}
+
+TEST_F(TimeInStateTest, SdkSandboxUid) {
+ // Find an unused app UID and its corresponding SDK sandbox uid.
+ uint32_t appUid = AID_APP_START, sandboxUid;
+ {
+ auto times = getUidsCpuFreqTimes();
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
+ for (const auto &kv : *times) {
+ if (kv.first > AID_APP_END) break;
+ appUid = std::max(appUid, kv.first);
+ }
+ appUid++;
+ sandboxUid = appUid + (AID_SDK_SANDBOX_PROCESS_START - AID_APP_START);
+ }
+
+ // Create a thread to run with the fake sandbox uid.
+ pthread_t thread;
+ ASSERT_EQ(pthread_create(&thread, NULL, &forceSwitchWithUid, &sandboxUid), 0);
+ pthread_join(thread, NULL);
+
+ // Confirm we recorded stats for appUid and AID_SDK_SANDBOX but not sandboxUid
+ auto allTimes = getUidsCpuFreqTimes();
+ ASSERT_TRUE(allTimes.has_value());
+ ASSERT_FALSE(allTimes->empty());
+ ASSERT_NE(allTimes->find(appUid), allTimes->end());
+ ASSERT_NE(allTimes->find(AID_SDK_SANDBOX), allTimes->end());
+ ASSERT_EQ(allTimes->find(sandboxUid), allTimes->end());
+
+ auto allConcurrentTimes = getUidsConcurrentTimes();
+ ASSERT_TRUE(allConcurrentTimes.has_value());
+ ASSERT_FALSE(allConcurrentTimes->empty());
+ ASSERT_NE(allConcurrentTimes->find(appUid), allConcurrentTimes->end());
+ ASSERT_NE(allConcurrentTimes->find(AID_SDK_SANDBOX), allConcurrentTimes->end());
+ ASSERT_EQ(allConcurrentTimes->find(sandboxUid), allConcurrentTimes->end());
+
+ ASSERT_TRUE(clearUidTimes(appUid));
+}
+
} // namespace bpf
} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index df4db19..455a1e2 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -42,4 +42,7 @@
srcs: [
"LatencyTrackerFuzzer.cpp",
],
+ fuzz_config: {
+ cc: ["android-framework-input@google.com"],
+ },
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e4bd325..7e650a1 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1203,8 +1203,12 @@
// because high frequency consumes extra battery.
const bool expensiveBlurs =
refreshArgs.blursAreExpensive && mLayerRequestingBackgroundBlur != nullptr;
- const bool expensiveRenderingExpected =
- clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3 || expensiveBlurs;
+ const bool expensiveRenderingExpected = expensiveBlurs ||
+ std::any_of(clientCompositionLayers.begin(), clientCompositionLayers.end(),
+ [outputDataspace =
+ clientCompositionDisplay.outputDataspace](const auto& layer) {
+ return layer.sourceDataspace != outputDataspace;
+ });
if (expensiveRenderingExpected) {
setExpensiveRenderingExpected(true);
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 3e983f3..723593d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -325,7 +325,8 @@
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
if (isHdrDataspace(state.dataspace) ||
- getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits) {
+ getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits ||
+ getOutput().getState().displayBrightnessNits == 0.f) {
state.dimmingRatio = 1.f;
state.whitePointNits = getOutput().getState().displayBrightnessNits;
} else {
@@ -506,9 +507,18 @@
to_string(error).c_str(), static_cast<int32_t>(error));
}
- // Don't dim cached layers
- const auto dimmingRatio =
- outputDependentState.overrideInfo.buffer ? 1.f : outputDependentState.dimmingRatio;
+ // Cached layers are not dimmed, which means that composer should attempt to dim.
+ // Note that if the dimming ratio is large, then this may cause the cached layer
+ // to kick back into GPU composition :(
+ // Also note that this assumes that there are no HDR layers that are able to be cached.
+ // Otherwise, this could cause HDR layers to be dimmed twice.
+ const auto dimmingRatio = outputDependentState.overrideInfo.buffer
+ ? (getOutput().getState().displayBrightnessNits != 0.f
+ ? std::clamp(getOutput().getState().sdrWhitePointNits /
+ getOutput().getState().displayBrightnessNits,
+ 0.f, 1.f)
+ : 1.f)
+ : outputDependentState.dimmingRatio;
if (auto error = hwcLayer->setBrightness(dimmingRatio); error != hal::Error::NONE) {
ALOGE("[%s] Failed to set brightness %f: %s (%d)", getLayerFE().getDebugName(),
@@ -788,6 +798,7 @@
}};
settings.sourceDataspace = getState().overrideInfo.dataspace;
settings.alpha = 1.0f;
+ settings.whitePointNits = getOutput().getState().sdrWhitePointNits;
return {static_cast<LayerFE::LayerSettings>(settings)};
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 2203f22..42c1263 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -20,6 +20,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/planner/CachedSet.h>
#include <math/HashCombine.h>
@@ -216,9 +217,8 @@
renderengine::LayerSettings holePunchSettings;
renderengine::LayerSettings holePunchBackgroundSettings;
if (mHolePunchLayer) {
- auto clientCompositionList =
- mHolePunchLayer->getOutputLayer()->getLayerFE().prepareClientCompositionList(
- targetSettings);
+ auto& layerFE = mHolePunchLayer->getOutputLayer()->getLayerFE();
+ auto clientCompositionList = layerFE.prepareClientCompositionList(targetSettings);
// Assume that the final layer contains the buffer that we want to
// replace with a hole punch.
holePunchSettings = clientCompositionList.back();
@@ -227,7 +227,8 @@
holePunchSettings.source.solidColor = half3(0.0f, 0.0f, 0.0f);
holePunchSettings.disableBlending = true;
holePunchSettings.alpha = 0.0f;
- holePunchSettings.name = std::string("hole punch layer");
+ holePunchSettings.name =
+ android::base::StringPrintf("hole punch layer for %s", layerFE.getDebugName());
layerSettings.push_back(holePunchSettings);
// Add a solid background as the first layer in case there is no opaque
@@ -390,7 +391,10 @@
const auto b = mTexture ? mTexture->get()->getBuffer().get() : nullptr;
base::StringAppendF(&result, " Override buffer: %p\n", b);
}
- base::StringAppendF(&result, " HolePunchLayer: %p\n", mHolePunchLayer);
+ base::StringAppendF(&result, " HolePunchLayer: %p\t%s\n", mHolePunchLayer,
+ mHolePunchLayer
+ ? mHolePunchLayer->getOutputLayer()->getLayerFE().getDebugName()
+ : "");
if (mLayers.size() == 1) {
base::StringAppendF(&result, " Layer [%s]\n", mLayers[0].getName().c_str());
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index dda0822..8eb1946 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -657,7 +657,7 @@
EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
}
-TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsCorrectly) {
+TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsAndDimmingRatioCorrectly) {
mOutputState.sdrWhitePointNits = 200.f;
mOutputState.displayBrightnessNits = 800.f;
@@ -665,12 +665,15 @@
mLayerFEState.isColorspaceAgnostic = false;
mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(mOutputState.sdrWhitePointNits, mOutputLayer.getState().whitePointNits);
+ EXPECT_EQ(mOutputState.sdrWhitePointNits / mOutputState.displayBrightnessNits,
+ mOutputLayer.getState().dimmingRatio);
mLayerFEState.dataspace = ui::Dataspace::BT2020_ITU_PQ;
mLayerFEState.isColorspaceAgnostic = false;
mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(mOutputState.displayBrightnessNits, mOutputLayer.getState().whitePointNits);
+ EXPECT_EQ(1.f, mOutputLayer.getState().dimmingRatio);
}
TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
@@ -750,9 +753,10 @@
static constexpr bool kLayerGenericMetadata1Mandatory = true;
static constexpr bool kLayerGenericMetadata2Mandatory = true;
static constexpr float kWhitePointNits = 200.f;
+ static constexpr float kSdrWhitePointNits = 100.f;
static constexpr float kDisplayBrightnessNits = 400.f;
static constexpr float kLayerBrightness = kWhitePointNits / kDisplayBrightnessNits;
- static constexpr float kFullLayerBrightness = 1.f;
+ static constexpr float kOverrideLayerBrightness = kSdrWhitePointNits / kDisplayBrightnessNits;
static const half4 kColor;
static const Rect kDisplayFrame;
@@ -798,6 +802,7 @@
mLayerFEState.acquireFence = kFence;
mOutputState.displayBrightnessNits = kDisplayBrightnessNits;
+ mOutputState.sdrWhitePointNits = kSdrWhitePointNits;
EXPECT_CALL(mOutput, getDisplayColorProfile())
.WillRepeatedly(Return(&mDisplayColorProfile));
@@ -1117,7 +1122,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kFullLayerBrightness);
+ kOverrideSurfaceDamage, kOverrideLayerBrightness);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1133,7 +1138,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kFullLayerBrightness);
+ kOverrideSurfaceDamage, kOverrideLayerBrightness);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1149,7 +1154,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kFullLayerBrightness);
+ kOverrideSurfaceDamage, kOverrideLayerBrightness);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1165,7 +1170,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kFullLayerBrightness);
+ kOverrideSurfaceDamage, kOverrideLayerBrightness);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 0c5ea79..8bbb73c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3986,8 +3986,9 @@
TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDataspaceIsUsed) {
mOutput.mState.dataspace = kExpensiveOutputDataspace;
+ LayerFE::LayerSettings layerSettings;
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kExpensiveOutputDataspace, _))
- .WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>{layerSettings}));
// For this test, we also check the call order of key functions.
InSequence seq;
diff --git a/services/surfaceflinger/Tracing/LocklessStack.h b/services/surfaceflinger/Tracing/LocklessStack.h
new file mode 100644
index 0000000..20f2aa8
--- /dev/null
+++ b/services/surfaceflinger/Tracing/LocklessStack.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <atomic>
+
+template <typename T>
+// Single consumer multi producer stack. We can understand the two operations independently to see
+// why they are without race condition.
+//
+// push is responsible for maintaining a linked list stored in mPush, and called from multiple
+// threads without lock. We can see that if two threads never observe the same value from
+// mPush.load, it just functions as a normal linked list. In the case where two threads observe the
+// same value, one of them has to execute the compare_exchange first. The one that doesn't execute
+// the compare exchange first, will receive false from compare_exchange. previousHead is updated (by
+// compare_exchange) to the most recent value of mPush, and we try again. It's relatively clear to
+// see that the process can repeat with an arbitrary number of threads.
+//
+// Pop is much simpler. If mPop is empty (as it begins) it atomically exchanges
+// the entire push list with null. This is safe, since the only other reader (push)
+// of mPush will retry if it changes in between it's read and atomic compare. We
+// then store the list and pop one element.
+//
+// If we already had something in the pop list we just pop directly.
+class LocklessStack {
+public:
+ class Entry {
+ public:
+ T* mValue;
+ std::atomic<Entry*> mNext;
+ Entry(T* value): mValue(value) {}
+ };
+ std::atomic<Entry*> mPush = nullptr;
+ std::atomic<Entry*> mPop = nullptr;
+ void push(T* value) {
+ Entry* entry = new Entry(value);
+ Entry* previousHead = mPush.load(/*std::memory_order_relaxed*/);
+ do {
+ entry->mNext = previousHead;
+ } while (!mPush.compare_exchange_weak(previousHead, entry)); /*std::memory_order_release*/
+ }
+ T* pop() {
+ Entry* popped = mPop.load(/*std::memory_order_acquire*/);
+ if (popped) {
+ // Single consumer so this is fine
+ mPop.store(popped->mNext/* , std::memory_order_release */);
+ auto value = popped->mValue;
+ delete popped;
+ return value;
+ } else {
+ Entry *grabbedList = mPush.exchange(nullptr/* , std::memory_order_acquire */);
+ if (!grabbedList) return nullptr;
+ mPop.store(grabbedList->mNext/* , std::memory_order_release */);
+ auto value = grabbedList->mValue;
+ delete grabbedList;
+ return value;
+ }
+ }
+};
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 1ec9577..d249b60 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -180,13 +180,13 @@
}
if (layer.what & layer_state_t::eReparent) {
- int32_t layerId = layer.parentSurfaceControlForChild
+ int64_t layerId = layer.parentSurfaceControlForChild
? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle())
: -1;
proto.set_parent_id(layerId);
}
if (layer.what & layer_state_t::eRelativeLayerChanged) {
- int32_t layerId = layer.relativeLayerSurfaceControl
+ int64_t layerId = layer.relativeLayerSurfaceControl
? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle())
: -1;
proto.set_relative_parent_id(layerId);
@@ -342,13 +342,13 @@
outState.merge(state);
if (state.what & layer_state_t::eReparent) {
- outState.parentId = proto.parent_id();
+ outState.parentId = static_cast<int32_t>(proto.parent_id());
}
if (state.what & layer_state_t::eRelativeLayerChanged) {
- outState.relativeParentId = proto.relative_parent_id();
+ outState.relativeParentId = static_cast<int32_t>(proto.relative_parent_id());
}
if (state.what & layer_state_t::eInputInfoChanged) {
- outState.inputCropId = proto.window_info_handle().crop_layer_id();
+ outState.inputCropId = static_cast<int32_t>(proto.window_info_handle().crop_layer_id());
}
if (state.what & layer_state_t::eBufferChanged) {
const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
@@ -364,7 +364,7 @@
}
void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) {
- layer.layerId = proto.layer_id();
+ layer.layerId = (int32_t)proto.layer_id();
layer.what |= proto.what();
layer.surface = mMapper->getLayerHandle(layer.layerId);
@@ -451,23 +451,25 @@
}
if (proto.what() & layer_state_t::eReparent) {
- int32_t layerId = proto.parent_id();
+ int64_t layerId = proto.parent_id();
if (layerId == -1) {
layer.parentSurfaceControlForChild = nullptr;
} else {
layer.parentSurfaceControlForChild =
new SurfaceControl(SurfaceComposerClient::getDefault(),
- mMapper->getLayerHandle(layerId), nullptr, layerId);
+ mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
+ nullptr, static_cast<int32_t>(layerId));
}
}
if (proto.what() & layer_state_t::eRelativeLayerChanged) {
- int32_t layerId = proto.relative_parent_id();
+ int64_t layerId = proto.relative_parent_id();
if (layerId == -1) {
layer.relativeLayerSurfaceControl = nullptr;
} else {
layer.relativeLayerSurfaceControl =
new SurfaceControl(SurfaceComposerClient::getDefault(),
- mMapper->getLayerHandle(layerId), nullptr, layerId);
+ mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
+ nullptr, static_cast<int32_t>(layerId));
}
layer.z = proto.z();
}
@@ -494,8 +496,9 @@
inputInfo.transform.set(transformProto.tx(), transformProto.ty());
inputInfo.replaceTouchableRegionWithCrop =
windowInfoProto.replace_touchable_region_with_crop();
- int32_t layerId = windowInfoProto.crop_layer_id();
- inputInfo.touchableRegionCropHandle = mMapper->getLayerHandle(layerId);
+ int64_t layerId = windowInfoProto.crop_layer_id();
+ inputInfo.touchableRegionCropHandle =
+ mMapper->getLayerHandle(static_cast<int32_t>(layerId));
layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
}
if (proto.what() & layer_state_t::eBackgroundColorChanged) {
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index 2f70b27..872a901 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -80,7 +80,8 @@
public:
virtual ~FlingerDataMapper() = default;
virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; }
- virtual int32_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
+ virtual int64_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
+ virtual int64_t getLayerId(BBinder* /* layerHandle */) const { return -1; }
virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; }
virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; }
virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
@@ -106,6 +107,7 @@
TransactionState fromProto(const proto::TransactionState&);
void mergeFromProto(const proto::LayerState&, TracingLayerState& outState);
void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+ std::unique_ptr<FlingerDataMapper> mMapper;
private:
proto::LayerState toProto(const layer_state_t&);
@@ -113,7 +115,6 @@
void fromProto(const proto::LayerState&, layer_state_t& out);
DisplayState fromProto(const proto::DisplayState&);
- std::unique_ptr<FlingerDataMapper> mMapper;
};
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index d5e837f..6381758 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -29,23 +29,16 @@
namespace android {
-class FlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
- std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
-
+// Keeps the binder address as the layer id so we can avoid holding the tracing lock in the
+// binder thread.
+class FlatDataMapper : public TransactionProtoParser::FlingerDataMapper {
public:
- FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
- : mLayerHandles(layerHandles) {}
-
- int32_t getLayerId(const sp<IBinder>& layerHandle) const override {
+ virtual int64_t getLayerId(const sp<IBinder>& layerHandle) const {
if (layerHandle == nullptr) {
return -1;
}
- auto it = mLayerHandles.find(layerHandle->localBinder());
- if (it == mLayerHandles.end()) {
- ALOGW("Could not find layer handle %p", layerHandle->localBinder());
- return -1;
- }
- return it->second;
+
+ return reinterpret_cast<int64_t>(layerHandle->localBinder());
}
void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
@@ -72,8 +65,33 @@
}
};
+class FlingerDataMapper : public FlatDataMapper {
+ std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
+
+public:
+ FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
+ : mLayerHandles(layerHandles) {}
+
+ int64_t getLayerId(const sp<IBinder>& layerHandle) const override {
+ if (layerHandle == nullptr) {
+ return -1;
+ }
+ return getLayerId(layerHandle->localBinder());
+ }
+
+ int64_t getLayerId(BBinder* localBinder) const {
+ auto it = mLayerHandles.find(localBinder);
+ if (it == mLayerHandles.end()) {
+ ALOGW("Could not find layer handle %p", localBinder);
+ return -1;
+ }
+ return it->second;
+ }
+};
+
TransactionTracing::TransactionTracing()
- : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)) {
+ : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)),
+ mLockfreeProtoParser(std::make_unique<FlatDataMapper>()) {
std::scoped_lock lock(mTraceLock);
mBuffer.setSize(mBufferSizeInBytes);
@@ -129,9 +147,9 @@
}
void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
- std::scoped_lock lock(mTraceLock);
- ATRACE_CALL();
- mQueuedTransactions[transaction.id] = mProtoParser.toProto(transaction);
+ proto::TransactionState* state =
+ new proto::TransactionState(mLockfreeProtoParser.toProto(transaction));
+ mTransactionQueue.push(state);
}
void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
@@ -182,6 +200,38 @@
std::scoped_lock lock(mTraceLock);
std::vector<std::string> removedEntries;
proto::TransactionTraceEntry entryProto;
+
+ while (auto incomingTransaction = mTransactionQueue.pop()) {
+ auto transaction = *incomingTransaction;
+ int32_t layerCount = transaction.layer_changes_size();
+ for (int i = 0; i < layerCount; i++) {
+ auto layer = transaction.mutable_layer_changes(i);
+ layer->set_layer_id(
+ mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(layer->layer_id())));
+ if ((layer->what() & layer_state_t::eReparent) && layer->parent_id() != -1) {
+ layer->set_parent_id(
+ mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
+ layer->parent_id())));
+ }
+
+ if ((layer->what() & layer_state_t::eRelativeLayerChanged) &&
+ layer->relative_parent_id() != -1) {
+ layer->set_relative_parent_id(
+ mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
+ layer->relative_parent_id())));
+ }
+
+ if (layer->has_window_info_handle() &&
+ layer->window_info_handle().crop_layer_id() != -1) {
+ auto input = layer->mutable_window_info_handle();
+ input->set_crop_layer_id(
+ mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
+ input->crop_layer_id())));
+ }
+ }
+ mQueuedTransactions[incomingTransaction->transaction_id()] = transaction;
+ delete incomingTransaction;
+ }
for (const CommittedTransactions& entry : committedTransactions) {
entryProto.set_elapsed_realtime_nanos(entry.timestamp);
entryProto.set_vsync_id(entry.vsyncId);
@@ -317,9 +367,9 @@
// Merge layer states to starting transaction state.
for (const proto::TransactionState& transaction : removedEntry.transactions()) {
for (const proto::LayerState& layerState : transaction.layer_changes()) {
- auto it = mStartingStates.find(layerState.layer_id());
+ auto it = mStartingStates.find((int32_t)layerState.layer_id());
if (it == mStartingStates.end()) {
- ALOGW("Could not find layer id %d", layerState.layer_id());
+ ALOGW("Could not find layer id %d", (int32_t)layerState.layer_id());
continue;
}
mProtoParser.mergeFromProto(layerState, it->second);
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index 95256c4..4c291f9 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -26,6 +26,7 @@
#include <thread>
#include "RingBuffer.h"
+#include "LocklessStack.h"
#include "TransactionProtoParser.h"
using namespace android::surfaceflinger;
@@ -78,6 +79,7 @@
size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE;
std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions
GUARDED_BY(mTraceLock);
+ LocklessStack<proto::TransactionState> mTransactionQueue;
nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
@@ -85,6 +87,9 @@
std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
+ // Parses the transaction to proto without holding any tracing locks so we can generate proto
+ // in the binder thread without any contention.
+ TransactionProtoParser mLockfreeProtoParser;
// We do not want main thread to block so main thread will try to acquire mMainThreadLock,
// otherwise will push data to temporary container.
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index fcf4499..4f99b19 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -70,7 +70,7 @@
// Keep insync with layer_state_t
message LayerState {
- int32 layer_id = 1;
+ int64 layer_id = 1;
// Changes are split into ChangesLsb and ChangesMsb. First 32 bits are in ChangesLsb
// and the next 32 bits are in ChangesMsb. This is needed because enums have to be
// 32 bits and there's no nice way to put 64bit constants into .proto files.
@@ -161,8 +161,8 @@
Matrix22 matrix = 11;
float corner_radius = 12;
uint32 background_blur_radius = 13;
- int32 parent_id = 14;
- int32 relative_parent_id = 15;
+ int64 parent_id = 14;
+ int64 relative_parent_id = 15;
float alpha = 16;
message Color3 {
@@ -233,7 +233,7 @@
bool focusable = 5;
bool has_wallpaper = 6;
float global_scale_factor = 7;
- int32 crop_layer_id = 8;
+ int64 crop_layer_id = 8;
bool replace_touchable_region_with_crop = 9;
RectProto touchable_region_crop = 10;
Transform transform = 11;
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index ab893a3..f5e3b77 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -81,7 +81,7 @@
sp<IBinder> getLayerHandle(int32_t id) const override {
return (id == 42) ? layerHandle : nullptr;
}
- int32_t getLayerId(const sp<IBinder>& handle) const override {
+ int64_t getLayerId(const sp<IBinder>& handle) const override {
return (handle == layerHandle) ? 42 : -1;
}
sp<IBinder> getDisplayHandle(int32_t id) const {