diff options
125 files changed, 5659 insertions, 1488 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 9cdc9e906d..a48dab97cb 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -481,8 +481,8 @@ static bool setClock() newClock = "global"; } - size_t begin = clockStr.find("[") + 1; - size_t end = clockStr.find("]"); + size_t begin = clockStr.find('[') + 1; + size_t end = clockStr.find(']'); if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) { return true; } @@ -543,7 +543,7 @@ static void pokeHalServices() auto listRet = sm->list([&](const auto &interfaces) { for (size_t i = 0; i < interfaces.size(); i++) { string fqInstanceName = interfaces[i]; - string::size_type n = fqInstanceName.find("/"); + string::size_type n = fqInstanceName.find('/'); if (n == std::string::npos || interfaces[i].size() == n+1) continue; hidl_string fqInterfaceName = fqInstanceName.substr(0, n); diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp index 7e05d72eae..014c99593c 100644 --- a/cmds/cmd/cmd.cpp +++ b/cmds/cmd/cmd.cpp @@ -35,12 +35,11 @@ #include <fcntl.h> #include <sys/time.h> #include <errno.h> +#include <memory> #include "selinux/selinux.h" #include "selinux/android.h" -#include <UniquePtr.h> - #define DEBUG 0 using namespace android; @@ -55,7 +54,7 @@ struct SecurityContext_Delete { freecon(p); } }; -typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext; +typedef std::unique_ptr<char[], SecurityContext_Delete> Unique_SecurityContext; class MyShellCallback : public BnShellCallback { diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 657323d90d..9e77e8fbcb 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -691,7 +691,7 @@ bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) { std::string valid_name = entry_name; // Rename extension if necessary. - size_t idx = entry_name.rfind("."); + size_t idx = entry_name.rfind('.'); if (idx != std::string::npos) { std::string extension = entry_name.substr(idx); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); @@ -1432,7 +1432,7 @@ bool Dumpstate::FinishZipFile() { return true; } -static std::string SHA256_file_hash(std::string filepath) { +static std::string SHA256_file_hash(const std::string& filepath) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC | O_NOFOLLOW))); if (fd == -1) { diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index f0e7200069..73c7f18236 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -176,7 +176,7 @@ int Dumpsys::main(int argc, char* const argv[]) { } for (size_t i = 0; i < N; i++) { - String16 service_name = std::move(services[i]); + const String16& service_name = std::move(services[i]); if (IsSkipped(skippedServices, service_name)) continue; sp<IBinder> service = sm_->checkService(service_name); diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 66beb6d4e0..5ca2b578a6 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -95,7 +95,7 @@ MATCHER_P(AndroidElementsAre, expected, "") { } int i = 0; std::ostringstream actual_stream, expected_stream; - for (String16 actual : arg) { + for (const String16& actual : arg) { std::string actual_str = String8(actual).c_str(); std::string expected_str = expected[i]; actual_stream << "'" << actual_str << "' "; diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp index 3eb39b9bed..ea0cd9e4e2 100644 --- a/cmds/installd/CacheTracker.cpp +++ b/cmds/installd/CacheTracker.cpp @@ -60,7 +60,7 @@ void CacheTracker::loadStats() { ATRACE_BEGIN("loadStats tree"); cacheUsed = 0; - for (auto path : mDataPaths) { + for (const auto& path : mDataPaths) { auto cachePath = read_path_inode(path, "cache", kXattrInodeCache); auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache); calculate_tree_size(cachePath, &cacheUsed); @@ -170,7 +170,7 @@ void CacheTracker::loadItems() { items.clear(); ATRACE_BEGIN("loadItems"); - for (auto path : mDataPaths) { + for (const auto& path : mDataPaths) { loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache)); loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache)); } diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index a711813b05..af7455a519 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -311,6 +311,7 @@ static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std return -1; } +#if APPLY_HARD_QUOTAS if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) { auto path = create_data_path(uuid ? uuid->c_str() : nullptr); struct statvfs stat; @@ -335,6 +336,10 @@ static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std // Hard quota already set; assume it's reasonable return 0; } +#else + // Hard quotas disabled + return 0; +#endif } binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid, @@ -1344,7 +1349,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); - for (auto packageName : packageNames) { + for (const auto& packageName : packageNames) { CHECK_ARGUMENT_PACKAGE_NAME(packageName); } // NOTE: Locking is relaxed on this method, since it's limited to @@ -1383,7 +1388,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri } ATRACE_BEGIN("obb"); - for (auto packageName : packageNames) { + for (const auto& packageName : packageNames) { auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str()); calculate_tree_size(obbCodePath, &extStats.codeSize); } @@ -1391,7 +1396,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) { ATRACE_BEGIN("code"); - for (auto codePath : codePaths) { + for (const auto& codePath : codePaths) { calculate_tree_size(codePath, &stats.codeSize, -1, multiuser_get_shared_gid(0, appId)); } @@ -1402,7 +1407,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri ATRACE_END(); } else { ATRACE_BEGIN("code"); - for (auto codePath : codePaths) { + for (const auto& codePath : codePaths) { calculate_tree_size(codePath, &stats.codeSize); } ATRACE_END(); diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index de86cdc4db..8c75ee5739 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -1143,10 +1143,9 @@ class Dex2oatFileWrapper { // (re)Creates the app image if needed. Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided, bool is_public, int uid, bool is_secondary_dex) { - // Use app images only if it is enabled (by a set image format) and we are compiling - // profile-guided (so the app image doesn't conservatively contain all classes). - // Note that we don't create an image for secondary dex files. - if (is_secondary_dex || !profile_guided) { + + // We don't create an image for secondary dex files. + if (is_secondary_dex) { return Dex2oatFileWrapper(); } @@ -1155,6 +1154,14 @@ Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_g // Happens when the out_oat_path has an unknown extension. return Dex2oatFileWrapper(); } + + // Use app images only if it is enabled (by a set image format) and we are compiling + // profile-guided (so the app image doesn't conservatively contain all classes). + if (!profile_guided) { + // In case there is a stale image, remove it now. Ignore any error. + unlink(image_path.c_str()); + return Dex2oatFileWrapper(); + } char app_image_format[kPropertyValueMax]; bool have_app_image_format = get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; @@ -1838,6 +1845,11 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, result = unlink_if_exists(current_profile) && result; result = unlink_if_exists(reference_profile) && result; + // We upgraded once the location of current profile for secondary dex files. + // Check for any previous left-overs and remove them as well. + std::string old_current_profile = dex_path + ".prof"; + result = unlink_if_exists(old_current_profile); + // Try removing the directories as well, they might be empty. result = rmdir_if_empty(oat_isa_dir) && result; result = rmdir_if_empty(oat_dir) && result; diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp index 630c1f3652..443dce6827 100644 --- a/cmds/installd/tests/Android.bp +++ b/cmds/installd/tests/Android.bp @@ -5,13 +5,13 @@ cc_test { srcs: ["installd_utils_test.cpp"], shared_libs: [ "libbase", - "liblog", "libutils", "libcutils", ], static_libs: [ - "libinstalld", "libdiskusage", + "libinstalld", + "liblog", ], } @@ -23,14 +23,14 @@ cc_test { "libbase", "libbinder", "libcutils", - "liblog", - "liblogwrap", "libselinux", "libutils", ], static_libs: [ - "libinstalld", "libdiskusage", + "libinstalld", + "liblog", + "liblogwrap", ], } @@ -42,13 +42,13 @@ cc_test { "libbase", "libbinder", "libcutils", - "liblog", - "liblogwrap", "libselinux", "libutils", ], static_libs: [ - "libinstalld", "libdiskusage", + "libinstalld", + "liblog", + "liblogwrap", ], } diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp index aed068c390..2d58515b11 100644 --- a/cmds/installd/tests/installd_cache_test.cpp +++ b/cmds/installd/tests/installd_cache_test.cpp @@ -99,7 +99,7 @@ static int64_t size(const char* path) { static int64_t free() { struct statvfs buf; if (!statvfs("/data/local/tmp", &buf)) { - return buf.f_bavail * buf.f_frsize; + return static_cast<int64_t>(buf.f_bavail) * buf.f_frsize; } else { PLOG(ERROR) << "Failed to statvfs"; return -1; diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index dab32363c7..46ed85fd59 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -38,16 +38,6 @@ #define TEST_PROFILE_DIR "/data/misc/profiles" -#define REALLY_LONG_APP_NAME "com.example." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - -#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" - namespace android { namespace installd { @@ -88,6 +78,14 @@ protected: virtual void TearDown() { free(android_system_dirs.dirs); } + + std::string create_too_long_path(const std::string& seed) { + std::string result = seed; + for (size_t i = seed.size(); i < PKG_PATH_MAX; i++) { + result += "a"; + } + return result; + } }; TEST_F(UtilsTest, IsValidApkPath_BadPrefix) { @@ -388,17 +386,18 @@ TEST_F(UtilsTest, CreateMovePath_Primary) { << "Primary user package directory should be created correctly"; } + TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) { char path[PKG_PATH_MAX]; - - EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0)) + std::string really_long_app_name = create_too_long_path("com.example"); + EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0)) << "Should fail to create move path for primary user"; } TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) { char path[PKG_PATH_MAX]; - - EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0)) + std::string really_long_leaf_name = create_too_long_path("leaf_"); + EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0)) << "Should fail to create move path for primary user"; } @@ -560,7 +559,7 @@ TEST_F(UtilsTest, CreatePrimaryReferenceProfile) { } TEST_F(UtilsTest, CreateSecondaryCurrentProfile) { - EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof", + EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof", create_current_profile_path(/*user*/0, "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } @@ -571,5 +570,88 @@ TEST_F(UtilsTest, CreateSecondaryReferenceProfile) { "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } +static void pass_secondary_dex_validation(const std::string& package_name, + const std::string& dex_path, int uid, int storage_flag) { + EXPECT_TRUE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid, + storage_flag)) + << dex_path << " should be allowed as a valid secondary dex path"; +} + +static void fail_secondary_dex_validation(const std::string& package_name, + const std::string& dex_path, int uid, int storage_flag) { + EXPECT_FALSE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid, + storage_flag)) + << dex_path << " should not be allowed as a valid secondary dex path"; +} + +TEST_F(UtilsTest, ValidateSecondaryDexFilesPath) { + std::string package_name = "com.test.app"; + std::string app_dir_ce_user_0 = "/data/data/" + package_name; + std::string app_dir_ce_user_10 = "/data/user/10/" + package_name; + + std::string app_dir_de_user_0 = "/data/user_de/0/" + package_name; + std::string app_dir_de_user_10 = "/data/user_de/10/" + package_name; + + EXPECT_EQ(app_dir_ce_user_0, + create_data_user_ce_package_path(nullptr, 0, package_name.c_str())); + EXPECT_EQ(app_dir_ce_user_10, + create_data_user_ce_package_path(nullptr, 10, package_name.c_str())); + + EXPECT_EQ(app_dir_de_user_0, + create_data_user_de_package_path(nullptr, 0, package_name.c_str())); + EXPECT_EQ(app_dir_de_user_10, + create_data_user_de_package_path(nullptr, 10, package_name.c_str())); + + uid_t app_uid_for_user_0 = multiuser_get_uid(/*user_id*/0, /*app_id*/ 1234); + uid_t app_uid_for_user_10 = multiuser_get_uid(/*user_id*/10, /*app_id*/ 1234); + + // Standard path for user 0 on CE storage. + pass_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/ce0.dex", app_uid_for_user_0, FLAG_STORAGE_CE); + // Standard path for user 10 on CE storage. + pass_secondary_dex_validation( + package_name, app_dir_ce_user_10 + "/ce10.dex", app_uid_for_user_10, FLAG_STORAGE_CE); + + // Standard path for user 0 on DE storage. + pass_secondary_dex_validation( + package_name, app_dir_de_user_0 + "/de0.dex", app_uid_for_user_0, FLAG_STORAGE_DE); + // Standard path for user 10 on DE storage. + pass_secondary_dex_validation( + package_name, app_dir_de_user_10 + "/de0.dex", app_uid_for_user_10, FLAG_STORAGE_DE); + + // Dex path for user 0 accessed from user 10. + fail_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/path0_from10.dex", + app_uid_for_user_10, FLAG_STORAGE_CE); + + // Dex path for CE storage accessed with DE. + fail_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/ce_from_de.dex", app_uid_for_user_0, FLAG_STORAGE_DE); + + // Dex path for DE storage accessed with CE. + fail_secondary_dex_validation( + package_name, app_dir_de_user_0 + "/de_from_ce.dex", app_uid_for_user_0, FLAG_STORAGE_CE); + + // Location which does not start with '/'. + fail_secondary_dex_validation( + package_name, "without_slash.dex", app_uid_for_user_10, FLAG_STORAGE_DE); + + // The dex file is not in the specified package directory. + fail_secondary_dex_validation( + "another.package", app_dir_ce_user_0 + "/for_another_package.dex", + app_uid_for_user_0, FLAG_STORAGE_DE); + + // The dex path contains indirect directories. + fail_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/1/../foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE); + fail_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/1/./foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE); + + // Super long path. + std::string too_long = create_too_long_path("too_long_"); + fail_secondary_dex_validation( + package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE); +} + } // namespace installd } // namespace android diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 7c054173b9..d277bd3ad8 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -238,13 +238,38 @@ std::string create_data_dalvik_cache_path() { // Keep profile paths in sync with ActivityThread and LoadedApk. const std::string PROFILE_EXT = ".prof"; +const std::string CURRENT_PROFILE_EXT = ".cur"; const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT; +// Gets the parent directory and the file name for the given secondary dex path. +// Returns true on success, false on failure (if the dex_path does not have the expected +// structure). +static bool get_secondary_dex_location(const std::string& dex_path, + std::string* out_dir_name, std::string* out_file_name) { + size_t dirIndex = dex_path.rfind('/'); + if (dirIndex == std::string::npos) { + return false; + } + if (dirIndex == dex_path.size() - 1) { + return false; + } + *out_dir_name = dex_path.substr(0, dirIndex); + *out_file_name = dex_path.substr(dirIndex + 1); + + return true; +} + std::string create_current_profile_path(userid_t user, const std::string& location, bool is_secondary_dex) { if (is_secondary_dex) { - // Secondary dex profiles are stored next to the dex files using .prof extension. - return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str()); + // Secondary dex current profiles are stored next to the dex files under the oat folder. + std::string dex_dir; + std::string dex_name; + CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name)) + << "Unexpected dir structure for secondary dex " << location; + return StringPrintf("%s/oat/%s%s%s", + dex_dir.c_str(), dex_name.c_str(), CURRENT_PROFILE_EXT.c_str(), + PROFILE_EXT.c_str()); } else { // Profiles for primary apks are under /data/misc/profiles/cur. std::string profile_dir = create_primary_current_profile_package_dir_path(user, location); @@ -255,12 +280,10 @@ std::string create_current_profile_path(userid_t user, const std::string& locati std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) { if (is_secondary_dex) { // Secondary dex reference profiles are stored next to the dex files under the oat folder. - size_t dirIndex = location.rfind('/'); - CHECK(dirIndex != std::string::npos) + std::string dex_dir; + std::string dex_name; + CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name)) << "Unexpected dir structure for secondary dex " << location; - - std::string dex_dir = location.substr(0, dirIndex); - std::string dex_name = location.substr(dirIndex +1); return StringPrintf("%s/oat/%s%s", dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str()); } else { @@ -633,7 +656,7 @@ int copy_dir_files(const char *srcname, int64_t data_disk_free(const std::string& data_path) { struct statvfs sfs; if (statvfs(data_path.c_str(), &sfs) == 0) { - return sfs.f_bavail * sfs.f_frsize; + return static_cast<int64_t>(sfs.f_bavail) * sfs.f_frsize; } else { PLOG(ERROR) << "Couldn't statvfs " << data_path; return -1; @@ -781,21 +804,30 @@ bool validate_secondary_dex_path(const std::string& pkgname, const std::string& const char* volume_uuid, int uid, int storage_flag) { CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE); + // Empty paths are not allowed. + if (dex_path.empty()) { return false; } + // First character should always be '/'. No relative paths. + if (dex_path[0] != '/') { return false; } + // The last character should not be '/'. + if (dex_path[dex_path.size() - 1] == '/') { return false; } + // There should be no '.' after the directory marker. + if (dex_path.find("/.") != std::string::npos) { return false; } + // The path should be at most PKG_PATH_MAX long. + if (dex_path.size() > PKG_PATH_MAX) { return false; } + + // The dex_path should be under the app data directory. std::string app_private_dir = storage_flag == FLAG_STORAGE_CE ? create_data_user_ce_package_path( volume_uuid, multiuser_get_user_id(uid), pkgname.c_str()) : create_data_user_de_package_path( volume_uuid, multiuser_get_user_id(uid), pkgname.c_str()); - dir_rec_t dir; - if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) { - LOG(WARNING) << "Could not get dir rec for " << app_private_dir; + + if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) { return false; } - // Usually secondary dex files have a nested directory structure. - // Pick at most 10 subdirectories when validating (arbitrary value). - // If the secondary dex file is >10 directory nested then validation will - // fail and the file will not be compiled. - return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0; + + // If we got here we have a valid path. + return true; } /** diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 070da84c9e..da3a2933ec 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -36,6 +36,8 @@ #define BYPASS_QUOTA 0 #define BYPASS_SDCARDFS 0 +#define APPLY_HARD_QUOTAS 1 + namespace android { namespace installd { diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp index e2d5f6df0a..0d4a1d193a 100644 --- a/cmds/lshal/Lshal.cpp +++ b/cmds/lshal/Lshal.cpp @@ -69,7 +69,7 @@ void Lshal::usage(const std::string &command) const { " lshal [list] [--interface|-i] [--transport|-t] [-r|--arch] [-e|--threads]\n" " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n" " [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n" - " [--debug|-d[=<output file>]]\n" + " [--debug|-d[=<output file>]] [--neat]\n" " -i, --interface: print the interface name column\n" " -n, --instance: print the instance name column\n" " -t, --transport: print the transport mode column\n" @@ -84,7 +84,8 @@ void Lshal::usage(const std::string &command) const { " IBase::debug with empty options\n" " --sort=i, --sort=interface: sort by interface name\n" " --sort=p, --sort=pid: sort by server pid\n" - " --init-vintf=<output file>: form a skeleton HAL manifest to specified\n" + " --neat: output is machine parsable (no explanatory text)\n" + " --init-vintf[=<output file>]: form a skeleton HAL manifest to specified\n" " file, or stdout if no file specified.\n"; static const std::string debug = diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 35b63ec5c3..2b5389b8dc 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -505,7 +505,7 @@ status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegion ALOGV("Setting Transparent Region Hint"); Region re = Region(); - for (auto r : trhc.region()) { + for (const auto& r : trhc.region()) { Rect rect = Rect(r.left(), r.top(), r.right(), r.bottom()); re.merge(rect); } diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h index 79ddb766c0..1a5ad176e2 100644 --- a/headers/media_plugin/media/openmax/OMX_VideoExt.h +++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h @@ -58,6 +58,12 @@ typedef struct OMX_NALSTREAMFORMATTYPE{ OMX_NALUFORMATSTYPE eNaluFormat; } OMX_NALSTREAMFORMATTYPE; +/** AVC additional profiles */ +typedef enum OMX_VIDEO_AVCPROFILETYPEEXT { + OMX_VIDEO_AVCProfileConstrainedBaseline = 0x10000, /**< Constrained baseline profile */ + OMX_VIDEO_AVCProfileConstrainedHigh = 0x80000, /**< Constrained high profile */ +} OMX_VIDEO_AVCPROFILETYPEEXT; + /** VP8 profiles */ typedef enum OMX_VIDEO_VP8PROFILETYPE { OMX_VIDEO_VP8ProfileMain = 0x01, @@ -164,20 +170,20 @@ typedef enum OMX_VIDEO_VP9PROFILETYPE { /** VP9 levels */ typedef enum OMX_VIDEO_VP9LEVELTYPE { - OMX_VIDEO_VP9Level1 = 0x0, - OMX_VIDEO_VP9Level11 = 0x1, - OMX_VIDEO_VP9Level2 = 0x2, - OMX_VIDEO_VP9Level21 = 0x4, - OMX_VIDEO_VP9Level3 = 0x8, - OMX_VIDEO_VP9Level31 = 0x10, - OMX_VIDEO_VP9Level4 = 0x20, - OMX_VIDEO_VP9Level41 = 0x40, - OMX_VIDEO_VP9Level5 = 0x80, - OMX_VIDEO_VP9Level51 = 0x100, - OMX_VIDEO_VP9Level52 = 0x200, - OMX_VIDEO_VP9Level6 = 0x400, - OMX_VIDEO_VP9Level61 = 0x800, - OMX_VIDEO_VP9Level62 = 0x1000, + OMX_VIDEO_VP9Level1 = 0x1, + OMX_VIDEO_VP9Level11 = 0x2, + OMX_VIDEO_VP9Level2 = 0x4, + OMX_VIDEO_VP9Level21 = 0x8, + OMX_VIDEO_VP9Level3 = 0x10, + OMX_VIDEO_VP9Level31 = 0x20, + OMX_VIDEO_VP9Level4 = 0x40, + OMX_VIDEO_VP9Level41 = 0x80, + OMX_VIDEO_VP9Level5 = 0x100, + OMX_VIDEO_VP9Level51 = 0x200, + OMX_VIDEO_VP9Level52 = 0x400, + OMX_VIDEO_VP9Level6 = 0x800, + OMX_VIDEO_VP9Level61 = 0x1000, + OMX_VIDEO_VP9Level62 = 0x2000, OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF, OMX_VIDEO_VP9LevelMax = 0x7FFFFFFF } OMX_VIDEO_VP9LEVELTYPE; diff --git a/include/android/sensor.h b/include/android/sensor.h index 7f460873b5..2db0ee7fd9 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -197,7 +197,7 @@ enum { * A sensor event. */ -/* NOTE: Must match hardware/sensors.h */ +/* NOTE: changes to these structs have to be backward compatible */ typedef struct ASensorVector { union { float v[3]; @@ -259,7 +259,7 @@ typedef struct { }; } AAdditionalInfoEvent; -/* NOTE: Must match hardware/sensors.h */ +/* NOTE: changes to this struct has to be backward compatible */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ int32_t sensor; @@ -388,13 +388,13 @@ ASensorManager* ASensorManager_getInstance(); #endif #if __ANDROID_API__ >= __ANDROID_API_O__ -/* +/** * Get a reference to the sensor manager. ASensorManager is a singleton * per package as different packages may have access to different sensors. * * Example: * - * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz"); + * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz"); * */ ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName); @@ -503,14 +503,12 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) * {@link ASensor_isDirectChannelTypeSupported}, respectively. * * Example: - * \code{.cpp} - * ASensorManager *manager = ...; - * ASensor *sensor = ...; - * int channelId = ...; * - * ASensorManager_configureDirectReport( - * manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST); - * \endcode + * ASensorManager *manager = ...; + * ASensor *sensor = ...; + * int channelId = ...; + * + * ASensorManager_configureDirectReport(manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST); * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. @@ -530,50 +528,86 @@ int ASensorManager_configureDirectReport( /*****************************************************************************/ /** - * Enable the selected sensor with a specified sampling period and max batch report latency. - * Returns a negative error code on failure. - * Note: To disable the selected sensor, use ASensorEventQueue_disableSensor() same as before. + * Enable the selected sensor with sampling and report parameters + * + * Enable the selected sensor at a specified sampling period and max batch report latency. + * To disable sensor, use {@link ASensorEventQueue_disableSensor}. + * + * \param queue {@link ASensorEventQueue} for sensor event to be report to. + * \param sensor {@link ASensor} to be enabled. + * \param samplingPeriodUs sampling period of sensor in microseconds. + * \param maxBatchReportLatencyus maximum time interval between two batch of sensor events are + * delievered in microseconds. For sensor streaming, set to 0. + * \return 0 on success or a negative error code on failure. */ int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor, int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs); /** - * Enable the selected sensor. Returns a negative error code on failure. + * Enable the selected sensor at default sampling rate. + * + * Start event reports of a sensor to specified sensor event queue at a default rate. + * + * \param queue {@link ASensorEventQueue} for sensor event to be report to. + * \param sensor {@link ASensor} to be enabled. + * + * \return 0 on success or a negative error code on failure. */ int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor); /** - * Disable the selected sensor. Returns a negative error code on failure. + * Disable the selected sensor. + * + * Stop event reports from the sensor to specified sensor event queue. + * + * \param queue {@link ASensorEventQueue} to be changed + * \param sensor {@link ASensor} to be disabled + * \return 0 on success or a negative error code on failure. */ int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor); /** * Sets the delivery rate of events in microseconds for the given sensor. + * + * This function has to be called after {@link ASensorEventQueue_enableSensor}. * Note that this is a hint only, generally event will arrive at a higher * rate. It is an error to set a rate inferior to the value returned by * ASensor_getMinDelay(). - * Returns a negative error code on failure. + * + * \param queue {@link ASensorEventQueue} to which sensor event is delivered. + * \param sensor {@link ASensor} of which sampling rate to be updated. + * \param usec sensor sampling period (1/sampling rate) in microseconds + * \return 0 on sucess or a negative error code on failure. */ int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec); /** - * Returns true if there are one or more events available in the - * sensor queue. Returns 1 if the queue has events; 0 if - * it does not have events; and a negative value if there is an error. + * Determine if a sensor event queue has pending event to be processed. + * + * \param queue {@link ASensorEventQueue} to be queried + * \return 1 if the queue has events; 0 if it does not have events; + * or a negative value if there is an error. */ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); /** - * Returns the next available events from the queue. Returns a negative - * value if no events are available or an error has occurred, otherwise - * the number of events returned. + * Retrieve pending events in sensor event queue + * + * Retrieve next available events from the queue to a specified event array. + * + * \param queue {@link ASensorEventQueue} to get events from + * \param events pointer to an array of {@link ASensorEvents}. + * \param count max number of event that can be filled into array event. + * \return number of events returned on success; negative error code when + * no events are pending or an error has occurred. * * Examples: - * ASensorEvent event; - * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1); * - * ASensorEvent eventBuffer[8]; - * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8); + * ASensorEvent event; + * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1); + * + * ASensorEvent eventBuffer[8]; + * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8); * */ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count); diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h new file mode 100644 index 0000000000..85ac78f9b1 --- /dev/null +++ b/include/android/sharedmem_jni.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup Memory + * @{ + */ + +/** + * @file sharedmem_jni.h + */ + +#ifndef ANDROID_SHARED_MEMORY_JNI_H +#define ANDROID_SHARED_MEMORY_JNI_H + +#include <jni.h> +#include <android/sharedmem.h> +#include <stddef.h> + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +/** + * Structures and functions for a shared memory buffer that can be shared across process. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if __ANDROID_API__ >= __ANDROID_API_O_MR1__ + +/** + * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file + * descriptor has all the same properties & capabilities as the FD returned from + * ASharedMemory_create(), however the protection flags will be the same as those of the + * android.os.SharedMemory object. + * + * Use close() to release the shared memory region. + * + * \param env The JNIEnv* pointer + * \param sharedMemory The Java android.os.SharedMemory object + * \return file descriptor that denotes the shared memory; -1 if the shared memory object is + * already closed, if the JNIEnv or jobject is NULL, or if there are too many open file + * descriptors (errno=EMFILE) + */ +int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory); + +#endif + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_SHARED_MEMORY_JNI_H + +/** @} */ diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 09fd0cb482..83b8021735 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -69,8 +69,13 @@ cc_library { "TextOutput.cpp", "IpPrefix.cpp", "Value.cpp", + "aidl/android/content/pm/IPackageManagerNative.aidl", ], + aidl: { + export_aidl_headers: true, + }, + cflags: [ "-Wall", "-Wextra", diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index e8329613ab..0b390c51c5 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -470,22 +470,33 @@ status_t IPCThreadState::getAndExecuteCommand() void IPCThreadState::processPendingDerefs() { if (mIn.dataPosition() >= mIn.dataSize()) { - size_t numPending = mPendingWeakDerefs.size(); - if (numPending > 0) { - for (size_t i = 0; i < numPending; i++) { - RefBase::weakref_type* refs = mPendingWeakDerefs[i]; + /* + * The decWeak()/decStrong() calls may cause a destructor to run, + * which in turn could have initiated an outgoing transaction, + * which in turn could cause us to add to the pending refs + * vectors; so instead of simply iterating, loop until they're empty. + * + * We do this in an outer loop, because calling decStrong() + * may result in something being added to mPendingWeakDerefs, + * which could be delayed until the next incoming command + * from the driver if we don't process it now. + */ + while (mPendingWeakDerefs.size() > 0 || mPendingStrongDerefs.size() > 0) { + while (mPendingWeakDerefs.size() > 0) { + RefBase::weakref_type* refs = mPendingWeakDerefs[0]; + mPendingWeakDerefs.removeAt(0); refs->decWeak(mProcess.get()); } - mPendingWeakDerefs.clear(); - } - numPending = mPendingStrongDerefs.size(); - if (numPending > 0) { - for (size_t i = 0; i < numPending; i++) { - BBinder* obj = mPendingStrongDerefs[i]; + if (mPendingStrongDerefs.size() > 0) { + // We don't use while() here because we don't want to re-order + // strong and weak decs at all; if this decStrong() causes both a + // decWeak() and a decStrong() to be queued, we want to process + // the decWeak() first. + BBinder* obj = mPendingStrongDerefs[0]; + mPendingStrongDerefs.removeAt(0); obj->decStrong(mProcess.get()); } - mPendingStrongDerefs.clear(); } } } diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl new file mode 100644 index 0000000000..6b7254cbb3 --- /dev/null +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -0,0 +1,41 @@ +/* +** +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm; + +/** + * Parallel implementation of certain {@link PackageManager} APIs that need to + * be exposed to native code. + * <p>These APIs are a parallel definition to the APIs in PackageManager, so, + * they can technically diverge. However, it's good practice to keep these + * APIs in sync with each other. + * <p>Because these APIs are exposed to native code, it's possible they will + * be exposed to privileged components [such as UID 0]. Care should be taken + * to avoid exposing potential security holes for methods where permission + * checks are bypassed based upon UID alone. + * + * @hide + */ +interface IPackageManagerNative { + /** + * Returns a set of names for the given UIDs. + * IMPORTANT: Unlike the Java version of this API, unknown UIDs are + * not represented by 'null's. Instead, they are represented by empty + * strings. + */ + @utf8InCpp String[] getNamesForUids(in int[] uids); +} diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 34aec5be5b..1611e11209 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -28,10 +28,19 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> +#include <sys/epoll.h> + #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) using namespace android; +static ::testing::AssertionResult IsPageAligned(void *buf) { + if (((unsigned long)buf & ((unsigned long)PAGE_SIZE - 1)) == 0) + return ::testing::AssertionSuccess(); + else + return ::testing::AssertionFailure() << buf << " is not page aligned"; +} + static testing::Environment* binder_env; static char *binderservername; static char *binderserversuffix; @@ -43,7 +52,10 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_NOP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, BINDER_LIB_TEST_REGISTER_SERVER, BINDER_LIB_TEST_ADD_SERVER, + BINDER_LIB_TEST_ADD_POLL_SERVER, BINDER_LIB_TEST_CALL_BACK, + BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF, + BINDER_LIB_TEST_DELAYED_CALL_BACK, BINDER_LIB_TEST_NOP_CALL_BACK, BINDER_LIB_TEST_GET_SELF_TRANSACTION, BINDER_LIB_TEST_GET_ID_TRANSACTION, @@ -60,7 +72,7 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, }; -pid_t start_server_process(int arg2) +pid_t start_server_process(int arg2, bool usePoll = false) { int ret; pid_t pid; @@ -68,11 +80,13 @@ pid_t start_server_process(int arg2) int pipefd[2]; char stri[16]; char strpipefd1[16]; + char usepoll[2]; char *childargv[] = { binderservername, binderserverarg, stri, strpipefd1, + usepoll, binderserversuffix, NULL }; @@ -83,6 +97,7 @@ pid_t start_server_process(int arg2) snprintf(stri, sizeof(stri), "%d", arg2); snprintf(strpipefd1, sizeof(strpipefd1), "%d", pipefd[1]); + snprintf(usepoll, sizeof(usepoll), "%d", usePoll ? 1 : 0); pid = fork(); if (pid == -1) @@ -167,14 +182,14 @@ class BinderLibTest : public ::testing::Test { virtual void TearDown() { } protected: - sp<IBinder> addServer(int32_t *idPtr = NULL) + sp<IBinder> addServerEtc(int32_t *idPtr, int code) { int ret; int32_t id; Parcel data, reply; sp<IBinder> binder; - ret = m_server->transact(BINDER_LIB_TEST_ADD_SERVER, data, &reply); + ret = m_server->transact(code, data, &reply); EXPECT_EQ(NO_ERROR, ret); EXPECT_FALSE(binder != NULL); @@ -186,6 +201,17 @@ class BinderLibTest : public ::testing::Test { *idPtr = id; return binder; } + + sp<IBinder> addServer(int32_t *idPtr = NULL) + { + return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_SERVER); + } + + sp<IBinder> addPollServer(int32_t *idPtr = NULL) + { + return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_POLL_SERVER); + } + void waitForReadData(int fd, int timeout_ms) { int ret; pollfd pfd = pollfd(); @@ -265,17 +291,23 @@ class BinderLibTestEvent pthread_mutex_unlock(&m_waitMutex); return ret; } + pthread_t getTriggeringThread() + { + return m_triggeringThread; + } protected: void triggerEvent(void) { pthread_mutex_lock(&m_waitMutex); pthread_cond_signal(&m_waitCond); m_eventTriggered = true; + m_triggeringThread = pthread_self(); pthread_mutex_unlock(&m_waitMutex); }; private: pthread_mutex_t m_waitMutex; pthread_cond_t m_waitCond; bool m_eventTriggered; + pthread_t m_triggeringThread; }; class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent @@ -283,6 +315,7 @@ class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent public: BinderLibTestCallBack() : m_result(NOT_ENOUGH_DATA) + , m_prev_end(NULL) { } status_t getResult(void) @@ -298,16 +331,43 @@ class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent (void)reply; (void)flags; switch(code) { - case BINDER_LIB_TEST_CALL_BACK: - m_result = data.readInt32(); + case BINDER_LIB_TEST_CALL_BACK: { + status_t status = data.readInt32(&m_result); + if (status != NO_ERROR) { + m_result = status; + } triggerEvent(); return NO_ERROR; + } + case BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF: { + sp<IBinder> server; + int ret; + const uint8_t *buf = data.data(); + size_t size = data.dataSize(); + if (m_prev_end) { + /* 64-bit kernel needs at most 8 bytes to align buffer end */ + EXPECT_LE((size_t)(buf - m_prev_end), (size_t)8); + } else { + EXPECT_TRUE(IsPageAligned((void *)buf)); + } + + m_prev_end = buf + size + data.objectsCount() * sizeof(binder_size_t); + + if (size > 0) { + server = static_cast<BinderLibTestEnv *>(binder_env)->getServer(); + ret = server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, + data, reply); + EXPECT_EQ(NO_ERROR, ret); + } + return NO_ERROR; + } default: return UNKNOWN_TRANSACTION; } } status_t m_result; + const uint8_t *m_prev_end; }; class TestDeathRecipient : public IBinder::DeathRecipient, public BinderLibTestEvent @@ -606,6 +666,65 @@ TEST_F(BinderLibTest, DeathNotificationMultiple) } } +TEST_F(BinderLibTest, DeathNotificationThread) +{ + status_t ret; + sp<BinderLibTestCallBack> callback; + sp<IBinder> target = addServer(); + ASSERT_TRUE(target != NULL); + sp<IBinder> client = addServer(); + ASSERT_TRUE(client != NULL); + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + ret = target->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + + { + Parcel data, reply; + ret = target->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(0, ret); + } + + /* Make sure it's dead */ + testDeathRecipient->waitEvent(5); + + /* Now, pass the ref to another process and ask that process to + * call linkToDeath() on it, and wait for a response. This tests + * two things: + * 1) You still get death notifications when calling linkToDeath() + * on a ref that is already dead when it was passed to you. + * 2) That death notifications are not directly pushed to the thread + * registering them, but to the threadpool (proc workqueue) instead. + * + * 2) is tested because the thread handling BINDER_LIB_TEST_DEATH_TRANSACTION + * is blocked on a condition variable waiting for the death notification to be + * called; therefore, that thread is not available for handling proc work. + * So, if the death notification was pushed to the thread workqueue, the callback + * would never be called, and the test would timeout and fail. + * + * Note that we can't do this part of the test from this thread itself, because + * the binder driver would only push death notifications to the thread if + * it is a looper thread, which this thread is not. + * + * See b/23525545 for details. + */ + { + Parcel data, reply; + + callback = new BinderLibTestCallBack(); + data.writeStrongBinder(target); + data.writeStrongBinder(callback); + ret = client->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + } + + ret = callback->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); + ret = callback->getResult(); + EXPECT_EQ(NO_ERROR, ret); +} + TEST_F(BinderLibTest, PassFile) { int ret; int pipefd[2]; @@ -681,10 +800,10 @@ TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) { const flat_binder_object *fb = reply.readObject(false); ASSERT_TRUE(fb != NULL); - EXPECT_EQ(fb->hdr.type, BINDER_TYPE_HANDLE); - EXPECT_EQ(ProcessState::self()->getStrongProxyForHandle(fb->handle), m_server); - EXPECT_EQ(fb->cookie, (binder_uintptr_t)0); - EXPECT_EQ(fb->binder >> 32, (binder_uintptr_t)0); + EXPECT_EQ(BINDER_TYPE_HANDLE, fb->hdr.type); + EXPECT_EQ(m_server, ProcessState::self()->getStrongProxyForHandle(fb->handle)); + EXPECT_EQ((binder_uintptr_t)0, fb->cookie); + EXPECT_EQ((uint64_t)0, (uint64_t)fb->binder >> 32); } TEST_F(BinderLibTest, FreedBinder) { @@ -728,6 +847,61 @@ TEST_F(BinderLibTest, FreedBinder) { } } +TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) { + status_t ret; + Parcel data, reply; + sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack(); + for (int i = 0; i < 2; i++) { + BinderLibTestBundle datai; + datai.appendFrom(&data, 0, data.dataSize()); + + data.freeData(); + data.writeInt32(1); + data.writeStrongBinder(callBack); + data.writeInt32(BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF); + + datai.appendTo(&data); + } + ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); +} + +TEST_F(BinderLibTest, OnewayQueueing) +{ + status_t ret; + Parcel data, data2; + + sp<IBinder> pollServer = addPollServer(); + + sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack(); + data.writeStrongBinder(callBack); + data.writeInt32(500000); // delay in us before calling back + + sp<BinderLibTestCallBack> callBack2 = new BinderLibTestCallBack(); + data2.writeStrongBinder(callBack2); + data2.writeInt32(0); // delay in us + + ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, NULL, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + + // The delay ensures that this second transaction will end up on the async_todo list + // (for a single-threaded server) + ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, NULL, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + + // The server will ensure that the two transactions are handled in the expected order; + // If the ordering is not as expected, an error will be returned through the callbacks. + ret = callBack->waitEvent(2); + EXPECT_EQ(NO_ERROR, ret); + ret = callBack->getResult(); + EXPECT_EQ(NO_ERROR, ret); + + ret = callBack2->waitEvent(2); + EXPECT_EQ(NO_ERROR, ret); + ret = callBack2->getResult(); + EXPECT_EQ(NO_ERROR, ret); +} + class BinderLibTestService : public BBinder { public: @@ -735,6 +909,7 @@ class BinderLibTestService : public BBinder : m_id(id) , m_nextServerId(id + 1) , m_serverStartRequested(false) + , m_callback(NULL) { pthread_mutex_init(&m_serverWaitMutex, NULL); pthread_cond_init(&m_serverWaitCond, NULL); @@ -743,6 +918,16 @@ class BinderLibTestService : public BBinder { exit(EXIT_SUCCESS); } + + void processPendingCall() { + if (m_callback != NULL) { + Parcel data; + data.writeInt32(NO_ERROR); + m_callback->transact(BINDER_LIB_TEST_CALL_BACK, data, nullptr, TF_ONE_WAY); + m_callback = NULL; + } + } + virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) { @@ -774,6 +959,7 @@ class BinderLibTestService : public BBinder pthread_mutex_unlock(&m_serverWaitMutex); return NO_ERROR; } + case BINDER_LIB_TEST_ADD_POLL_SERVER: case BINDER_LIB_TEST_ADD_SERVER: { int ret; uint8_t buf[1] = { 0 }; @@ -788,9 +974,10 @@ class BinderLibTestService : public BBinder } else { serverid = m_nextServerId++; m_serverStartRequested = true; + bool usePoll = code == BINDER_LIB_TEST_ADD_POLL_SERVER; pthread_mutex_unlock(&m_serverWaitMutex); - ret = start_server_process(serverid); + ret = start_server_process(serverid, usePoll); pthread_mutex_lock(&m_serverWaitMutex); } if (ret > 0) { @@ -818,6 +1005,42 @@ class BinderLibTestService : public BBinder } case BINDER_LIB_TEST_NOP_TRANSACTION: return NO_ERROR; + case BINDER_LIB_TEST_DELAYED_CALL_BACK: { + // Note: this transaction is only designed for use with a + // poll() server. See comments around epoll_wait(). + if (m_callback != NULL) { + // A callback was already pending; this means that + // we received a second call while still processing + // the first one. Fail the test. + sp<IBinder> callback = data.readStrongBinder(); + Parcel data2; + data2.writeInt32(UNKNOWN_ERROR); + + callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, NULL, TF_ONE_WAY); + } else { + m_callback = data.readStrongBinder(); + int32_t delayUs = data.readInt32(); + /* + * It's necessary that we sleep here, so the next + * transaction the caller makes will be queued to + * the async queue. + */ + usleep(delayUs); + + /* + * Now when we return, libbinder will tell the kernel + * we are done with this transaction, and the kernel + * can move the queued transaction to either the + * thread todo worklist (for kernels without the fix), + * or the proc todo worklist. In case of the former, + * the next outbound call will pick up the pending + * transaction, which leads to undesired reentrant + * behavior. This is caught in the if() branch above. + */ + } + + return NO_ERROR; + } case BINDER_LIB_TEST_NOP_CALL_BACK: { Parcel data2, reply2; sp<IBinder> binder; @@ -825,7 +1048,7 @@ class BinderLibTestService : public BBinder if (binder == NULL) { return BAD_VALUE; } - reply2.writeInt32(NO_ERROR); + data2.writeInt32(NO_ERROR); binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2); return NO_ERROR; } @@ -967,16 +1190,26 @@ class BinderLibTestService : public BBinder bool m_serverStartRequested; sp<IBinder> m_serverStarted; sp<IBinder> m_strongRef; + bool m_callbackPending; + sp<IBinder> m_callback; }; -int run_server(int index, int readypipefd) +int run_server(int index, int readypipefd, bool usePoll) { binderLibTestServiceName += String16(binderserversuffix); status_t ret; sp<IServiceManager> sm = defaultServiceManager(); + BinderLibTestService* testServicePtr; { sp<BinderLibTestService> testService = new BinderLibTestService(index); + /* + * We need this below, but can't hold a sp<> because it prevents the + * node from being cleaned up automatically. It's safe in this case + * because of how the tests are written. + */ + testServicePtr = testService.get(); + if (index == 0) { ret = sm->addService(binderLibTestServiceName, testService); } else { @@ -994,8 +1227,53 @@ int run_server(int index, int readypipefd) if (ret) return 1; //printf("%s: joinThreadPool\n", __func__); - ProcessState::self()->startThreadPool(); - IPCThreadState::self()->joinThreadPool(); + if (usePoll) { + int fd; + struct epoll_event ev; + int epoll_fd; + IPCThreadState::self()->setupPolling(&fd); + if (fd < 0) { + return 1; + } + IPCThreadState::self()->flushCommands(); // flush BC_ENTER_LOOPER + + epoll_fd = epoll_create1(0); + if (epoll_fd == -1) { + return 1; + } + + ev.events = EPOLLIN; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { + return 1; + } + + while (1) { + /* + * We simulate a single-threaded process using the binder poll + * interface; besides handling binder commands, it can also + * issue outgoing transactions, by storing a callback in + * m_callback and setting m_callbackPending. + * + * processPendingCall() will then issue that transaction. + */ + struct epoll_event events[1]; + int numEvents = epoll_wait(epoll_fd, events, 1, 1000); + if (numEvents < 0) { + if (errno == EINTR) { + continue; + } + return 1; + } + if (numEvents > 0) { + IPCThreadState::self()->handlePolledCommands(); + IPCThreadState::self()->flushCommands(); // flush BC_FREE_BUFFER + testServicePtr->processPendingCall(); + } + } + } else { + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + } //printf("%s: joinThreadPool returned\n", __func__); return 1; /* joinThreadPool should not return */ } @@ -1009,9 +1287,9 @@ int main(int argc, char **argv) { binderservername = argv[0]; } - if (argc == 5 && !strcmp(argv[1], binderserverarg)) { - binderserversuffix = argv[4]; - return run_server(atoi(argv[2]), atoi(argv[3])); + if (argc == 6 && !strcmp(argv[1], binderserverarg)) { + binderserversuffix = argv[5]; + return run_server(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) == 1); } binderserversuffix = new char[16]; snprintf(binderserversuffix, 16, "%d", getpid()); diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 4558fe87c6..21debc1a83 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -20,6 +20,9 @@ cc_library_headers { cc_library_shared { name: "libgui", vendor_available: true, + vndk: { + enabled: true, + }, clang: true, cppflags: [ @@ -93,6 +96,7 @@ cc_library_shared { "IProducerListener.cpp", "ISurfaceComposer.cpp", "ISurfaceComposerClient.cpp", + "LayerDebugInfo.cpp", "LayerState.cpp", "OccupancyTracker.cpp", "StreamSplitter.cpp", diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index d9d50dbeb4..da4295609b 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -19,6 +19,8 @@ //#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <utils/Log.h> +#include <inttypes.h> + #include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> @@ -31,13 +33,13 @@ namespace android { BufferItemConsumer::BufferItemConsumer( - const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage, + const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, int bufferCount, bool controlledByApp) : ConsumerBase(consumer, controlledByApp) { status_t err = mConsumer->setConsumerUsageBits(consumerUsage); LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set consumer usage bits to %#x", consumerUsage); + "Failed to set consumer usage bits to %#" PRIx64, consumerUsage); if (bufferCount != DEFAULT_MAX_BUFFERS) { err = mConsumer->setMaxAcquiredBufferCount(bufferCount); LOG_ALWAYS_FATAL_IF(err != OK, diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 3424012acf..c5cab2d730 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -764,7 +764,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, &transform, &acquireFence, &stickyTransform, &getFrameTimestamps); - Region surfaceDamage = input.getSurfaceDamage(); + const Region& surfaceDamage = input.getSurfaceDamage(); if (acquireFence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); @@ -1102,6 +1102,7 @@ int BufferQueueProducer::query(int what, int *outValue) { value = (mCore->mQueue.size() > 1); break; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: + // deprecated; higher 32 bits are truncated value = static_cast<int32_t>(mCore->mConsumerUsageBits); break; case NATIVE_WINDOW_DEFAULT_DATASPACE: @@ -1547,4 +1548,12 @@ status_t BufferQueueProducer::getUniqueId(uint64_t* outId) const { return NO_ERROR; } +status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const { + BQ_LOGV("getConsumerUsage"); + + Mutex::Autolock lock(mCore->mMutex); + *outUsage = mCore->mConsumerUsageBits; + return NO_ERROR; +} + } // namespace android diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 3d3637648c..7aa7872513 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -335,16 +335,25 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, return OK; } - auto status = mSlots[slot].mFence->getStatus(); - - if (status == Fence::Status::Invalid) { - CB_LOGE("fence has invalid state"); + // Check status of fences first because merging is expensive. + // Merging an invalid fence with any other fence results in an + // invalid fence. + auto currentStatus = mSlots[slot].mFence->getStatus(); + if (currentStatus == Fence::Status::Invalid) { + CB_LOGE("Existing fence has invalid state"); return BAD_VALUE; } - if (status == Fence::Status::Signaled) { + auto incomingStatus = fence->getStatus(); + if (incomingStatus == Fence::Status::Invalid) { + CB_LOGE("New fence has invalid state"); mSlots[slot].mFence = fence; - } else { // status == Fence::Status::Unsignaled + return BAD_VALUE; + } + + // If both fences are signaled or both are unsignaled, we need to merge + // them to get an accurate timestamp. + if (currentStatus == incomingStatus) { char fenceName[32] = {}; snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot); sp<Fence> mergedFence = Fence::merge( @@ -357,7 +366,17 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, return BAD_VALUE; } mSlots[slot].mFence = mergedFence; + } else if (incomingStatus == Fence::Status::Unsignaled) { + // If one fence has signaled and the other hasn't, the unsignaled + // fence will approximately correspond with the correct timestamp. + // There's a small race if both fences signal at about the same time + // and their statuses are retrieved with unfortunate timing. However, + // by this point, they will have both signaled and only the timestamp + // will be slightly off; any dependencies after this point will + // already have been met. + mSlots[slot].mFence = fence; } + // else if (currentStatus == Fence::Status::Unsignaled) is a no-op. return OK; } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 34c9d7805a..14d9937142 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -43,7 +43,7 @@ #include <utils/String8.h> #include <utils/Trace.h> -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define CROP_EXT_STR "EGL_ANDROID_image_crop" #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" #define EGL_PROTECTED_CONTENT_EXT 0x32C0 @@ -1115,7 +1115,7 @@ status_t GLConsumer::setDefaultBufferDataSpace( return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); } -status_t GLConsumer::setConsumerUsageBits(uint32_t usage) { +status_t GLConsumer::setConsumerUsageBits(uint64_t usage) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!"); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 8406a52544..71e22cedf0 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -62,7 +62,8 @@ enum { SET_DEQUEUE_TIMEOUT, GET_LAST_QUEUED_BUFFER, GET_FRAME_TIMESTAMPS, - GET_UNIQUE_ID + GET_UNIQUE_ID, + GET_CONSUMER_USAGE, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -504,6 +505,25 @@ public: } return actualResult; } + + virtual status_t getConsumerUsage(uint64_t* outUsage) const { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + status_t result = remote()->transact(GET_CONSUMER_USAGE, data, &reply); + if (result != NO_ERROR) { + ALOGE("getConsumerUsage failed to transact: %d", result); + } + status_t actualResult = NO_ERROR; + result = reply.readInt32(&actualResult); + if (result != NO_ERROR) { + return result; + } + result = reply.readUint64(outUsage); + if (result != NO_ERROR) { + return result; + } + return actualResult; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -622,6 +642,10 @@ public: status_t getUniqueId(uint64_t* outId) const override { return mBase->getUniqueId(outId); } + + status_t getConsumerUsage(uint64_t* outUsage) const override { + return mBase->getConsumerUsage(outUsage); + } }; IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer, @@ -889,6 +913,20 @@ status_t BnGraphicBufferProducer::onTransact( } return NO_ERROR; } + case GET_CONSUMER_USAGE: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + uint64_t outUsage = 0; + status_t actualResult = getConsumerUsage(&outUsage); + status_t result = reply->writeInt32(actualResult); + if (result != NO_ERROR) { + return result; + } + result = reply->writeUint64(outUsage); + if (result != NO_ERROR) { + return result; + } + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0a0d112af6..8e7f814313 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -28,6 +28,7 @@ #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> +#include <gui/LayerDebugInfo.h> #include <private/gui/LayerState.h> @@ -469,6 +470,36 @@ public: return result; } + virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const + { + if (!outLayers) { + return UNEXPECTED_NULL; + } + + Parcel data, reply; + + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + return err; + } + + err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply); + if (err != NO_ERROR) { + return err; + } + + int32_t result = 0; + err = reply.readInt32(&result); + if (err != NO_ERROR) { + return err; + } + if (result != NO_ERROR) { + return result; + } + + outLayers->clear(); + return reply.readParcelableVector(outLayers); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -763,6 +794,17 @@ status_t BnSurfaceComposer::onTransact( } return injectVSync(when); } + case GET_LAYER_DEBUG_INFO: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + std::vector<LayerDebugInfo> outLayers; + status_t result = getLayerDebugInfo(&outLayers); + reply->writeInt32(result); + if (result == NO_ERROR) + { + result = reply->writeParcelableVector(outLayers); + } + return result; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp new file mode 100644 index 0000000000..57ddde075a --- /dev/null +++ b/libs/gui/LayerDebugInfo.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/LayerDebugInfo.h> + +#include <ui/DebugUtils.h> + +#include <binder/Parcel.h> + +#include <utils/String8.h> + +using namespace android; + +#define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false) + +namespace android { + +status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { + RETURN_ON_ERROR(parcel->writeCString(mName.c_str())); + RETURN_ON_ERROR(parcel->writeCString(mParentName.c_str())); + RETURN_ON_ERROR(parcel->writeCString(mType.c_str())); + RETURN_ON_ERROR(parcel->write(mTransparentRegion)); + RETURN_ON_ERROR(parcel->write(mVisibleRegion)); + RETURN_ON_ERROR(parcel->write(mSurfaceDamageRegion)); + RETURN_ON_ERROR(parcel->writeUint32(mLayerStack)); + RETURN_ON_ERROR(parcel->writeFloat(mX)); + RETURN_ON_ERROR(parcel->writeFloat(mY)); + RETURN_ON_ERROR(parcel->writeUint32(mZ)); + RETURN_ON_ERROR(parcel->writeInt32(mWidth)); + RETURN_ON_ERROR(parcel->writeInt32(mHeight)); + RETURN_ON_ERROR(parcel->write(mCrop)); + RETURN_ON_ERROR(parcel->write(mFinalCrop)); + RETURN_ON_ERROR(parcel->writeFloat(mAlpha)); + RETURN_ON_ERROR(parcel->writeUint32(mFlags)); + RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat)); + RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace))); + for (size_t index = 0; index < 4; index++) { + RETURN_ON_ERROR(parcel->writeFloat(mMatrix[index / 2][index % 2])); + } + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferWidth)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferHeight)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferStride)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferFormat)); + RETURN_ON_ERROR(parcel->writeInt32(mNumQueuedFrames)); + RETURN_ON_ERROR(parcel->writeBool(mRefreshPending)); + RETURN_ON_ERROR(parcel->writeBool(mIsOpaque)); + RETURN_ON_ERROR(parcel->writeBool(mContentDirty)); + return NO_ERROR; +} + +status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) { + mName = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + mParentName = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + mType = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + RETURN_ON_ERROR(parcel->read(mTransparentRegion)); + RETURN_ON_ERROR(parcel->read(mVisibleRegion)); + RETURN_ON_ERROR(parcel->read(mSurfaceDamageRegion)); + RETURN_ON_ERROR(parcel->readUint32(&mLayerStack)); + RETURN_ON_ERROR(parcel->readFloat(&mX)); + RETURN_ON_ERROR(parcel->readFloat(&mY)); + RETURN_ON_ERROR(parcel->readUint32(&mZ)); + RETURN_ON_ERROR(parcel->readInt32(&mWidth)); + RETURN_ON_ERROR(parcel->readInt32(&mHeight)); + RETURN_ON_ERROR(parcel->read(mCrop)); + RETURN_ON_ERROR(parcel->read(mFinalCrop)); + RETURN_ON_ERROR(parcel->readFloat(&mAlpha)); + RETURN_ON_ERROR(parcel->readUint32(&mFlags)); + RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat)); + // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways? + mDataSpace = static_cast<android_dataspace>(parcel->readUint32()); + RETURN_ON_ERROR(parcel->errorCheck()); + for (size_t index = 0; index < 4; index++) { + RETURN_ON_ERROR(parcel->readFloat(&mMatrix[index / 2][index % 2])); + } + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferWidth)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferHeight)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferStride)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferFormat)); + RETURN_ON_ERROR(parcel->readInt32(&mNumQueuedFrames)); + RETURN_ON_ERROR(parcel->readBool(&mRefreshPending)); + RETURN_ON_ERROR(parcel->readBool(&mIsOpaque)); + RETURN_ON_ERROR(parcel->readBool(&mContentDirty)); + return NO_ERROR; +} + +std::string to_string(const LayerDebugInfo& info) { + String8 result; + + result.appendFormat("+ %s (%s)\n", info.mType.c_str(), info.mName.c_str()); + info.mTransparentRegion.dump(result, "TransparentRegion"); + info.mVisibleRegion.dump(result, "VisibleRegion"); + info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion"); + + result.appendFormat(" layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ", + info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY), + info.mWidth, info.mHeight); + + result.appendFormat("crop=%s, finalCrop=%s, ", + to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str()); + result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty); + result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str()); + result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str()); + result.appendFormat("alpha=%.3f, flags=0x%08x, ", + static_cast<double>(info.mAlpha), info.mFlags); + result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]", + static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]), + static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1])); + result.append("\n"); + result.appendFormat(" parent=%s\n", info.mParentName.c_str()); + result.appendFormat(" activeBuffer=[%4ux%4u:%4u,%s],", + info.mActiveBufferWidth, info.mActiveBufferHeight, + info.mActiveBufferStride, + decodePixelFormat(info.mActiveBufferFormat).c_str()); + result.appendFormat(" queued-frames=%d, mRefreshPending=%d", + info.mNumQueuedFrames, info.mRefreshPending); + result.append("\n"); + return std::string(result.c_str()); +} + +} // android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 78eb69d132..6c9d88b599 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -974,6 +974,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_USAGE64: res = dispatchSetUsage64(args); break; + case NATIVE_WINDOW_GET_CONSUMER_USAGE64: + res = dispatchGetConsumerUsage64(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1152,6 +1155,11 @@ int Surface::dispatchGetHdrSupport(va_list args) { return getHdrSupport(outSupport); } +int Surface::dispatchGetConsumerUsage64(va_list args) { + uint64_t* usage = va_arg(args, uint64_t*); + return getConsumerUsage(usage); +} + int Surface::connect(int api) { static sp<IProducerListener> listener = new DummyProducerListener(); return connect(api, listener); @@ -1501,6 +1509,12 @@ int Surface::setBuffersDataSpace(android_dataspace dataSpace) return NO_ERROR; } +android_dataspace_t Surface::getBuffersDataSpace() { + ALOGV("Surface::getBuffersDataSpace"); + Mutex::Autolock lock(mMutex); + return mDataSpace; +} + void Surface::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].buffer = 0; @@ -1721,6 +1735,11 @@ status_t Surface::getUniqueId(uint64_t* outId) const { return mGraphicBufferProducer->getUniqueId(outId); } +int Surface::getConsumerUsage(uint64_t* outUsage) const { + Mutex::Autolock lock(mMutex); + return mGraphicBufferProducer->getConsumerUsage(outUsage); +} + nsecs_t Surface::getLastDequeueStartTime() const { Mutex::Autolock lock(mMutex); return mLastDequeueStartTime; diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp index 187b211be8..afa15c5cda 100644 --- a/libs/gui/SyncFeatures.cpp +++ b/libs/gui/SyncFeatures.cpp @@ -27,7 +27,7 @@ #include <private/gui/SyncFeatures.h> -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp index 4a023a6425..3b89291dc8 100644 --- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp +++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp @@ -21,6 +21,8 @@ #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> #include <gui/bufferqueue/1.0/B2HProducerListener.h> +#include <system/window.h> + namespace android { namespace hardware { namespace graphics { @@ -1232,6 +1234,18 @@ status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const { return transStatus == NO_ERROR ? fnStatus : transStatus; } +status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t* outUsage) const { + ALOGW("getConsumerUsage is not fully supported"); + int result; + status_t transStatus = toStatusT(mBase->query( + NATIVE_WINDOW_CONSUMER_USAGE_BITS, + [&result, outUsage] (int32_t tResult, int32_t tValue) { + result = static_cast<int>(tResult); + *outUsage = static_cast<uint64_t>(tValue); + })); + return transStatus == NO_ERROR ? result : static_cast<int>(transStatus); +} + } // namespace utils } // namespace V1_0 } // namespace bufferqueue diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index 217fe6ad81..d9c57757f5 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -52,7 +52,7 @@ class BufferItemConsumer: public ConsumerBase // controlledByApp tells whether this consumer is controlled by the // application. BufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, - uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, + uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, bool controlledByApp = false); ~BufferItemConsumer() override; diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index d6f215e2c6..5c7ffb416d 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -183,6 +183,9 @@ public: // See IGraphicBufferProducer::getUniqueId virtual status_t getUniqueId(uint64_t* outId) const override; + // See IGraphicBufferProducer::getConsumerUsage + virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp<IBinder>& who); diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 2cf6162fd8..75f2ccaaea 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -210,7 +210,7 @@ public: // so the refactoring can proceed smoothly status_t setDefaultBufferFormat(PixelFormat defaultFormat); status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); - status_t setConsumerUsageBits(uint32_t usage); + status_t setConsumerUsageBits(uint64_t usage); status_t setTransformHint(uint32_t hint); status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); @@ -386,7 +386,7 @@ private: // BufferQueue instance; these will be OR:d with any additional flags passed // from the GLConsumer user. In particular, GLConsumer will always // consume buffers as hardware textures. - static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; + static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; // mCurrentTextureImage is the EglImage/buffer of the current texture. It's // possible that this buffer is not associated with any buffer slot, so we diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index f231f951e7..039dc0d657 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -593,6 +593,12 @@ public: // Returns a unique id for this BufferQueue virtual status_t getUniqueId(uint64_t* outId) const = 0; + + // Returns the consumer usage flags for this BufferQueue. This returns the + // full 64-bit usage flags, rather than the truncated 32-bit usage flags + // returned by querying the now deprecated + // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. + virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index f80ba000b4..b2267426a8 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -39,6 +39,7 @@ struct ComposerState; struct DisplayState; struct DisplayInfo; struct DisplayStatInfo; +class LayerDebugInfo; class HdrCapabilities; class IDisplayEventConnection; class IGraphicBufferProducer; @@ -195,6 +196,12 @@ public: virtual status_t enableVSyncInjections(bool enable) = 0; virtual status_t injectVSync(nsecs_t when) = 0; + + /* Gets the list of active layers in Z order for debugging purposes + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0; }; // ---------------------------------------------------------------------------- @@ -229,6 +236,7 @@ public: SET_ACTIVE_COLOR_MODE, ENABLE_VSYNC_INJECTIONS, INJECT_VSYNC, + GET_LAYER_DEBUG_INFO, CREATE_SCOPED_CONNECTION }; diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h new file mode 100644 index 0000000000..8453e043ef --- /dev/null +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <binder/Parcelable.h> + +#include <ui/PixelFormat.h> +#include <ui/Region.h> + +#include <string> + +namespace android { + +/* Class for transporting debug info from SurfaceFlinger to authorized + * recipients. The class is intended to be a data container. There are + * no getters or setters. + */ +class LayerDebugInfo : public Parcelable { +public: + LayerDebugInfo() = default; + LayerDebugInfo(const LayerDebugInfo&) = default; + virtual ~LayerDebugInfo() = default; + + virtual status_t writeToParcel(Parcel* parcel) const; + virtual status_t readFromParcel(const Parcel* parcel); + + std::string mName = std::string("NOT FILLED"); + std::string mParentName = std::string("NOT FILLED"); + std::string mType = std::string("NOT FILLED"); + Region mTransparentRegion = Region::INVALID_REGION; + Region mVisibleRegion = Region::INVALID_REGION; + Region mSurfaceDamageRegion = Region::INVALID_REGION; + uint32_t mLayerStack = 0; + float mX = 0.f; + float mY = 0.f; + uint32_t mZ = 0 ; + int32_t mWidth = -1; + int32_t mHeight = -1; + Rect mCrop = Rect::INVALID_RECT; + Rect mFinalCrop = Rect::INVALID_RECT; + float mAlpha = 0.f; + uint32_t mFlags = 0; + PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; + android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + // Row-major transform matrix (SurfaceControl::setMatrix()) + float mMatrix[2][2] = {{0.f, 0.f}, {0.f, 0.f}}; + int32_t mActiveBufferWidth = -1; + int32_t mActiveBufferHeight = -1; + int32_t mActiveBufferStride = 0; + PixelFormat mActiveBufferFormat = PIXEL_FORMAT_NONE; + int32_t mNumQueuedFrames = -1; + bool mRefreshPending = false; + bool mIsOpaque = false; + bool mContentDirty = false; +}; + +std::string to_string(const LayerDebugInfo& info); + +} // namespace android diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 60eac0cf92..3fe29d955b 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -159,6 +159,7 @@ public: status_t getHdrSupport(bool* supported); status_t getUniqueId(uint64_t* outId) const; + status_t getConsumerUsage(uint64_t* outUsage) const; // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call nsecs_t getLastDequeueStartTime() const; @@ -223,6 +224,7 @@ private: int dispatchGetFrameTimestamps(va_list args); int dispatchGetWideColorSupport(va_list args); int dispatchGetHdrSupport(va_list args); + int dispatchGetConsumerUsage64(va_list args); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); @@ -279,6 +281,8 @@ public: // detachNextBuffer, or attachBuffer call. status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out); + android_dataspace_t getBuffersDataSpace(); + protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 8bb705cf77..c15209d32c 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -90,6 +90,16 @@ public: status_t setFlags(uint32_t flags, uint32_t mask); status_t setTransparentRegionHint(const Region& transparent); status_t setAlpha(float alpha=1.0f); + + // Experimentarily it appears that the matrix transforms the + // on-screen rectangle and it's contents before the position is + // applied. + // + // TODO: Test with other combinations to find approximate transformation rules. + // + // For example: + // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives + // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y)) status_t setMatrix(float dsdx, float dtdx, float dtdy, float dsdy); status_t setCrop(const Rect& crop); status_t setFinalCrop(const Rect& crop); diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h index c1c3ae730d..74850b4879 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h @@ -94,6 +94,7 @@ struct H2BGraphicBufferProducer : public ::android::H2BConverter< sp<Fence>* outFence, float outTransformMatrix[16]) override; void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override; status_t getUniqueId(uint64_t* outId) const override; + status_t getConsumerUsage(uint64_t* outUsage) const override; }; } // namespace utils diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp index 2b9fd5d4b6..bb6b8a59fe 100644 --- a/libs/gui/tests/Malicious.cpp +++ b/libs/gui/tests/Malicious.cpp @@ -92,6 +92,9 @@ public: } void getFrameTimestamps(FrameEventHistoryDelta*) override {} status_t getUniqueId(uint64_t* outId) const override { return mProducer->getUniqueId(outId); } + status_t getConsumerUsage(uint64_t* outUsage) const override { + return mProducer->getConsumerUsage(outUsage); + } protected: sp<IGraphicBufferProducer> mProducer; diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index bd598e419e..d5b2f004ed 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -28,7 +28,7 @@ #include <utils/Log.h> #include <utils/Thread.h> -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define CROP_EXT_STR "EGL_ANDROID_image_crop" namespace android { diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e18af17bde..45e95a593b 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -539,6 +539,9 @@ public: return NO_ERROR; } status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; } + status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override { + return NO_ERROR; + } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index d8dc9575ba..9abd04ca04 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -450,7 +450,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, break; } - case AINPUT_EVENT_TYPE_MOTION: { + case InputMessage::TYPE_MOTION: { ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source); if (batchIndex >= 0) { Batch& batch = mBatches.editItemAt(batchIndex); diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index cc74b9b5cf..a914408297 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -105,7 +105,7 @@ static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool r // this is the strategy that applications will actually use. Be very careful // when adjusting the default strategy because it can dramatically affect // (often in a bad way) the user experience. -const char* VelocityTracker::DEFAULT_STRATEGY = "impulse"; +const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2"; VelocityTracker::VelocityTracker(const char* strategy) : mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) { diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 3df97a1b4a..64908049d6 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -115,7 +115,7 @@ enum { * The consumer gralloc usage bits currently set by the consumer. * The values are defined in hardware/libhardware/include/gralloc.h. */ - NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, + NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, /* deprecated */ /** * Transformation that will by applied to buffers by the hwcomposer. @@ -224,6 +224,7 @@ enum { NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, NATIVE_WINDOW_GET_HDR_SUPPORT = 29, NATIVE_WINDOW_SET_USAGE64 = 30, + NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, // clang-format on }; @@ -900,13 +901,18 @@ static inline int native_window_get_frame_timestamps( static inline int native_window_get_wide_color_support( struct ANativeWindow* window, bool* outSupport) { - return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT, - outSupport); + return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT, + outSupport); } static inline int native_window_get_hdr_support(struct ANativeWindow* window, bool* outSupport) { - return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport); + return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport); +} + +static inline int native_window_get_consumer_usage(struct ANativeWindow* window, + uint64_t* outUsage) { + return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage); } __END_DECLS diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS new file mode 100644 index 0000000000..6a38a1ff14 --- /dev/null +++ b/libs/sensor/OWNERS @@ -0,0 +1,2 @@ +ashutoshj@google.com +pengxu@google.com diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 6630d9060a..cabe94ef78 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -15,6 +15,9 @@ cc_library_shared { name: "libui", vendor_available: true, + vndk: { + enabled: true, + }, clang: true, cppflags: [ diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index 6e31d2a2c4..2d72944665 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -16,10 +16,13 @@ #include <ui/DebugUtils.h> #include <ui/PixelFormat.h> +#include <ui/Rect.h> #include <android-base/stringprintf.h> #include <string> +using android::base::StringPrintf; + std::string decodeStandard(android_dataspace dataspace) { const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK); switch (dataspaceSelect) { @@ -262,3 +265,7 @@ std::string decodePixelFormat(android::PixelFormat format) { return android::base::StringPrintf("Unknown %#08x", format); } } + +std::string to_string(const android::Rect& rect) { + return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom); +} diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp index 39adc5e929..755e60c82e 100644 --- a/libs/ui/HdrCapabilities.cpp +++ b/libs/ui/HdrCapabilities.cpp @@ -76,7 +76,7 @@ status_t HdrCapabilities::unflatten(void const* buffer, size_t size) { mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]); mMinLuminance = reinterpret_cast<float const&>(buf[2]); if (itemCount) { - mSupportedHdrTypes.reserve(itemCount); + mSupportedHdrTypes.resize(itemCount); for (size_t i = 0; i < itemCount; ++i) { mSupportedHdrTypes[i] = buf[4 + i]; } diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h index 30f4a59fe0..dad9446b3a 100644 --- a/libs/ui/include/ui/DebugUtils.h +++ b/libs/ui/include/ui/DebugUtils.h @@ -21,9 +21,14 @@ #include <string> +namespace android { +class Rect; +} + std::string decodeStandard(android_dataspace dataspace); std::string decodeTransfer(android_dataspace dataspace); std::string decodeRange(android_dataspace dataspace); std::string dataspaceDetails(android_dataspace dataspace); std::string decodeColorMode(android_color_mode colormode); std::string decodePixelFormat(android::PixelFormat format); +std::string to_string(const android::Rect& rect); diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index bfb9a55e93..f9f87ff1b8 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp @@ -417,6 +417,28 @@ void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) { on_buffer_removed_ = callback; } +pdx::Status<void> BufferHubQueue::FreeAllBuffers() { + // Clear all available buffers. + available_buffers_.Clear(); + + pdx::Status<void> last_error; // No error. + // Clear all buffers this producer queue is tracking. + for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { + if (buffers_[slot] != nullptr) { + auto status = RemoveBuffer(slot); + if (!status) { + ALOGE( + "ProducerQueue::FreeAllBuffers: Failed to remove buffer at " + "slot=%d.", + slot); + last_error = status.error_status(); + } + } + } + + return last_error; +} + ProducerQueue::ProducerQueue(LocalChannelHandle handle) : BASE(std::move(handle)) { auto status = ImportQueue(); diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp index 6613add0a1..53eed8924a 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp @@ -206,11 +206,11 @@ status_t BufferHubQueueProducer::dequeueBuffer( // It's either in free state (if the buffer has never been used before) or // in queued state (if the buffer has been dequeued and queued back to // BufferHubQueue). - // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's - // model. - LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() && - !buffers_[slot].mBufferState.isQueued()), - "dequeueBuffer: slot %zu is not free or queued.", slot); + LOG_ALWAYS_FATAL_IF( + (!buffers_[slot].mBufferState.isFree() && + !buffers_[slot].mBufferState.isQueued()), + "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot, + buffers_[slot].mBufferState.string()); buffers_[slot].mBufferState.freeQueued(); buffers_[slot].mBufferState.dequeue(); @@ -514,6 +514,7 @@ status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode /*mode*/) { return BAD_VALUE; } + FreeAllBuffers(); connected_api_ = kNoConnectedApi; return NO_ERROR; } @@ -608,6 +609,14 @@ status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const { return NO_ERROR; } +status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const { + ALOGD_IF(TRACE, __FUNCTION__); + + // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS + *out_usage = 0; + return NO_ERROR; +} + status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, PixelFormat format, @@ -647,5 +656,31 @@ status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) { return NO_ERROR; } +status_t BufferHubQueueProducer::FreeAllBuffers() { + for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { + // Reset in memory objects related the the buffer. + buffers_[slot].mGraphicBuffer = nullptr; + buffers_[slot].mBufferState.reset(); + buffers_[slot].mRequestBufferCalled = false; + buffers_[slot].mBufferProducer = nullptr; + buffers_[slot].mFence = Fence::NO_FENCE; + } + + auto status = queue_->FreeAllBuffers(); + if (!status) { + ALOGE( + "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on " + "the queue: %s", + status.GetErrorMessage().c_str()); + } + + if (queue_->capacity() != 0 || queue_->count() != 0) { + LOG_ALWAYS_FATAL( + "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed."); + } + + return NO_ERROR; +} + } // namespace dvr } // namespace android diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index d57c7af882..3e93788521 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h @@ -122,6 +122,10 @@ class BufferHubQueue : public pdx::Client { // to deregister a buffer for epoll and internal bookkeeping. virtual pdx::Status<void> RemoveBuffer(size_t slot); + // Free all buffers that belongs to this queue. Can only be called from + // producer side. + virtual pdx::Status<void> FreeAllBuffers(); + // Dequeue a buffer from the free queue, blocking until one is available. The // timeout argument specifies the number of milliseconds that |Dequeue()| will // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely, @@ -297,6 +301,11 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // Remove producer buffer from the queue. pdx::Status<void> RemoveBuffer(size_t slot) override; + // Free all buffers on this producer queue. + pdx::Status<void> FreeAllBuffers() override { + return BufferHubQueue::FreeAllBuffers(); + } + // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode, // and caller should call Post() once it's done writing to release the buffer // to the consumer side. diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h index d33a831469..7ed55fb533 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h @@ -112,6 +112,9 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // See |IGraphicBufferProducer::getUniqueId| status_t getUniqueId(uint64_t* out_id) const override; + // See |IGraphicBufferProducer::getConsumerUsage| + status_t getConsumerUsage(uint64_t* out_usage) const override; + private: using LocalHandle = pdx::LocalHandle; @@ -132,6 +135,10 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // Remove a buffer via BufferHubRPC. status_t RemoveBuffer(size_t slot); + // Free all buffers which are owned by the prodcuer. Note that if graphic + // buffers are acquired by the consumer, we can't . + status_t FreeAllBuffers(); + // Concreate implementation backed by BufferHubBuffer. std::shared_ptr<ProducerQueue> queue_; diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp index e0a4052ec2..7581a065b3 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp @@ -570,6 +570,103 @@ TEST_F(BufferHubQueueTest, TestQueueInfo) { EXPECT_EQ(consumer_queue_->is_async(), kIsAsync); } +TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { + constexpr size_t kBufferCount = 2; + +#define CHECK_NO_BUFFER_THEN_ALLOCATE(num_buffers) \ + EXPECT_EQ(consumer_queue_->count(), 0U); \ + EXPECT_EQ(consumer_queue_->capacity(), 0U); \ + EXPECT_EQ(producer_queue_->count(), 0U); \ + EXPECT_EQ(producer_queue_->capacity(), 0U); \ + for (size_t i = 0; i < num_buffers; i++) { \ + AllocateBuffer(); \ + } \ + EXPECT_EQ(producer_queue_->count(), num_buffers); \ + EXPECT_EQ(producer_queue_->capacity(), num_buffers); + + size_t slot; + uint64_t seq; + LocalHandle fence; + pdx::Status<void> status; + pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status; + pdx::Status<std::shared_ptr<BufferProducer>> producer_status; + std::shared_ptr<BufferConsumer> consumer_buffer; + std::shared_ptr<BufferProducer> producer_buffer; + + ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), + UsagePolicy{})); + + // Free all buffers when buffers are avaible for dequeue. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when one buffer is dequeued. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when all buffers are dequeued. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + for (size_t i = 0; i < kBufferCount; i++) { + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + } + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when one buffer is posted. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + producer_buffer = producer_status.take(); + ASSERT_NE(nullptr, producer_buffer); + ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when all buffers are posted. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + for (size_t i = 0; i < kBufferCount; i++) { + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + producer_buffer = producer_status.take(); + ASSERT_NE(nullptr, producer_buffer); + ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + } + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when all buffers are acquired. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + for (size_t i = 0; i < kBufferCount; i++) { + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + producer_buffer = producer_status.take(); + ASSERT_NE(nullptr, producer_buffer); + ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence); + ASSERT_TRUE(consumer_status.ok()); + } + + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // In addition to FreeAllBuffers() from the queue, it is also required to + // delete all references to the ProducerBuffer (i.e. the PDX client). + producer_buffer = nullptr; + + // Crank consumer queue events to pickup EPOLLHUP events on the queue. + consumer_queue_->HandleQueueEvents(); + + // One last check. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + +#undef CHECK_NO_BUFFER_THEN_ALLOCATE +} + } // namespace } // namespace dvr diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp index 8f55125125..28cd63af2d 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp @@ -508,6 +508,44 @@ TEST_F(BufferHubQueueProducerTest, ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE)); } +TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) { + int slot = -1; + sp<GraphicBuffer> buffer; + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + + EXPECT_NO_FATAL_FAILURE(ConnectProducer()); + + constexpr int maxDequeuedBuffers = 1; + int minUndequeuedBuffers; + EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers)); + EXPECT_EQ(NO_ERROR, mProducer->setAsyncMode(false)); + EXPECT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers)); + + int maxCapacity = maxDequeuedBuffers + minUndequeuedBuffers; + + // Dequeue, request, and queue all buffers. + for (int i = 0; i < maxCapacity; i++) { + EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output)); + } + + // Disconnect then reconnect. + EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); + EXPECT_NO_FATAL_FAILURE(ConnectProducer()); + + // Dequeue, request, and queue all buffers. + for (int i = 0; i < maxCapacity; i++) { + EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output)); + } + + EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); +} + } // namespace } // namespace dvr diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp index 018abbb2a7..e4e20f9700 100644 --- a/libs/vr/libdvr/dvr_buffer_queue.cpp +++ b/libs/vr/libdvr/dvr_buffer_queue.cpp @@ -14,6 +14,8 @@ using android::dvr::BufferHubQueueProducer; using android::dvr::BufferProducer; using android::dvr::ConsumerQueue; using android::dvr::ProducerQueue; +using android::dvr::ProducerQueueConfigBuilder; +using android::dvr::UsagePolicy; extern "C" { @@ -156,6 +158,36 @@ int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) { return 0; } +int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format, + uint32_t layer_count, uint64_t usage, + size_t capacity, size_t metadata_size, + DvrWriteBufferQueue** out_write_queue) { + if (!out_write_queue) + return -EINVAL; + + auto config_builder = ProducerQueueConfigBuilder() + .SetDefaultWidth(width) + .SetDefaultHeight(height) + .SetDefaultFormat(format) + .SetMetadataSize(metadata_size); + std::unique_ptr<ProducerQueue> producer_queue = + ProducerQueue::Create(config_builder.Build(), UsagePolicy{}); + if (!producer_queue) { + ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue."); + return -ENOMEM; + } + + auto status = producer_queue->AllocateBuffers(width, height, layer_count, + format, usage, capacity); + if (!status.ok()) { + ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers."); + return -ENOMEM; + } + + *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue)); + return 0; +} + void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) { delete write_queue; } diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index d0dbd8d390..451d037352 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -159,6 +159,12 @@ typedef const struct native_handle* (*DvrBufferGetNativeHandlePtr)( DvrBuffer* buffer); // dvr_buffer_queue.h +typedef int (*DvrWriteBufferQueueCreatePtr)(uint32_t width, uint32_t height, + uint32_t format, + uint32_t layer_count, + uint64_t usage, size_t capacity, + size_t metadata_size, + DvrWriteBufferQueue** queue_out); typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue); typedef ssize_t (*DvrWriteBufferQueueGetCapacityPtr)( DvrWriteBufferQueue* write_queue); diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h index 72e0f674f4..da12c13065 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h +++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h @@ -160,3 +160,6 @@ DVR_V1_API_ENTRY(PoseClientSensorsEnable); // Read buffer queue DVR_V1_API_ENTRY(ReadBufferQueueGetEventFd); + +// Create write buffer queue locally +DVR_V1_API_ENTRY(WriteBufferQueueCreate); diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h index e2127f8e31..b3b41e2373 100644 --- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h +++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h @@ -12,6 +12,36 @@ typedef struct ANativeWindow ANativeWindow; typedef struct DvrWriteBufferQueue DvrWriteBufferQueue; typedef struct DvrReadBufferQueue DvrReadBufferQueue; +// Creates a write buffer queue to be used locally. +// +// Note that this API is mostly for testing purpose. For now there is no +// mechanism to send a DvrWriteBufferQueue cross process. Use +// dvrSurfaceCreateWriteBufferQueue if cross-process buffer transport is +// intended. +// +// @param width The width of the buffers that this queue will produce. +// @param height The height of buffers that this queue will produce. +// @param format The format of the buffers that this queue will produce. This +// must be one of the AHARDWAREBUFFER_FORMAT_XXX enums. +// @param layer_count The number of layers of the buffers that this queue will +// produce. +// @param usage The usage of the buffers that this queue will produce. This +// must a combination of the AHARDWAREBUFFER_USAGE_XXX flags. +// @param capacity The number of buffer that this queue will allocate. Note that +// all buffers will be allocated on create. Currently, the number of buffers +// is the queue cannot be changed after creation though DVR API. However, +// ANativeWindow can choose to reallocate, attach, or detach buffers from +// a DvrWriteBufferQueue through Android platform logic. +// @param metadata_size The size of metadata in bytes. +// @param out_write_queue The pointer of a DvrWriteBufferQueue will be filled +// here if the method call succeeds. The metadata size must match +// the metadata size in dvrWriteBufferPost/dvrReadBufferAcquire. +// @return Zero on success, or negative error code. +int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format, + uint32_t layer_count, uint64_t usage, + size_t capacity, size_t metadata_size, + DvrWriteBufferQueue** out_write_queue); + // Destroy a write buffer queue. // // @param write_queue The DvrWriteBufferQueue of interest. diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp index f75283d6e0..7520eee70e 100644 --- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp +++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp @@ -1,24 +1,30 @@ +#include <android/log.h> +#include <android/native_window.h> +#include <android-base/unique_fd.h> #include <dvr/dvr_api.h> #include <dvr/dvr_buffer_queue.h> -#include <gui/Surface.h> -#include <private/dvr/buffer_hub_queue_client.h> -#include <base/logging.h> #include <gtest/gtest.h> -#include "../dvr_internal.h" -#include "../dvr_buffer_queue_internal.h" +#include <array> +#include <unordered_map> -namespace android { -namespace dvr { +#ifndef ALOGD +#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#endif + +#ifndef ALOGD_IF +#define ALOGD_IF(cond, ...) \ + ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0) +#endif namespace { static constexpr uint32_t kBufferWidth = 100; static constexpr uint32_t kBufferHeight = 1; static constexpr uint32_t kLayerCount = 1; -static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; -static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY; +static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB; +static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN; static constexpr size_t kQueueCapacity = 3; typedef uint64_t TestMeta; @@ -36,14 +42,6 @@ class DvrBufferQueueTest : public ::testing::Test { } protected: - void SetUp() override { - config_builder_ = ProducerQueueConfigBuilder() - .SetDefaultWidth(kBufferWidth) - .SetDefaultHeight(kBufferHeight) - .SetDefaultFormat(kBufferFormat) - .SetMetadata<TestMeta>(); - } - void TearDown() override { if (write_queue_ != nullptr) { dvrWriteBufferQueueDestroy(write_queue_); @@ -51,19 +49,6 @@ class DvrBufferQueueTest : public ::testing::Test { } } - void CreateWriteBufferQueue() { - write_queue_ = new DvrWriteBufferQueue( - ProducerQueue::Create(config_builder_.Build(), UsagePolicy{})); - ASSERT_NE(nullptr, write_queue_); - } - - void AllocateBuffers(size_t buffer_count) { - auto status = write_queue_->producer_queue()->AllocateBuffers( - kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage, - buffer_count); - ASSERT_TRUE(status.ok()); - } - void HandleBufferAvailable() { buffer_available_count_ += 1; ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_); @@ -75,22 +60,26 @@ class DvrBufferQueueTest : public ::testing::Test { buffer_removed_count_); } - ProducerQueueConfigBuilder config_builder_; DvrWriteBufferQueue* write_queue_{nullptr}; int buffer_available_count_{0}; int buffer_removed_count_{0}; }; TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); dvrWriteBufferQueueDestroy(write_queue_); write_queue_ = nullptr; } TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_); @@ -99,10 +88,13 @@ TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) { } TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue = nullptr; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); @@ -111,11 +103,14 @@ TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) { } TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue1 = nullptr; DvrReadBufferQueue* read_queue2 = nullptr; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue1); @@ -130,8 +125,10 @@ TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) { } TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBuffer* read_buffer = nullptr; DvrWriteBuffer* write_buffer = nullptr; @@ -164,8 +161,10 @@ TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) { } TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); static constexpr int kTimeout = 0; DvrReadBufferQueue* read_queue = nullptr; @@ -173,7 +172,7 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { DvrWriteBuffer* wb = nullptr; int fence_fd = -1; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); @@ -193,7 +192,7 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { ASSERT_TRUE(dvrWriteBufferIsValid(wb)); ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d", wb, fence_fd); - pdx::LocalHandle release_fence(fence_fd); + android::base::unique_fd release_fence(fence_fd); // Post buffer to the read_queue. TestMeta seq = 42U; @@ -215,7 +214,7 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb, fence_fd); - pdx::LocalHandle acquire_fence(fence_fd); + android::base::unique_fd acquire_fence(fence_fd); // Release buffer to the write_queue. ret = dvrReadBufferRelease(rb, -1); @@ -234,40 +233,52 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { } TEST_F(DvrBufferQueueTest, TestGetExternalSurface) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); ANativeWindow* window = nullptr; // The |write_queue_| doesn't have proper metadata (must be // DvrNativeBufferMetadata) configured during creation. - int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window); + ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window); ASSERT_EQ(-EINVAL, ret); ASSERT_EQ(nullptr, window); + dvrWriteBufferQueueDestroy(write_queue_); + write_queue_ = nullptr; // A write queue with DvrNativeBufferMetadata should work fine. - auto config = ProducerQueueConfigBuilder() - .SetMetadata<DvrNativeBufferMetadata>() - .Build(); - std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)> - write_queue( - new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})), - dvrWriteBufferQueueDestroy); - ASSERT_NE(nullptr, write_queue.get()); + ASSERT_EQ(nullptr, write_queue_); + + ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); + ASSERT_EQ(0, ret); + ASSERT_NE(nullptr, write_queue_); - ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window); + ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, window); - sp<Surface> surface = static_cast<Surface*>(window); - ASSERT_TRUE(Surface::isValid(surface)); + // TODO(b/64723700): Remove dependencies of Android platform bits so that we + // can run dvr_buffer_queue-test in DTS. + uint32_t width = ANativeWindow_getWidth(window); + uint32_t height = ANativeWindow_getHeight(window); + uint32_t format = ANativeWindow_getFormat(window); + ASSERT_EQ(kBufferWidth, width); + ASSERT_EQ(kBufferHeight, height); + ASSERT_EQ(kBufferFormat, format); } // Create buffer queue of three buffers and dequeue three buffers out of it. // Before each dequeue operation, we resize the buffer queue and expect the // queue always return buffer with desired dimension. TEST_F(DvrBufferQueueTest, TestResizeBuffer) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); static constexpr int kTimeout = 0; int fence_fd = -1; @@ -281,7 +292,7 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { AHardwareBuffer* ahb3 = nullptr; AHardwareBuffer_Desc buffer_desc; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); @@ -314,7 +325,7 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { ASSERT_EQ(0, ret); ASSERT_TRUE(dvrWriteBufferIsValid(wb1)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1); - pdx::LocalHandle release_fence1(fence_fd); + android::base::unique_fd release_fence1(fence_fd); // Check the buffer dimension. ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1); @@ -341,7 +352,7 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { ASSERT_TRUE(dvrWriteBufferIsValid(wb2)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2, fence_fd); - pdx::LocalHandle release_fence2(fence_fd); + android::base::unique_fd release_fence2(fence_fd); // Check the buffer dimension, should be new width ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2); @@ -367,7 +378,7 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { ASSERT_TRUE(dvrWriteBufferIsValid(wb3)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3, fence_fd); - pdx::LocalHandle release_fence3(fence_fd); + android::base::unique_fd release_fence3(fence_fd); // Check the buffer dimension, should be new width ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3); @@ -387,9 +398,10 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) { // Overrides default queue parameters: Empty metadata. - config_builder_.SetMetadata<void>(); - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/1, /*metadata_size=*/0, &write_queue_); + ASSERT_EQ(0, ret); DvrReadBuffer* rb = nullptr; DvrWriteBuffer* wb = nullptr; @@ -416,8 +428,10 @@ TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) { } TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/1, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBuffer* rb = nullptr; DvrWriteBuffer* wb = nullptr; @@ -451,11 +465,13 @@ TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) { } TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue = nullptr; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); @@ -468,8 +484,10 @@ TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) { // Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id, // the corresponding AHardwareBuffer handle stays the same. TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); int fence_fd = -1; DvrReadBufferQueue* read_queue = nullptr; @@ -621,6 +639,3 @@ TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) { } } // namespace - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 733edc659c..af18e218d5 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -40,10 +40,8 @@ namespace dvr { DisplayService::DisplayService(Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) : BASE("DisplayService", - Endpoint::Create(display::DisplayProtocol::kClientPath)), - hardware_composer_(hidl, request_display_callback), - request_display_callback_(request_display_callback) { - hardware_composer_.Initialize(); + Endpoint::Create(display::DisplayProtocol::kClientPath)) { + hardware_composer_.Initialize(hidl, request_display_callback); } bool DisplayService::IsInitialized() const { @@ -245,18 +243,16 @@ Status<display::SurfaceInfo> DisplayService::OnCreateSurface( surface_status.GetErrorMessage().c_str()); return ErrorStatus(surface_status.error()); } + auto surface = surface_status.take(); + message.SetChannel(surface); - SurfaceType surface_type = surface_status.get()->surface_type(); - display::SurfaceUpdateFlags update_flags = - surface_status.get()->update_flags(); - display::SurfaceInfo surface_info{surface_status.get()->surface_id(), - surface_status.get()->visible(), - surface_status.get()->z_order()}; + // Update the surface with the attributes supplied with the create call. For + // application surfaces this has the side effect of notifying the display + // manager of the new surface. For direct surfaces, this may trigger a mode + // change, depending on the value of the visible attribute. + surface->OnSetAttributes(message, attributes); - message.SetChannel(surface_status.take()); - - SurfaceUpdated(surface_type, update_flags); - return {surface_info}; + return {{surface->surface_id(), surface->visible(), surface->z_order()}}; } void DisplayService::SurfaceUpdated(SurfaceType surface_type, @@ -398,10 +394,6 @@ pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) { return {0}; } -void DisplayService::OnHardwareComposerRefresh() { - hardware_composer_.OnHardwareComposerRefresh(); -} - void DisplayService::SetDisplayConfigurationUpdateNotifier( DisplayConfigurationUpdateNotifier update_notifier) { update_notifier_ = update_notifier; diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 6efe264b09..55e33ab852 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -72,8 +72,6 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { void GrantDisplayOwnership() { hardware_composer_.Enable(); } void SeizeDisplayOwnership() { hardware_composer_.Disable(); } - void OnHardwareComposerRefresh(); - private: friend BASE; friend DisplaySurface; @@ -119,7 +117,6 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { pdx::Status<void> HandleSurfaceMessage(pdx::Message& message); HardwareComposer hardware_composer_; - RequestDisplayCallback request_display_callback_; EpollEventDispatcher dispatcher_; DisplayConfigurationUpdateNotifier update_notifier_; diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp index 4852fabd4b..685378133e 100644 --- a/libs/vr/libvrflinger/display_surface.cpp +++ b/libs/vr/libvrflinger/display_surface.cpp @@ -26,14 +26,12 @@ namespace dvr { DisplaySurface::DisplaySurface(DisplayService* service, SurfaceType surface_type, int surface_id, - int process_id, int user_id, - const display::SurfaceAttributes& attributes) + int process_id, int user_id) : service_(service), surface_type_(surface_type), surface_id_(surface_id), process_id_(process_id), user_id_(user_id), - attributes_(attributes), update_flags_(display::SurfaceUpdateFlags::NewSurface) {} DisplaySurface::~DisplaySurface() { @@ -471,8 +469,8 @@ Status<std::shared_ptr<DisplaySurface>> DisplaySurface::Create( if (direct) { const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id); if (trusted) { - return {std::shared_ptr<DisplaySurface>{new DirectDisplaySurface( - service, surface_id, process_id, user_id, attributes)}}; + return {std::shared_ptr<DisplaySurface>{ + new DirectDisplaySurface(service, surface_id, process_id, user_id)}}; } else { ALOGE( "DisplaySurface::Create: Direct surfaces may only be created by " @@ -482,7 +480,7 @@ Status<std::shared_ptr<DisplaySurface>> DisplaySurface::Create( } } else { return {std::shared_ptr<DisplaySurface>{new ApplicationDisplaySurface( - service, surface_id, process_id, user_id, attributes)}}; + service, surface_id, process_id, user_id)}}; } } diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h index 7a0fb18548..c8b1a078f7 100644 --- a/libs/vr/libvrflinger/display_surface.h +++ b/libs/vr/libvrflinger/display_surface.h @@ -53,8 +53,7 @@ class DisplaySurface : public pdx::Channel { protected: DisplaySurface(DisplayService* service, SurfaceType surface_type, - int surface_id, int process_id, int user_id, - const display::SurfaceAttributes& attributes); + int surface_id, int process_id, int user_id); // Utility to retrieve a shared pointer to this channel as the desired derived // type. @@ -119,10 +118,9 @@ class DisplaySurface : public pdx::Channel { class ApplicationDisplaySurface : public DisplaySurface { public: ApplicationDisplaySurface(DisplayService* service, int surface_id, - int process_id, int user_id, - const display::SurfaceAttributes& attributes) + int process_id, int user_id) : DisplaySurface(service, SurfaceType::Application, surface_id, - process_id, user_id, attributes) {} + process_id, user_id) {} std::shared_ptr<ConsumerQueue> GetQueue(int32_t queue_id); std::vector<int32_t> GetQueueIds() const override; @@ -140,12 +138,11 @@ class ApplicationDisplaySurface : public DisplaySurface { class DirectDisplaySurface : public DisplaySurface { public: DirectDisplaySurface(DisplayService* service, int surface_id, int process_id, - int user_id, - const display::SurfaceAttributes& attributes) + int user_id) : DisplaySurface(service, SurfaceType::Direct, surface_id, process_id, - user_id, attributes), + user_id), acquired_buffers_(kMaxPostedBuffers), - metadata_(nullptr){} + metadata_(nullptr) {} std::vector<int32_t> GetQueueIds() const override; bool IsBufferAvailable(); bool IsBufferPosted(); diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index 4479d1eb8f..f9a5dcd987 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -28,6 +28,8 @@ #include <private/dvr/clock_ns.h> #include <private/dvr/ion_buffer.h> +using android::hardware::Return; +using android::hardware::Void; using android::pdx::LocalHandle; using android::pdx::rpc::EmptyVariant; using android::pdx::rpc::IfAnyOf; @@ -42,9 +44,6 @@ namespace { const char kBacklightBrightnessSysFile[] = "/sys/class/leds/lcd-backlight/brightness"; -const char kPrimaryDisplayVSyncEventFile[] = - "/sys/class/graphics/fb0/vsync_event"; - const char kPrimaryDisplayWaitPPEventFile[] = "/sys/class/graphics/fb0/wait_pp"; const char kDvrPerformanceProperty[] = "sys.dvr.performance"; @@ -86,22 +85,11 @@ bool SetThreadPolicy(const std::string& scheduler_class, } // anonymous namespace -// Layer static data. -Hwc2::Composer* Layer::hwc2_hidl_; -const HWCDisplayMetrics* Layer::display_metrics_; - // HardwareComposer static data; constexpr size_t HardwareComposer::kMaxHardwareLayers; HardwareComposer::HardwareComposer() - : HardwareComposer(nullptr, RequestDisplayCallback()) {} - -HardwareComposer::HardwareComposer( - Hwc2::Composer* hwc2_hidl, RequestDisplayCallback request_display_callback) - : initialized_(false), - hwc2_hidl_(hwc2_hidl), - request_display_callback_(request_display_callback), - callbacks_(new ComposerCallback) {} + : initialized_(false), request_display_callback_(nullptr) {} HardwareComposer::~HardwareComposer(void) { UpdatePostThreadState(PostThreadState::Quit, true); @@ -109,16 +97,19 @@ HardwareComposer::~HardwareComposer(void) { post_thread_.join(); } -bool HardwareComposer::Initialize() { +bool HardwareComposer::Initialize( + Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) { if (initialized_) { ALOGE("HardwareComposer::Initialize: already initialized."); return false; } + request_display_callback_ = request_display_callback; + HWC::Error error = HWC::Error::None; Hwc2::Config config; - error = hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); + error = hidl->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); if (error != HWC::Error::None) { ALOGE("HardwareComposer: Failed to get current display config : %d", @@ -126,8 +117,8 @@ bool HardwareComposer::Initialize() { return false; } - error = - GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_); + error = GetDisplayMetrics(hidl, HWC_DISPLAY_PRIMARY, config, + &native_display_metrics_); if (error != HWC::Error::None) { ALOGE( @@ -149,9 +140,6 @@ bool HardwareComposer::Initialize() { display_transform_ = HWC_TRANSFORM_NONE; display_metrics_ = native_display_metrics_; - // Pass hwc instance and metrics to setup globals for Layer. - Layer::InitializeGlobals(hwc2_hidl_, &native_display_metrics_); - post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); LOG_ALWAYS_FATAL_IF( !post_thread_event_fd_, @@ -210,15 +198,11 @@ void HardwareComposer::UpdatePostThreadState(PostThreadStateType state, } void HardwareComposer::OnPostThreadResumed() { - hwc2_hidl_->resetCommands(); + hidl_.reset(new Hwc2::Composer("default")); + hidl_callback_ = new ComposerCallback; + hidl_->registerCallback(hidl_callback_); - // HIDL HWC seems to have an internal race condition. If we submit a frame too - // soon after turning on VSync we don't get any VSync signals. Give poor HWC - // implementations a chance to enable VSync before we continue. - EnableVsync(false); - std::this_thread::sleep_for(100ms); EnableVsync(true); - std::this_thread::sleep_for(100ms); // TODO(skiazyk): We need to do something about accessing this directly, // supposedly there is a backlight service on the way. @@ -240,9 +224,12 @@ void HardwareComposer::OnPostThreadPaused() { } active_layer_count_ = 0; - EnableVsync(false); + if (hidl_) { + EnableVsync(false); + } - hwc2_hidl_->resetCommands(); + hidl_callback_ = nullptr; + hidl_.reset(nullptr); // Trigger target-specific performance mode change. property_set(kDvrPerformanceProperty, "idle"); @@ -252,21 +239,21 @@ HWC::Error HardwareComposer::Validate(hwc2_display_t display) { uint32_t num_types; uint32_t num_requests; HWC::Error error = - hwc2_hidl_->validateDisplay(display, &num_types, &num_requests); + hidl_->validateDisplay(display, &num_types, &num_requests); if (error == HWC2_ERROR_HAS_CHANGES) { // TODO(skiazyk): We might need to inspect the requested changes first, but // so far it seems like we shouldn't ever hit a bad state. // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_, // display); - error = hwc2_hidl_->acceptDisplayChanges(display); + error = hidl_->acceptDisplayChanges(display); } return error; } -int32_t HardwareComposer::EnableVsync(bool enabled) { - return (int32_t)hwc2_hidl_->setVsyncEnabled( +HWC::Error HardwareComposer::EnableVsync(bool enabled) { + return hidl_->setVsyncEnabled( HWC_DISPLAY_PRIMARY, (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE : HWC2_VSYNC_DISABLE)); @@ -274,7 +261,7 @@ int32_t HardwareComposer::EnableVsync(bool enabled) { HWC::Error HardwareComposer::Present(hwc2_display_t display) { int32_t present_fence; - HWC::Error error = hwc2_hidl_->presentDisplay(display, &present_fence); + HWC::Error error = hidl_->presentDisplay(display, &present_fence); // According to the documentation, this fence is signaled at the time of // vsync/DMA for physical displays. @@ -288,20 +275,21 @@ HWC::Error HardwareComposer::Present(hwc2_display_t display) { return error; } -HWC::Error HardwareComposer::GetDisplayAttribute(hwc2_display_t display, +HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* hidl, + hwc2_display_t display, hwc2_config_t config, hwc2_attribute_t attribute, int32_t* out_value) const { - return hwc2_hidl_->getDisplayAttribute( + return hidl->getDisplayAttribute( display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value); } HWC::Error HardwareComposer::GetDisplayMetrics( - hwc2_display_t display, hwc2_config_t config, + Hwc2::Composer* hidl, hwc2_display_t display, hwc2_config_t config, HWCDisplayMetrics* out_metrics) const { HWC::Error error; - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_WIDTH, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_WIDTH, &out_metrics->width); if (error != HWC::Error::None) { ALOGE( @@ -310,7 +298,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_HEIGHT, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_HEIGHT, &out_metrics->height); if (error != HWC::Error::None) { ALOGE( @@ -319,7 +307,8 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_VSYNC_PERIOD, + error = GetDisplayAttribute(hidl, display, config, + HWC2_ATTRIBUTE_VSYNC_PERIOD, &out_metrics->vsync_period_ns); if (error != HWC::Error::None) { ALOGE( @@ -328,7 +317,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_X, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_X, &out_metrics->dpi.x); if (error != HWC::Error::None) { ALOGE( @@ -337,7 +326,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_Y, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_Y, &out_metrics->dpi.y); if (error != HWC::Error::None) { ALOGE( @@ -374,7 +363,7 @@ std::string HardwareComposer::Dump() { if (post_thread_resumed_) { stream << "Hardware Composer Debug Info:" << std::endl; - stream << hwc2_hidl_->dumpDebugInfo(); + stream << hidl_->dumpDebugInfo(); } return stream.str(); @@ -446,8 +435,8 @@ void HardwareComposer::PostLayers() { std::vector<Hwc2::Layer> out_layers; std::vector<int> out_fences; - error = hwc2_hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, - &out_fences); + error = hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, + &out_fences); ALOGE_IF(error != HWC::Error::None, "HardwareComposer::PostLayers: Failed to get release fences: %s", error.to_string().c_str()); @@ -546,7 +535,7 @@ void HardwareComposer::UpdateConfigBuffer() { } int HardwareComposer::PostThreadPollInterruptible( - const pdx::LocalHandle& event_fd, int requested_events) { + const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms) { pollfd pfd[2] = { { .fd = event_fd.Get(), @@ -561,7 +550,7 @@ int HardwareComposer::PostThreadPollInterruptible( }; int ret, error; do { - ret = poll(pfd, 2, -1); + ret = poll(pfd, 2, timeout_ms); error = errno; ALOGW_IF(ret < 0, "HardwareComposer::PostThreadPollInterruptible: Error during " @@ -571,6 +560,8 @@ int HardwareComposer::PostThreadPollInterruptible( if (ret < 0) { return -error; + } else if (ret == 0) { + return -ETIMEDOUT; } else if (pfd[0].revents != 0) { return 0; } else if (pfd[1].revents != 0) { @@ -623,114 +614,17 @@ int HardwareComposer::ReadWaitPPState() { } } -// Reads the timestamp of the last vsync from the display driver. -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. -int HardwareComposer::ReadVSyncTimestamp(int64_t* timestamp) { - const int event_fd = primary_display_vsync_event_fd_.Get(); - int ret, error; - - // The driver returns data in the form "VSYNC=<timestamp ns>". - std::array<char, 32> data; - data.fill('\0'); - - // Seek back to the beginning of the event file. - ret = lseek(event_fd, 0, SEEK_SET); - if (ret < 0) { - error = errno; - ALOGE( - "HardwareComposer::ReadVSyncTimestamp: Failed to seek vsync event fd: " - "%s", - strerror(error)); - return -error; - } - - // Read the vsync event timestamp. - ret = read(event_fd, data.data(), data.size()); - if (ret < 0) { - error = errno; - ALOGE_IF( - error != EAGAIN, - "HardwareComposer::ReadVSyncTimestamp: Error while reading timestamp: " - "%s", - strerror(error)); - return -error; - } - - ret = sscanf(data.data(), "VSYNC=%" PRIu64, - reinterpret_cast<uint64_t*>(timestamp)); - if (ret < 0) { - error = errno; - ALOGE( - "HardwareComposer::ReadVSyncTimestamp: Error while parsing timestamp: " - "%s", - strerror(error)); - return -error; - } - - return 0; -} - -// Blocks until the next vsync event is signaled by the display driver. -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. -int HardwareComposer::BlockUntilVSync() { - // Vsync is signaled by POLLPRI on the fb vsync node. - return PostThreadPollInterruptible(primary_display_vsync_event_fd_, POLLPRI); -} - // Waits for the next vsync and returns the timestamp of the vsync event. If // vsync already passed since the last call, returns the latest vsync timestamp -// instead of blocking. This method updates the last_vsync_timeout_ in the -// process. -// -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. +// instead of blocking. int HardwareComposer::WaitForVSync(int64_t* timestamp) { - int error; - - // Get the current timestamp and decide what to do. - while (true) { - int64_t current_vsync_timestamp; - error = ReadVSyncTimestamp(¤t_vsync_timestamp); - if (error < 0 && error != -EAGAIN) - return error; - - if (error == -EAGAIN) { - // Vsync was turned off, wait for the next vsync event. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) - return error; - - // Try again to get the timestamp for this new vsync interval. - continue; - } - - // Check that we advanced to a later vsync interval. - if (TimestampGT(current_vsync_timestamp, last_vsync_timestamp_)) { - *timestamp = last_vsync_timestamp_ = current_vsync_timestamp; - return 0; - } - - // See how close we are to the next expected vsync. If we're within 1ms, - // sleep for 1ms and try again. - const int64_t ns_per_frame = display_metrics_.vsync_period_ns; - const int64_t threshold_ns = 1000000; // 1ms - - const int64_t next_vsync_est = last_vsync_timestamp_ + ns_per_frame; - const int64_t distance_to_vsync_est = next_vsync_est - GetSystemClockNs(); - - if (distance_to_vsync_est > threshold_ns) { - // Wait for vsync event notification. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) - return error; - } else { - // Sleep for a short time (1 millisecond) before retrying. - error = SleepUntil(GetSystemClockNs() + threshold_ns); - if (error < 0 || error == kPostThreadInterrupted) - return error; - } + int error = PostThreadPollInterruptible( + hidl_callback_->GetVsyncEventFd(), POLLIN, /*timeout_ms*/ 1000); + if (error == kPostThreadInterrupted || error < 0) { + return error; + } else { + *timestamp = hidl_callback_->GetVsyncTime(); + return 0; } } @@ -749,7 +643,8 @@ int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) { return -error; } - return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN); + return PostThreadPollInterruptible( + vsync_sleep_timer_fd_, POLLIN, /*timeout_ms*/ -1); } void HardwareComposer::PostThread() { @@ -772,15 +667,6 @@ void HardwareComposer::PostThread() { strerror(errno)); #endif // ENABLE_BACKLIGHT_BRIGHTNESS - // Open the vsync event node for the primary display. - // TODO(eieio): Move this into a platform-specific class. - primary_display_vsync_event_fd_ = - LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY); - ALOGE_IF(!primary_display_vsync_event_fd_, - "HardwareComposer: Failed to open vsync event node for primary " - "display: %s", - strerror(errno)); - // Open the wait pingpong status node for the primary display. // TODO(eieio): Move this into a platform-specific class. primary_display_wait_pp_fd_ = @@ -821,8 +707,9 @@ void HardwareComposer::PostThread() { std::unique_lock<std::mutex> lock(post_thread_mutex_); ALOGI("HardwareComposer::PostThread: Entering quiescent state."); - // Tear down resources. - OnPostThreadPaused(); + // Tear down resources if necessary. + if (was_running) + OnPostThreadPaused(); was_running = false; post_thread_resumed_ = false; @@ -950,7 +837,8 @@ bool HardwareComposer::UpdateLayerConfig() { // The bottom layer is opaque, other layers blend. HWC::BlendMode blending = layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage; - layers_[layer_index].Setup(surfaces[layer_index], blending, + layers_[layer_index].Setup(surfaces[layer_index], native_display_metrics_, + hidl_.get(), blending, display_transform_, HWC::Composition::Device, layer_index); display_surfaces_.push_back(surfaces[layer_index]); @@ -978,50 +866,67 @@ void HardwareComposer::SetVSyncCallback(VSyncCallback callback) { vsync_callback_ = callback; } -void HardwareComposer::HwcRefresh(hwc2_callback_data_t /*data*/, - hwc2_display_t /*display*/) { - // TODO(eieio): implement invalidate callbacks. +void HardwareComposer::SetBacklightBrightness(int brightness) { + if (backlight_brightness_fd_) { + std::array<char, 32> text; + const int length = snprintf(text.data(), text.size(), "%d", brightness); + write(backlight_brightness_fd_.Get(), text.data(), length); + } } -void HardwareComposer::HwcVSync(hwc2_callback_data_t /*data*/, - hwc2_display_t /*display*/, - int64_t /*timestamp*/) { - ATRACE_NAME(__PRETTY_FUNCTION__); - // Intentionally empty. HWC may require a callback to be set to enable vsync - // signals. We bypass this callback thread by monitoring the vsync event - // directly, but signals still need to be enabled. +HardwareComposer::ComposerCallback::ComposerCallback() { + vsync_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + LOG_ALWAYS_FATAL_IF( + !vsync_event_fd_, + "Failed to create vsync event fd : %s", + strerror(errno)); } -void HardwareComposer::HwcHotplug(hwc2_callback_data_t /*callbackData*/, - hwc2_display_t /*display*/, - hwc2_connection_t /*connected*/) { - // TODO(eieio): implement display hotplug callbacks. +Return<void> HardwareComposer::ComposerCallback::onHotplug( + Hwc2::Display /*display*/, + IComposerCallback::Connection /*conn*/) { + return Void(); } -void HardwareComposer::OnHardwareComposerRefresh() { - // TODO(steventhomas): Handle refresh. +Return<void> HardwareComposer::ComposerCallback::onRefresh( + Hwc2::Display /*display*/) { + return hardware::Void(); } -void HardwareComposer::SetBacklightBrightness(int brightness) { - if (backlight_brightness_fd_) { - std::array<char, 32> text; - const int length = snprintf(text.data(), text.size(), "%d", brightness); - write(backlight_brightness_fd_.Get(), text.data(), length); +Return<void> HardwareComposer::ComposerCallback::onVsync( + Hwc2::Display display, int64_t timestamp) { + if (display == HWC_DISPLAY_PRIMARY) { + std::lock_guard<std::mutex> lock(vsync_mutex_); + vsync_time_ = timestamp; + int error = eventfd_write(vsync_event_fd_.Get(), 1); + LOG_ALWAYS_FATAL_IF(error != 0, "Failed writing to vsync event fd"); } + return Void(); +} + +const pdx::LocalHandle& +HardwareComposer::ComposerCallback::GetVsyncEventFd() const { + return vsync_event_fd_; } -void Layer::InitializeGlobals(Hwc2::Composer* hwc2_hidl, - const HWCDisplayMetrics* metrics) { - hwc2_hidl_ = hwc2_hidl; - display_metrics_ = metrics; +int64_t HardwareComposer::ComposerCallback::GetVsyncTime() { + std::lock_guard<std::mutex> lock(vsync_mutex_); + eventfd_t event; + eventfd_read(vsync_event_fd_.Get(), &event); + LOG_ALWAYS_FATAL_IF(vsync_time_ < 0, + "Attempt to read vsync time before vsync event"); + int64_t return_val = vsync_time_; + vsync_time_ = -1; + return return_val; } void Layer::Reset() { - if (hwc2_hidl_ != nullptr && hardware_composer_layer_) { - hwc2_hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); + if (hidl_ != nullptr && hardware_composer_layer_) { + hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); hardware_composer_layer_ = 0; } + hidl_ = nullptr; z_order_ = 0; blending_ = HWC::BlendMode::None; transform_ = HWC::Transform::None; @@ -1033,29 +938,35 @@ void Layer::Reset() { } void Layer::Setup(const std::shared_ptr<DirectDisplaySurface>& surface, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) { + const HWCDisplayMetrics& display_metrics, + Hwc2::Composer* hidl, HWC::BlendMode blending, + HWC::Transform transform, HWC::Composition composition_type, + size_t z_order) { Reset(); + hidl_ = hidl; z_order_ = z_order; blending_ = blending; transform_ = transform; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type; source_ = SourceSurface{surface}; - CommonLayerSetup(); + CommonLayerSetup(display_metrics); } void Layer::Setup(const std::shared_ptr<IonBuffer>& buffer, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) { + const HWCDisplayMetrics& display_metrics, + Hwc2::Composer* hidl, HWC::BlendMode blending, + HWC::Transform transform, HWC::Composition composition_type, + size_t z_order) { Reset(); + hidl_ = hidl; z_order_ = z_order; blending_ = blending; transform_ = transform; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type; source_ = SourceBuffer{buffer}; - CommonLayerSetup(); + CommonLayerSetup(display_metrics); } void Layer::UpdateBuffer(const std::shared_ptr<IonBuffer>& buffer) { @@ -1075,7 +986,7 @@ IonBuffer* Layer::GetBuffer() { return source_.Visit(Visitor{}); } -void Layer::UpdateLayerSettings() { +void Layer::UpdateLayerSettings(const HWCDisplayMetrics& display_metrics) { if (!IsLayerSetup()) { ALOGE( "HardwareComposer::Layer::UpdateLayerSettings: Attempt to update " @@ -1086,7 +997,7 @@ void Layer::UpdateLayerSettings() { HWC::Error error; hwc2_display_t display = HWC_DISPLAY_PRIMARY; - error = hwc2_hidl_->setLayerCompositionType( + error = hidl_->setLayerCompositionType( display, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); ALOGE_IF( @@ -1094,7 +1005,7 @@ void Layer::UpdateLayerSettings() { "Layer::UpdateLayerSettings: Error setting layer composition type: %s", error.to_string().c_str()); - error = hwc2_hidl_->setLayerBlendMode( + error = hidl_->setLayerBlendMode( display, hardware_composer_layer_, blending_.cast<Hwc2::IComposerClient::BlendMode>()); ALOGE_IF(error != HWC::Error::None, @@ -1103,41 +1014,39 @@ void Layer::UpdateLayerSettings() { // TODO(eieio): Use surface attributes or some other mechanism to control // the layer display frame. - error = hwc2_hidl_->setLayerDisplayFrame( + error = hidl_->setLayerDisplayFrame( display, hardware_composer_layer_, - {0, 0, display_metrics_->width, display_metrics_->height}); + {0, 0, display_metrics.width, display_metrics.height}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer display frame: %s", error.to_string().c_str()); - error = hwc2_hidl_->setLayerVisibleRegion( + error = hidl_->setLayerVisibleRegion( display, hardware_composer_layer_, - {{0, 0, display_metrics_->width, display_metrics_->height}}); + {{0, 0, display_metrics.width, display_metrics.height}}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer visible region: %s", error.to_string().c_str()); - error = - hwc2_hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); + error = hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s", error.to_string().c_str()); - error = - hwc2_hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_); + error = hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting z_ order: %s", error.to_string().c_str()); } -void Layer::CommonLayerSetup() { +void Layer::CommonLayerSetup(const HWCDisplayMetrics& display_metrics) { HWC::Error error = - hwc2_hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); + hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); ALOGE_IF( error != HWC::Error::None, "Layer::CommonLayerSetup: Failed to create layer on primary display: %s", error.to_string().c_str()); - UpdateLayerSettings(); + UpdateLayerSettings(display_metrics); } void Layer::Prepare() { @@ -1156,12 +1065,12 @@ void Layer::Prepare() { if (!handle.get()) { if (composition_type_ == HWC::Composition::Invalid) { composition_type_ = HWC::Composition::SolidColor; - hwc2_hidl_->setLayerCompositionType( + hidl_->setLayerCompositionType( HWC_DISPLAY_PRIMARY, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0}; - hwc2_hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, - layer_color); + hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + layer_color); } else { // The composition type is already set. Nothing else to do until a // buffer arrives. @@ -1169,15 +1078,15 @@ void Layer::Prepare() { } else { if (composition_type_ != target_composition_type_) { composition_type_ = target_composition_type_; - hwc2_hidl_->setLayerCompositionType( + hidl_->setLayerCompositionType( HWC_DISPLAY_PRIMARY, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); } HWC::Error error{HWC::Error::None}; - error = hwc2_hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY, - hardware_composer_layer_, 0, handle, - acquire_fence_.Get()); + error = hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY, + hardware_composer_layer_, 0, handle, + acquire_fence_.Get()); ALOGE_IF(error != HWC::Error::None, "Layer::Prepare: Error setting layer buffer: %s", @@ -1186,9 +1095,9 @@ void Layer::Prepare() { if (!surface_rect_functions_applied_) { const float float_right = right; const float float_bottom = bottom; - error = hwc2_hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, - hardware_composer_layer_, - {0, 0, float_right, float_bottom}); + error = hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, + hardware_composer_layer_, + {0, 0, float_right, float_bottom}); ALOGE_IF(error != HWC::Error::None, "Layer::Prepare: Error setting layer source crop: %s", diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index a0c50e14d8..fc0efeeeb4 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -54,11 +54,6 @@ class Layer { public: Layer() {} - // Sets up the global state used by all Layer instances. This must be called - // before using any Layer methods. - static void InitializeGlobals(Hwc2::Composer* hwc2_hidl, - const HWCDisplayMetrics* metrics); - // Releases any shared pointers and fence handles held by this instance. void Reset(); @@ -72,6 +67,7 @@ class Layer { // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). // |index| is the index of this surface in the DirectDisplaySurface array. void Setup(const std::shared_ptr<DirectDisplaySurface>& surface, + const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl, HWC::BlendMode blending, HWC::Transform transform, HWC::Composition composition_type, size_t z_roder); @@ -83,9 +79,10 @@ class Layer { // |transform| receives HWC_TRANSFORM_* values. // |composition_type| receives either HWC_FRAMEBUFFER for most layers or // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). - void Setup(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending, - HWC::Transform transform, HWC::Composition composition_type, - size_t z_order); + void Setup(const std::shared_ptr<IonBuffer>& buffer, + const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl, + HWC::BlendMode blending, HWC::Transform transform, + HWC::Composition composition_type, size_t z_order); // Layers that use a direct IonBuffer should call this each frame to update // which buffer will be used for the next PostLayers. @@ -121,7 +118,7 @@ class Layer { bool IsLayerSetup() const { return !source_.empty(); } // Applies all of the settings to this layer using the hwc functions - void UpdateLayerSettings(); + void UpdateLayerSettings(const HWCDisplayMetrics& display_metrics); int GetSurfaceId() const { int surface_id = -1; @@ -142,10 +139,9 @@ class Layer { } private: - void CommonLayerSetup(); + void CommonLayerSetup(const HWCDisplayMetrics& display_metrics); - static Hwc2::Composer* hwc2_hidl_; - static const HWCDisplayMetrics* display_metrics_; + Hwc2::Composer* hidl_ = nullptr; // The hardware composer layer and metrics to use during the prepare cycle. hwc2_layer_t hardware_composer_layer_ = 0; @@ -263,11 +259,10 @@ class HardwareComposer { static constexpr size_t kMaxHardwareLayers = 4; HardwareComposer(); - HardwareComposer(Hwc2::Composer* hidl, - RequestDisplayCallback request_display_callback); ~HardwareComposer(); - bool Initialize(); + bool Initialize(Hwc2::Composer* hidl, + RequestDisplayCallback request_display_callback); bool IsInitialized() const { return initialized_; } @@ -281,11 +276,6 @@ class HardwareComposer { // Get the HMD display metrics for the current display. display::Metrics GetHmdDisplayMetrics() const; - HWC::Error GetDisplayAttribute(hwc2_display_t display, hwc2_config_t config, - hwc2_attribute_t attributes, - int32_t* out_value) const; - HWC::Error GetDisplayMetrics(hwc2_display_t display, hwc2_config_t config, - HWCDisplayMetrics* out_metrics) const; std::string Dump(); void SetVSyncCallback(VSyncCallback callback); @@ -308,34 +298,31 @@ class HardwareComposer { int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); - void OnHardwareComposerRefresh(); - private: - int32_t EnableVsync(bool enabled); + HWC::Error GetDisplayAttribute(Hwc2::Composer* hidl, hwc2_display_t display, + hwc2_config_t config, + hwc2_attribute_t attributes, + int32_t* out_value) const; + HWC::Error GetDisplayMetrics(Hwc2::Composer* hidl, hwc2_display_t display, + hwc2_config_t config, + HWCDisplayMetrics* out_metrics) const; + + HWC::Error EnableVsync(bool enabled); class ComposerCallback : public Hwc2::IComposerCallback { public: - ComposerCallback() {} - - hardware::Return<void> onHotplug(Hwc2::Display /*display*/, - Connection /*connected*/) override { - // TODO(skiazyk): depending on how the server is implemented, we might - // have to set it up to synchronize with receiving this event, as it can - // potentially be a critical event for setting up state within the - // hwc2 module. That is, we (technically) should not call any other hwc - // methods until this method has been called after registering the - // callbacks. - return hardware::Void(); - } - - hardware::Return<void> onRefresh(Hwc2::Display /*display*/) override { - return hardware::Void(); - } - - hardware::Return<void> onVsync(Hwc2::Display /*display*/, - int64_t /*timestamp*/) override { - return hardware::Void(); - } + ComposerCallback(); + hardware::Return<void> onHotplug(Hwc2::Display display, + Connection conn) override; + hardware::Return<void> onRefresh(Hwc2::Display display) override; + hardware::Return<void> onVsync(Hwc2::Display display, + int64_t timestamp) override; + const pdx::LocalHandle& GetVsyncEventFd() const; + int64_t GetVsyncTime(); + private: + std::mutex vsync_mutex_; + pdx::LocalHandle vsync_event_fd_; + int64_t vsync_time_ = -1; }; HWC::Error Validate(hwc2_display_t display); @@ -364,17 +351,18 @@ class HardwareComposer { void UpdatePostThreadState(uint32_t state, bool suspend); // Blocks until either event_fd becomes readable, or we're interrupted by a - // control thread. Any errors are returned as negative errno values. If we're - // interrupted, kPostThreadInterrupted will be returned. + // control thread, or timeout_ms is reached before any events occur. Any + // errors are returned as negative errno values, with -ETIMEDOUT returned in + // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be + // returned. int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd, - int requested_events); + int requested_events, + int timeout_ms); - // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made - // on the post thread that can be interrupted by a control thread. If - // interrupted, these calls return kPostThreadInterrupted. + // WaitForVSync and SleepUntil are blocking calls made on the post thread that + // can be interrupted by a control thread. If interrupted, these calls return + // kPostThreadInterrupted. int ReadWaitPPState(); - int BlockUntilVSync(); - int ReadVSyncTimestamp(int64_t* timestamp); int WaitForVSync(int64_t* timestamp); int SleepUntil(int64_t wakeup_timestamp); @@ -398,11 +386,9 @@ class HardwareComposer { bool initialized_; - // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own - // this pointer. - Hwc2::Composer* hwc2_hidl_; + std::unique_ptr<Hwc2::Composer> hidl_; + sp<ComposerCallback> hidl_callback_; RequestDisplayCallback request_display_callback_; - sp<ComposerCallback> callbacks_; // Display metrics of the physical display. HWCDisplayMetrics native_display_metrics_; @@ -433,7 +419,8 @@ class HardwareComposer { std::thread post_thread_; // Post thread state machine and synchronization primitives. - PostThreadStateType post_thread_state_{PostThreadState::Idle}; + PostThreadStateType post_thread_state_{ + PostThreadState::Idle | PostThreadState::Suspended}; std::atomic<bool> post_thread_quiescent_{true}; bool post_thread_resumed_{false}; pdx::LocalHandle post_thread_event_fd_; @@ -444,9 +431,6 @@ class HardwareComposer { // Backlight LED brightness sysfs node. pdx::LocalHandle backlight_brightness_fd_; - // Primary display vsync event sysfs node. - pdx::LocalHandle primary_display_vsync_event_fd_; - // Primary display wait_pingpong state sysfs node. pdx::LocalHandle primary_display_wait_pp_fd_; @@ -478,12 +462,6 @@ class HardwareComposer { static constexpr int kPostThreadInterrupted = 1; - static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display); - static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display, - int64_t timestamp); - static void HwcHotplug(hwc2_callback_data_t callbackData, - hwc2_display_t display, hwc2_connection_t connected); - HardwareComposer(const HardwareComposer&) = delete; void operator=(const HardwareComposer&) = delete; }; diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h index e7f41a7379..33cbc84d7d 100644 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h @@ -29,9 +29,6 @@ class VrFlinger { void GrantDisplayOwnership(); void SeizeDisplayOwnership(); - // Called on a binder thread. - void OnHardwareComposerRefresh(); - // dump all vr flinger state. std::string Dump(); diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp index 56405deeaa..fcf94f0865 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -133,10 +133,6 @@ void VrFlinger::SeizeDisplayOwnership() { display_service_->SeizeDisplayOwnership(); } -void VrFlinger::OnHardwareComposerRefresh() { - display_service_->OnHardwareComposerRefresh(); -} - std::string VrFlinger::Dump() { // TODO(karthikrs): Add more state information here. return display_service_->DumpState(0/*unused*/); diff --git a/opengl/Android.bp b/opengl/Android.bp index aec5a95628..9ca8b0b0fd 100644 --- a/opengl/Android.bp +++ b/opengl/Android.bp @@ -52,6 +52,30 @@ ndk_headers { license: "include/KHR/NOTICE", } +llndk_library { + name: "libEGL", + symbol_file: "libs/libEGL.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv1_CM", + symbol_file: "libs/libGLESv1_CM.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv2", + symbol_file: "libs/libGLESv2.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv3", + symbol_file: "libs/libGLESv3.map.txt", + export_include_dirs: ["include"], +} + cc_library_headers { name: "gl_headers", vendor_available: true, diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index b4cc2113e9..802b3b46e0 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -85,7 +85,6 @@ cc_defaults { cc_defaults { name: "egl_libs_defaults", defaults: ["gl_libs_defaults"], - vendor_available: true, cflags: [ "-DLOG_TAG=\"libEGL\"", ], @@ -152,7 +151,6 @@ cc_test { cc_defaults { name: "gles_libs_defaults", defaults: ["gl_libs_defaults"], - vendor_available: true, arch: { arm: { instruction_set: "arm", diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 0214b0eb56..94dfe6a9de 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -1447,7 +1447,7 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return setError(EGL_BAD_PARAMETER, (const char *)0); } -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) { clearError(); diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt index 89269a0231..fa26e33f39 100644 --- a/opengl/libs/libEGL.map.txt +++ b/opengl/libs/libEGL.map.txt @@ -21,6 +21,7 @@ LIBEGL { eglDestroyStreamKHR; # introduced=23 eglDestroySurface; eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglDupNativeFenceFDANDROID; # vndk eglGetConfigAttrib; eglGetConfigs; eglGetCurrentContext; @@ -44,6 +45,7 @@ LIBEGL { eglQueryStreamTimeKHR; # introduced=23 eglQueryStreamu64KHR; # introduced=23 eglQueryString; + eglQueryStringImplementationANDROID; # vndk eglQuerySurface; eglReleaseTexImage; eglReleaseThread; diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index ee88667328..67c0969e21 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -30,7 +30,7 @@ #include <EGLUtils.h> using namespace android; -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp index 69e56ff59b..5956366809 100644 --- a/opengl/tests/hwc/hwcRects.cpp +++ b/opengl/tests/hwc/hwcRects.cpp @@ -170,7 +170,7 @@ static EGLSurface surface; static EGLint width, height; // Function prototypes -static Rectangle parseRect(string rectStr); +static Rectangle parseRect(const string& rectStr); void init(void); void printSyntax(const char *cmd); @@ -358,7 +358,7 @@ main(int argc, char *argv[]) // Parse string description of rectangle and add it to list of rectangles // to be rendered. -static Rectangle parseRect(string rectStr) +static Rectangle parseRect(const string& rectStr) { int rv; string str; diff --git a/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h index 014c2611ae..9dc6bcf56a 100644 --- a/opengl/tests/lib/include/EGLUtils.h +++ b/opengl/tests/lib/include/EGLUtils.h @@ -20,11 +20,16 @@ #include <stdint.h> #include <stdlib.h> +#include <vector> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> #include <system/window.h> #include <utils/Errors.h> -#include <EGL/egl.h> +#include <utils/String8.h> +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); // ---------------------------------------------------------------------------- namespace android { @@ -47,6 +52,17 @@ public: EGLint const* attrs, EGLNativeWindowType window, EGLConfig* outConfig); + + static inline String8 printGLString(const char* name, GLenum s); + static inline String8 printEGLString(EGLDisplay dpy, const char* name, GLenum s); + static inline String8 checkEglError(const char* op, EGLBoolean returnVal); + static inline String8 checkGlError(const char* op); + static inline String8 printEGLConfiguration(EGLDisplay dpy, EGLConfig config); + static inline bool printEGLConfigurations(EGLDisplay dpy, String8& msg); + static inline bool printEGLConfigurations(FILE* output, EGLDisplay dpy); + static inline String8 decodeColorSpace(EGLint colorSpace); + static inline bool hasEglExtension(EGLDisplay dpy, const char* name); + static inline bool hasExtension(const char* exts, const char* name); }; // ---------------------------------------------------------------------------- @@ -91,9 +107,8 @@ status_t EGLUtils::selectConfigForPixelFormat( if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE) return BAD_VALUE; - EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs); - if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) { - free(configs); + std::vector<EGLConfig> configs(numConfigs); + if (eglChooseConfig(dpy, attrs, configs.data(), numConfigs, &n) == EGL_FALSE) { return BAD_VALUE; } @@ -108,8 +123,6 @@ status_t EGLUtils::selectConfigForPixelFormat( } } - free(configs); - if (i<n) { *outConfig = config; return NO_ERROR; @@ -137,6 +150,159 @@ status_t EGLUtils::selectConfigForNativeWindow( return selectConfigForPixelFormat(dpy, attrs, format, outConfig); } +String8 EGLUtils::printGLString(const char* name, GLenum s) { + String8 msg; + const char* v = reinterpret_cast<const char*>(glGetString(s)); + msg.appendFormat("GL %s = %s\n", name, v); + return msg; +} + +String8 EGLUtils::printEGLString(EGLDisplay dpy, const char* name, GLenum s) { + String8 msg; + const char* v = static_cast<const char*>(eglQueryString(dpy, s)); + msg.appendFormat("GL %s = %s\n", name, v); + const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s); + msg.appendFormat("ImplementationANDROID: %s = %s\n", name, va); + return msg; +} + +String8 EGLUtils::checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { + String8 msg; + if (returnVal != EGL_TRUE) { + msg.appendFormat("%s() returned %d\n", op, returnVal); + } + + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { + msg.appendFormat("after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error); + } + return msg; +} + +String8 EGLUtils::checkGlError(const char* op) { + String8 msg; + for (GLint error = glGetError(); error != GL_NO_ERROR; error = glGetError()) { + msg.appendFormat("after %s() glError (0x%x)\n", op, error); + } + return msg; +} + +String8 EGLUtils::printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { +#define X(VAL) \ + { VAL, #VAL } + struct { + EGLint attribute; + const char* name; + } names[] = { + X(EGL_BUFFER_SIZE), + X(EGL_ALPHA_SIZE), + X(EGL_BLUE_SIZE), + X(EGL_GREEN_SIZE), + X(EGL_RED_SIZE), + X(EGL_DEPTH_SIZE), + X(EGL_STENCIL_SIZE), + X(EGL_CONFIG_CAVEAT), + X(EGL_CONFIG_ID), + X(EGL_LEVEL), + X(EGL_MAX_PBUFFER_HEIGHT), + X(EGL_MAX_PBUFFER_PIXELS), + X(EGL_MAX_PBUFFER_WIDTH), + X(EGL_NATIVE_RENDERABLE), + X(EGL_NATIVE_VISUAL_ID), + X(EGL_NATIVE_VISUAL_TYPE), + X(EGL_SAMPLES), + X(EGL_SAMPLE_BUFFERS), + X(EGL_SURFACE_TYPE), + X(EGL_TRANSPARENT_TYPE), + X(EGL_TRANSPARENT_RED_VALUE), + X(EGL_TRANSPARENT_GREEN_VALUE), + X(EGL_TRANSPARENT_BLUE_VALUE), + X(EGL_BIND_TO_TEXTURE_RGB), + X(EGL_BIND_TO_TEXTURE_RGBA), + X(EGL_MIN_SWAP_INTERVAL), + X(EGL_MAX_SWAP_INTERVAL), + X(EGL_LUMINANCE_SIZE), + X(EGL_ALPHA_MASK_SIZE), + X(EGL_COLOR_BUFFER_TYPE), + X(EGL_RENDERABLE_TYPE), + X(EGL_CONFORMANT), + }; +#undef X + + String8 msg; + for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { + EGLint value = -1; + EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); + EGLint error = eglGetError(); + if (returnVal && error == EGL_SUCCESS) { + msg.appendFormat(" %s: %d (0x%x)", names[j].name, value, value); + } + } + msg.append("\n"); + return msg; +} + +bool EGLUtils::printEGLConfigurations(EGLDisplay dpy, String8& msg) { + EGLint numConfig = 0; + EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig); + msg.append(checkEglError("eglGetConfigs", returnVal)); + if (!returnVal) { + return false; + } + + msg.appendFormat("Number of EGL configuration: %d\n", numConfig); + + std::vector<EGLConfig> configs(numConfig); + + returnVal = eglGetConfigs(dpy, configs.data(), numConfig, &numConfig); + msg.append(checkEglError("eglGetConfigs", returnVal)); + if (!returnVal) { + return false; + } + + for (int i = 0; i < numConfig; i++) { + msg.appendFormat("Configuration %d\n", i); + msg.append(printEGLConfiguration(dpy, configs[i])); + } + + return true; +} + +bool EGLUtils::printEGLConfigurations(FILE* output, EGLDisplay dpy) { + String8 msg; + bool status = printEGLConfigurations(dpy, msg); + fprintf(output, "%s", msg.c_str()); + return status; +} + +String8 EGLUtils::decodeColorSpace(EGLint colorSpace) { + switch (colorSpace) { + case EGL_GL_COLORSPACE_SRGB_KHR: + return String8("EGL_GL_COLORSPACE_SRGB_KHR"); + case EGL_GL_COLORSPACE_DISPLAY_P3_EXT: + return String8("EGL_GL_COLORSPACE_DISPLAY_P3_EXT"); + case EGL_GL_COLORSPACE_LINEAR_KHR: + return String8("EGL_GL_COLORSPACE_LINEAR_KHR"); + default: + return String8::format("UNKNOWN ColorSpace %d", colorSpace); + } +} + +bool EGLUtils::hasExtension(const char* exts, const char* name) { + size_t nameLen = strlen(name); + if (exts) { + for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) { + if (match[nameLen] == '\0' || match[nameLen] == ' ') { + return true; + } + } + } + return false; +} + +bool EGLUtils::hasEglExtension(EGLDisplay dpy, const char* name) { + return hasExtension(eglQueryString(dpy, EGL_EXTENSIONS), name); +} + // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS new file mode 100644 index 0000000000..6a38a1ff14 --- /dev/null +++ b/services/sensorservice/OWNERS @@ -0,0 +1,2 @@ +ashutoshj@google.com +pengxu@google.com diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 7d9b0b730a..da3b2758d1 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -223,8 +223,13 @@ ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { } void SensorDevice::autoDisable(void *ident, int handle) { - Info& info( mActivationCount.editValueFor(handle) ); Mutex::Autolock _l(mLock); + ssize_t activationIndex = mActivationCount.indexOfKey(handle); + if (activationIndex < 0) { + ALOGW("Handle %d cannot be found in activation record", handle); + return; + } + Info& info(mActivationCount.editValueAt(activationIndex)); info.removeBatchParamsForIdent(ident); } @@ -235,7 +240,12 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) { bool actuateHardware = false; Mutex::Autolock _l(mLock); - Info& info( mActivationCount.editValueFor(handle) ); + ssize_t activationIndex = mActivationCount.indexOfKey(handle); + if (activationIndex < 0) { + ALOGW("Handle %d cannot be found in activation record", handle); + return BAD_VALUE; + } + Info& info(mActivationCount.editValueAt(activationIndex)); ALOGD_IF(DEBUG_CONNECTIONS, "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu", @@ -329,7 +339,12 @@ status_t SensorDevice::batch( ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs); Mutex::Autolock _l(mLock); - Info& info(mActivationCount.editValueFor(handle)); + ssize_t activationIndex = mActivationCount.indexOfKey(handle); + if (activationIndex < 0) { + ALOGW("Handle %d cannot be found in activation record", handle); + return BAD_VALUE; + } + Info& info(mActivationCount.editValueAt(activationIndex)); if (info.batchParams.indexOfKey(ident) < 0) { BatchParams params(samplingPeriodNs, maxBatchReportLatencyNs); diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index cc93105543..4775e4ef54 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -2,3 +2,5 @@ cc_library_static { name: "libsurfaceflingerincludes", export_include_dirs: ["."], } + +subdirs = ["tests/fakehwc"]
\ No newline at end of file diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 744dd50df5..0244c1b862 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -28,6 +28,7 @@ #include <utils/RefBase.h> #include <utils/Log.h> +#include <ui/DebugUtils.h> #include <ui/DisplayInfo.h> #include <ui/PixelFormat.h> @@ -134,9 +135,11 @@ DisplayDevice::DisplayDevice( EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { #ifdef USE_HWC2 - config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888); + config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888, + /*logConfig*/ false); #else - config = RenderEngine::chooseEglConfig(display, format); + config = RenderEngine::chooseEglConfig(display, format, + /*logConfig*/ false); #endif } eglSurface = eglCreateWindowSurface(display, config, window, NULL); @@ -615,6 +618,7 @@ uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() { void DisplayDevice::dump(String8& result) const { const Transform& tr(mGlobalTransform); + ANativeWindow* const window = mNativeWindow.get(); EGLint redSize, greenSize, blueSize, alphaSize; eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize); eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize); @@ -624,9 +628,9 @@ void DisplayDevice::dump(String8& result) const { result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p " "(%d:%d:%d:%d), orient=%2d (type=%08x), " "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n", - mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, - mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation, - tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, + mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window, + redSize, greenSize, blueSize, alphaSize, mOrientation, tr.getType(), + getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, mVisibleLayersSortedByZ.size()); result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d]," "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n", @@ -634,6 +638,9 @@ void DisplayDevice::dump(String8& result) const { mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); + auto const surface = static_cast<Surface*>(window); + android_dataspace dataspace = surface->getBuffersDataSpace(); + result.appendFormat(" dataspace: %s (%d)\n", dataspaceDetails(dataspace).c_str(), dataspace); String8 surfaceDump; mDisplaySurface->dumpAsString(surfaceDump); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index e34fa163c4..433a224e25 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -157,15 +157,11 @@ void Composer::CommandWriter::writeBufferMetadata( write64(metadata.usage); } -Composer::Composer(bool useVrComposer) +Composer::Composer(const std::string& serviceName) : mWriter(kWriterInitialSize), - mIsUsingVrComposer(useVrComposer) + mIsUsingVrComposer(serviceName == std::string("vr")) { - if (mIsUsingVrComposer) { - mComposer = IComposer::getService("vr"); - } else { - mComposer = IComposer::getService(); // use default name - } + mComposer = IComposer::getService(serviceName); if (mComposer == nullptr) { LOG_ALWAYS_FATAL("failed to get hwcomposer service"); @@ -219,6 +215,10 @@ void Composer::registerCallback(const sp<IComposerCallback>& callback) } } +bool Composer::isRemote() { + return mClient->isRemote(); +} + void Composer::resetCommands() { mWriter.reset(); } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 96dd833cd5..31a3c1d785 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -136,13 +136,18 @@ private: // Composer is a wrapper to IComposer, a proxy to server-side composer. class Composer { public: - Composer(bool useVrComposer); + Composer(const std::string& serviceName); std::vector<IComposer::Capability> getCapabilities(); std::string dumpDebugInfo(); void registerCallback(const sp<IComposerCallback>& callback); + // Returns true if the connected composer service is running in a remote + // process, false otherwise. This will return false if the service is + // configured in passthrough mode, for example. + bool isRemote(); + // Reset all pending commands in the command buffer. Useful if you want to // skip a frame but have already queued some commands. void resetCommands(); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 270a73228b..78c0c8567a 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -33,45 +33,6 @@ #include <algorithm> #include <inttypes.h> -extern "C" { - static void hotplug_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId, int32_t intConnected) { - auto device = static_cast<HWC2::Device*>(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - auto connected = static_cast<HWC2::Connection>(intConnected); - device->callHotplug(std::move(display), connected); - } else { - ALOGE("Hotplug callback called with unknown display %" PRIu64, - displayId); - } - } - - static void refresh_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId) { - auto device = static_cast<HWC2::Device*>(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - device->callRefresh(std::move(display)); - } else { - ALOGE("Refresh callback called with unknown display %" PRIu64, - displayId); - } - } - - static void vsync_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId, int64_t timestamp) { - auto device = static_cast<HWC2::Device*>(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - device->callVsync(std::move(display), timestamp); - } else { - ALOGE("Vsync callback called with unknown display %" PRIu64, - displayId); - } - } -} - using android::Fence; using android::FloatRect; using android::GraphicBuffer; @@ -86,51 +47,78 @@ namespace HWC2 { namespace Hwc2 = android::Hwc2; +namespace { + +class ComposerCallbackBridge : public Hwc2::IComposerCallback { +public: + ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId) + : mCallback(callback), mSequenceId(sequenceId), + mHasPrimaryDisplay(false) {} + + Return<void> onHotplug(Hwc2::Display display, + IComposerCallback::Connection conn) override + { + HWC2::Connection connection = static_cast<HWC2::Connection>(conn); + if (!mHasPrimaryDisplay) { + LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected, + "Initial onHotplug callback should be " + "primary display connected"); + mHasPrimaryDisplay = true; + mCallback->onHotplugReceived(mSequenceId, display, + connection, true); + } else { + mCallback->onHotplugReceived(mSequenceId, display, + connection, false); + } + return Void(); + } + + Return<void> onRefresh(Hwc2::Display display) override + { + mCallback->onRefreshReceived(mSequenceId, display); + return Void(); + } + + Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override + { + mCallback->onVsyncReceived(mSequenceId, display, timestamp); + return Void(); + } + + bool HasPrimaryDisplay() { return mHasPrimaryDisplay; } + +private: + ComposerCallback* mCallback; + int32_t mSequenceId; + bool mHasPrimaryDisplay; +}; + +} // namespace anonymous + + // Device methods -Device::Device(bool useVrComposer) - : mComposer(std::make_unique<Hwc2::Composer>(useVrComposer)), +Device::Device(const std::string& serviceName) + : mComposer(std::make_unique<Hwc2::Composer>(serviceName)), mCapabilities(), mDisplays(), - mHotplug(), - mPendingHotplugs(), - mRefresh(), - mPendingRefreshes(), - mVsync(), - mPendingVsyncs() + mRegisteredCallback(false) { loadCapabilities(); - registerCallbacks(); } -Device::~Device() -{ - for (auto element : mDisplays) { - auto display = element.second.lock(); - if (!display) { - ALOGE("~Device: Found a display (%" PRId64 " that has already been" - " destroyed", element.first); - continue; - } - - DisplayType displayType = HWC2::DisplayType::Invalid; - auto error = display->getType(&displayType); - if (error != Error::None) { - ALOGE("~Device: Failed to determine type of display %" PRIu64 - ": %s (%d)", display->getId(), to_string(error).c_str(), - static_cast<int32_t>(error)); - continue; - } - - if (displayType == HWC2::DisplayType::Physical) { - error = display->setVsyncEnabled(HWC2::Vsync::Disable); - if (error != Error::None) { - ALOGE("~Device: Failed to disable vsync for display %" PRIu64 - ": %s (%d)", display->getId(), to_string(error).c_str(), - static_cast<int32_t>(error)); - } - } +void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) { + if (mRegisteredCallback) { + ALOGW("Callback already registered. Ignored extra registration " + "attempt."); + return; } + mRegisteredCallback = true; + sp<ComposerCallbackBridge> callbackBridge( + new ComposerCallbackBridge(callback, sequenceId)); + mComposer->registerCallback(callbackBridge); + LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(), + "Registered composer callback but didn't get primary display"); } // Required by HWC2 device @@ -146,7 +134,7 @@ uint32_t Device::getMaxVirtualDisplayCount() const } Error Device::createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, std::shared_ptr<Display>* outDisplay) + android_pixel_format_t* format, Display** outDisplay) { ALOGI("Creating virtual display"); @@ -159,104 +147,66 @@ Error Device::createVirtualDisplay(uint32_t width, uint32_t height, return error; } - ALOGI("Created virtual display"); + auto display = std::make_unique<Display>( + *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual); + *outDisplay = display.get(); *format = static_cast<android_pixel_format_t>(intFormat); - *outDisplay = getDisplayById(displayId); - if (!*outDisplay) { - ALOGE("Failed to get display by id"); - return Error::BadDisplay; - } - (*outDisplay)->setConnected(true); + mDisplays.emplace(displayId, std::move(display)); + ALOGI("Created virtual display"); return Error::None; } -void Device::registerHotplugCallback(HotplugCallback hotplug) +void Device::destroyDisplay(hwc2_display_t displayId) { - ALOGV("registerHotplugCallback"); - mHotplug = hotplug; - for (auto& pending : mPendingHotplugs) { - auto& display = pending.first; - auto connected = pending.second; - ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(), - to_string(connected).c_str()); - mHotplug(std::move(display), connected); - } + ALOGI("Destroying display %" PRIu64, displayId); + mDisplays.erase(displayId); } -void Device::registerRefreshCallback(RefreshCallback refresh) -{ - mRefresh = refresh; - for (auto& pending : mPendingRefreshes) { - mRefresh(std::move(pending)); - } -} - -void Device::registerVsyncCallback(VsyncCallback vsync) -{ - mVsync = vsync; - for (auto& pending : mPendingVsyncs) { - auto& display = pending.first; - auto timestamp = pending.second; - mVsync(std::move(display), timestamp); - } -} - -// For use by Device callbacks +void Device::onHotplug(hwc2_display_t displayId, Connection connection) { + if (connection == Connection::Connected) { + auto display = getDisplayById(displayId); + if (display) { + if (display->isConnected()) { + ALOGW("Attempt to hotplug connect display %" PRIu64 + " , which is already connected.", displayId); + } else { + display->setConnected(true); + } + } else { + DisplayType displayType; + auto intError = mComposer->getDisplayType(displayId, + reinterpret_cast<Hwc2::IComposerClient::DisplayType *>( + &displayType)); + auto error = static_cast<Error>(intError); + if (error != Error::None) { + ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). " + "Aborting hotplug attempt.", + displayId, to_string(error).c_str(), intError); + return; + } -void Device::callHotplug(std::shared_ptr<Display> display, Connection connected) -{ - if (connected == Connection::Connected) { - if (!display->isConnected()) { - mComposer->setClientTargetSlotCount(display->getId()); - display->loadConfigs(); - display->setConnected(true); + auto newDisplay = std::make_unique<Display>( + *mComposer.get(), mCapabilities, displayId, displayType); + mDisplays.emplace(displayId, std::move(newDisplay)); + } + } else if (connection == Connection::Disconnected) { + // The display will later be destroyed by a call to + // destroyDisplay(). For now we just mark it disconnected. + auto display = getDisplayById(displayId); + if (display) { + display->setConnected(false); + } else { + ALOGW("Attempted to disconnect unknown display %" PRIu64, + displayId); } - } else { - display->setConnected(false); - mDisplays.erase(display->getId()); - } - - if (mHotplug) { - mHotplug(std::move(display), connected); - } else { - ALOGV("callHotplug called, but no valid callback registered, storing"); - mPendingHotplugs.emplace_back(std::move(display), connected); - } -} - -void Device::callRefresh(std::shared_ptr<Display> display) -{ - if (mRefresh) { - mRefresh(std::move(display)); - } else { - ALOGV("callRefresh called, but no valid callback registered, storing"); - mPendingRefreshes.emplace_back(std::move(display)); - } -} - -void Device::callVsync(std::shared_ptr<Display> display, nsecs_t timestamp) -{ - if (mVsync) { - mVsync(std::move(display), timestamp); - } else { - ALOGV("callVsync called, but no valid callback registered, storing"); - mPendingVsyncs.emplace_back(std::move(display), timestamp); } } // Other Device methods -std::shared_ptr<Display> Device::getDisplayById(hwc2_display_t id) { - if (mDisplays.count(id) != 0) { - auto strongDisplay = mDisplays[id].lock(); - ALOGE_IF(!strongDisplay, "Display %" PRId64 " is in mDisplays but is no" - " longer alive", id); - return strongDisplay; - } - - auto display = std::make_shared<Display>(*this, id); - mDisplays.emplace(id, display); - return display; +Display* Device::getDisplayById(hwc2_display_t id) { + auto iter = mDisplays.find(id); + return iter == mDisplays.end() ? nullptr : iter->second.get(); } // Device initialization methods @@ -271,84 +221,37 @@ void Device::loadCapabilities() } } -bool Device::hasCapability(HWC2::Capability capability) const -{ - return std::find(mCapabilities.cbegin(), mCapabilities.cend(), - capability) != mCapabilities.cend(); -} - -namespace { -class ComposerCallback : public Hwc2::IComposerCallback { -public: - ComposerCallback(Device* device) : mDevice(device) {} - - Return<void> onHotplug(Hwc2::Display display, - Connection connected) override - { - hotplug_hook(mDevice, display, static_cast<int32_t>(connected)); - return Void(); - } - - Return<void> onRefresh(Hwc2::Display display) override - { - refresh_hook(mDevice, display); - return Void(); - } - - Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override - { - vsync_hook(mDevice, display, timestamp); - return Void(); - } - -private: - Device* mDevice; -}; -} // namespace anonymous - -void Device::registerCallbacks() -{ - sp<ComposerCallback> callback = new ComposerCallback(this); - mComposer->registerCallback(callback); -} - - -// For use by Display - -void Device::destroyVirtualDisplay(hwc2_display_t display) -{ - ALOGI("Destroying virtual display"); - auto intError = mComposer->destroyVirtualDisplay(display); - auto error = static_cast<Error>(intError); - ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:" - " %s (%d)", display, to_string(error).c_str(), intError); - mDisplays.erase(display); -} - // Display methods -Display::Display(Device& device, hwc2_display_t id) - : mDevice(device), +Display::Display(android::Hwc2::Composer& composer, + const std::unordered_set<Capability>& capabilities, + hwc2_display_t id, DisplayType type) + : mComposer(composer), + mCapabilities(capabilities), mId(id), mIsConnected(false), - mType(DisplayType::Invalid) + mType(type) { ALOGV("Created display %" PRIu64, id); - - auto intError = mDevice.mComposer->getDisplayType(mId, - reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(&mType)); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)", - id, to_string(error).c_str(), intError); - } + setConnected(true); } -Display::~Display() -{ - ALOGV("Destroyed display %" PRIu64, mId); +Display::~Display() { + mLayers.clear(); + if (mType == DisplayType::Virtual) { - mDevice.destroyVirtualDisplay(mId); + ALOGV("Destroying virtual display"); + auto intError = mComposer.destroyVirtualDisplay(mId); + auto error = static_cast<Error>(intError); + ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 + ") failed: %s (%d)", mId, to_string(error).c_str(), intError); + } else if (mType == DisplayType::Physical) { + auto error = setVsyncEnabled(HWC2::Vsync::Disable); + if (error != Error::None) { + ALOGE("~Display: Failed to disable vsync for display %" PRIu64 + ": %s (%d)", mId, to_string(error).c_str(), + static_cast<int32_t>(error)); + } } } @@ -383,22 +286,35 @@ float Display::Config::Builder::getDefaultDensity() { Error Display::acceptChanges() { - auto intError = mDevice.mComposer->acceptDisplayChanges(mId); + auto intError = mComposer.acceptDisplayChanges(mId); return static_cast<Error>(intError); } -Error Display::createLayer(std::shared_ptr<Layer>* outLayer) +Error Display::createLayer(Layer** outLayer) { + if (!outLayer) { + return Error::BadParameter; + } hwc2_layer_t layerId = 0; - auto intError = mDevice.mComposer->createLayer(mId, &layerId); + auto intError = mComposer.createLayer(mId, &layerId); auto error = static_cast<Error>(intError); if (error != Error::None) { return error; } - auto layer = std::make_shared<Layer>(shared_from_this(), layerId); - mLayers.emplace(layerId, layer); - *outLayer = std::move(layer); + auto layer = std::make_unique<Layer>( + mComposer, mCapabilities, mId, layerId); + *outLayer = layer.get(); + mLayers.emplace(layerId, std::move(layer)); + return Error::None; +} + +Error Display::destroyLayer(Layer* layer) +{ + if (!layer) { + return Error::BadParameter; + } + mLayers.erase(layer->getId()); return Error::None; } @@ -407,7 +323,7 @@ Error Display::getActiveConfig( { ALOGV("[%" PRIu64 "] getActiveConfig", mId); hwc2_config_t configId = 0; - auto intError = mDevice.mComposer->getActiveConfig(mId, &configId); + auto intError = mComposer.getActiveConfig(mId, &configId); auto error = static_cast<Error>(intError); if (error != Error::None) { @@ -430,12 +346,12 @@ Error Display::getActiveConfig( } Error Display::getChangedCompositionTypes( - std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes) + std::unordered_map<Layer*, Composition>* outTypes) { std::vector<Hwc2::Layer> layerIds; std::vector<Hwc2::IComposerClient::Composition> types; - auto intError = mDevice.mComposer->getChangedCompositionTypes(mId, - &layerIds, &types); + auto intError = mComposer.getChangedCompositionTypes( + mId, &layerIds, &types); uint32_t numElements = layerIds.size(); auto error = static_cast<Error>(intError); error = static_cast<Error>(intError); @@ -464,7 +380,7 @@ Error Display::getChangedCompositionTypes( Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const { std::vector<Hwc2::ColorMode> modes; - auto intError = mDevice.mComposer->getColorModes(mId, &modes); + auto intError = mComposer.getColorModes(mId, &modes); uint32_t numModes = modes.size(); auto error = static_cast<Error>(intError); if (error != Error::None) { @@ -489,19 +405,18 @@ std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const Error Display::getName(std::string* outName) const { - auto intError = mDevice.mComposer->getDisplayName(mId, outName); + auto intError = mComposer.getDisplayName(mId, outName); return static_cast<Error>(intError); } Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, - std::unordered_map<std::shared_ptr<Layer>, LayerRequest>* - outLayerRequests) + std::unordered_map<Layer*, LayerRequest>* outLayerRequests) { uint32_t intDisplayRequests; std::vector<Hwc2::Layer> layerIds; std::vector<uint32_t> layerRequests; - auto intError = mDevice.mComposer->getDisplayRequests(mId, - &intDisplayRequests, &layerIds, &layerRequests); + auto intError = mComposer.getDisplayRequests( + mId, &intDisplayRequests, &layerIds, &layerRequests); uint32_t numElements = layerIds.size(); auto error = static_cast<Error>(intError); if (error != Error::None) { @@ -535,7 +450,7 @@ Error Display::getType(DisplayType* outType) const Error Display::supportsDoze(bool* outSupport) const { bool intSupport = false; - auto intError = mDevice.mComposer->getDozeSupport(mId, &intSupport); + auto intError = mComposer.getDozeSupport(mId, &intSupport); auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -552,7 +467,7 @@ Error Display::getHdrCapabilities( float maxAverageLuminance = -1.0f; float minLuminance = -1.0f; std::vector<Hwc2::Hdr> intTypes; - auto intError = mDevice.mComposer->getHdrCapabilities(mId, &intTypes, + auto intError = mComposer.getHdrCapabilities(mId, &intTypes, &maxLuminance, &maxAverageLuminance, &minLuminance); auto error = static_cast<HWC2::Error>(intError); @@ -571,25 +486,24 @@ Error Display::getHdrCapabilities( } Error Display::getReleaseFences( - std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const + std::unordered_map<Layer*, sp<Fence>>* outFences) const { std::vector<Hwc2::Layer> layerIds; std::vector<int> fenceFds; - auto intError = mDevice.mComposer->getReleaseFences(mId, - &layerIds, &fenceFds); + auto intError = mComposer.getReleaseFences(mId, &layerIds, &fenceFds); auto error = static_cast<Error>(intError); uint32_t numElements = layerIds.size(); if (error != Error::None) { return error; } - std::unordered_map<std::shared_ptr<Layer>, sp<Fence>> releaseFences; + std::unordered_map<Layer*, sp<Fence>> releaseFences; releaseFences.reserve(numElements); for (uint32_t element = 0; element < numElements; ++element) { auto layer = getLayerById(layerIds[element]); if (layer) { sp<Fence> fence(new Fence(fenceFds[element])); - releaseFences.emplace(std::move(layer), fence); + releaseFences.emplace(layer, fence); } else { ALOGE("getReleaseFences: invalid layer %" PRIu64 " found on display %" PRIu64, layerIds[element], mId); @@ -607,7 +521,7 @@ Error Display::getReleaseFences( Error Display::present(sp<Fence>* outPresentFence) { int32_t presentFenceFd = -1; - auto intError = mDevice.mComposer->presentDisplay(mId, &presentFenceFd); + auto intError = mComposer.presentDisplay(mId, &presentFenceFd); auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -625,7 +539,7 @@ Error Display::setActiveConfig(const std::shared_ptr<const Config>& config) config->getDisplayId(), mId); return Error::BadConfig; } - auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId()); + auto intError = mComposer.setActiveConfig(mId, config->getId()); return static_cast<Error>(intError); } @@ -634,7 +548,7 @@ Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target, { // TODO: Properly encode client target surface damage int32_t fenceFd = acquireFence->dup(); - auto intError = mDevice.mComposer->setClientTarget(mId, slot, target, + auto intError = mComposer.setClientTarget(mId, slot, target, fenceFd, static_cast<Hwc2::Dataspace>(dataspace), std::vector<Hwc2::IComposerClient::Rect>()); return static_cast<Error>(intError); @@ -642,15 +556,15 @@ Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target, Error Display::setColorMode(android_color_mode_t mode) { - auto intError = mDevice.mComposer->setColorMode(mId, - static_cast<Hwc2::ColorMode>(mode)); + auto intError = mComposer.setColorMode( + mId, static_cast<Hwc2::ColorMode>(mode)); return static_cast<Error>(intError); } Error Display::setColorTransform(const android::mat4& matrix, android_color_transform_t hint) { - auto intError = mDevice.mComposer->setColorTransform(mId, + auto intError = mComposer.setColorTransform(mId, matrix.asArray(), static_cast<Hwc2::ColorTransform>(hint)); return static_cast<Error>(intError); } @@ -660,7 +574,7 @@ Error Display::setOutputBuffer(const sp<GraphicBuffer>& buffer, { int32_t fenceFd = releaseFence->dup(); auto handle = buffer->getNativeBuffer()->handle; - auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd); + auto intError = mComposer.setOutputBuffer(mId, handle, fenceFd); close(fenceFd); return static_cast<Error>(intError); } @@ -668,14 +582,14 @@ Error Display::setOutputBuffer(const sp<GraphicBuffer>& buffer, Error Display::setPowerMode(PowerMode mode) { auto intMode = static_cast<Hwc2::IComposerClient::PowerMode>(mode); - auto intError = mDevice.mComposer->setPowerMode(mId, intMode); + auto intError = mComposer.setPowerMode(mId, intMode); return static_cast<Error>(intError); } Error Display::setVsyncEnabled(Vsync enabled) { auto intEnabled = static_cast<Hwc2::IComposerClient::Vsync>(enabled); - auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled); + auto intError = mComposer.setVsyncEnabled(mId, intEnabled); return static_cast<Error>(intError); } @@ -683,8 +597,7 @@ Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests) { uint32_t numTypes = 0; uint32_t numRequests = 0; - auto intError = mDevice.mComposer->validateDisplay(mId, - &numTypes, &numRequests); + auto intError = mComposer.validateDisplay(mId, &numTypes, &numRequests); auto error = static_cast<Error>(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -701,7 +614,8 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests uint32_t numTypes = 0; uint32_t numRequests = 0; int32_t presentFenceFd = -1; - auto intError = mDevice.mComposer->presentOrValidateDisplay(mId, &numTypes, &numRequests, &presentFenceFd, state); + auto intError = mComposer.presentOrValidateDisplay( + mId, &numTypes, &numRequests, &presentFenceFd, state); auto error = static_cast<Error>(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -720,15 +634,23 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests void Display::discardCommands() { - mDevice.mComposer->resetCommands(); + mComposer.resetCommands(); } // For use by Device +void Display::setConnected(bool connected) { + if (!mIsConnected && connected && mType == DisplayType::Physical) { + mComposer.setClientTargetSlotCount(mId); + loadConfigs(); + } + mIsConnected = connected; +} + int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute) { int32_t value = 0; - auto intError = mDevice.mComposer->getDisplayAttribute(mId, configId, + auto intError = mComposer.getDisplayAttribute(mId, configId, static_cast<Hwc2::IComposerClient::Attribute>(attribute), &value); auto error = static_cast<Error>(intError); @@ -760,7 +682,7 @@ void Display::loadConfigs() ALOGV("[%" PRIu64 "] loadConfigs", mId); std::vector<Hwc2::Config> configIds; - auto intError = mDevice.mComposer->getDisplayConfigs(mId, &configIds); + auto intError = mComposer.getDisplayConfigs(mId, &configIds); auto error = static_cast<Error>(intError); if (error != Error::None) { ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId, @@ -773,54 +695,51 @@ void Display::loadConfigs() } } -// For use by Layer - -void Display::destroyLayer(hwc2_layer_t layerId) -{ - auto intError =mDevice.mComposer->destroyLayer(mId, layerId); - auto error = static_cast<Error>(intError); - ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" - " failed: %s (%d)", mId, layerId, to_string(error).c_str(), - intError); - mLayers.erase(layerId); -} - // Other Display methods -std::shared_ptr<Layer> Display::getLayerById(hwc2_layer_t id) const +Layer* Display::getLayerById(hwc2_layer_t id) const { if (mLayers.count(id) == 0) { return nullptr; } - auto layer = mLayers.at(id).lock(); - return layer; + return mLayers.at(id).get(); } // Layer methods -Layer::Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id) - : mDisplay(display), - mDisplayId(display->getId()), - mDevice(display->getDevice()), - mId(id) +Layer::Layer(android::Hwc2::Composer& composer, + const std::unordered_set<Capability>& capabilities, + hwc2_display_t displayId, hwc2_layer_t layerId) + : mComposer(composer), + mCapabilities(capabilities), + mDisplayId(displayId), + mId(layerId) { - ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id, - display->getId()); + ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId); } Layer::~Layer() { - auto display = mDisplay.lock(); - if (display) { - display->destroyLayer(mId); + auto intError = mComposer.destroyLayer(mDisplayId, mId); + auto error = static_cast<Error>(intError); + ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" + " failed: %s (%d)", mDisplayId, mId, to_string(error).c_str(), + intError); + if (mLayerDestroyedListener) { + mLayerDestroyedListener(this); } } +void Layer::setLayerDestroyedListener(std::function<void(Layer*)> listener) { + LOG_ALWAYS_FATAL_IF(mLayerDestroyedListener && listener, + "Attempt to set layer destroyed listener multiple times"); + mLayerDestroyedListener = listener; +} + Error Layer::setCursorPosition(int32_t x, int32_t y) { - auto intError = mDevice.mComposer->setCursorPosition(mDisplayId, - mId, x, y); + auto intError = mComposer.setCursorPosition(mDisplayId, mId, x, y); return static_cast<Error>(intError); } @@ -828,8 +747,8 @@ Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence) { int32_t fenceFd = acquireFence->dup(); - auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId, - mId, slot, buffer, fenceFd); + auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer, + fenceFd); return static_cast<Error>(intError); } @@ -839,7 +758,7 @@ Error Layer::setSurfaceDamage(const Region& damage) // rects for HWC Hwc2::Error intError = Hwc2::Error::NONE; if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) { - intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, + intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, std::vector<Hwc2::IComposerClient::Rect>()); } else { size_t rectCount = 0; @@ -851,8 +770,7 @@ Error Layer::setSurfaceDamage(const Region& damage) rectArray[rect].right, rectArray[rect].bottom}); } - intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, - mId, hwcRects); + intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, hwcRects); } return static_cast<Error>(intError); @@ -861,24 +779,22 @@ Error Layer::setSurfaceDamage(const Region& damage) Error Layer::setBlendMode(BlendMode mode) { auto intMode = static_cast<Hwc2::IComposerClient::BlendMode>(mode); - auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId, - mId, intMode); + auto intError = mComposer.setLayerBlendMode(mDisplayId, mId, intMode); return static_cast<Error>(intError); } Error Layer::setColor(hwc_color_t color) { Hwc2::IComposerClient::Color hwcColor{color.r, color.g, color.b, color.a}; - auto intError = mDevice.mComposer->setLayerColor(mDisplayId, - mId, hwcColor); + auto intError = mComposer.setLayerColor(mDisplayId, mId, hwcColor); return static_cast<Error>(intError); } Error Layer::setCompositionType(Composition type) { auto intType = static_cast<Hwc2::IComposerClient::Composition>(type); - auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId, - mId, intType); + auto intError = mComposer.setLayerCompositionType( + mDisplayId, mId, intType); return static_cast<Error>(intError); } @@ -889,8 +805,7 @@ Error Layer::setDataspace(android_dataspace_t dataspace) } mDataSpace = dataspace; auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace); - auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId, - mId, intDataspace); + auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace); return static_cast<Error>(intError); } @@ -898,27 +813,24 @@ Error Layer::setDisplayFrame(const Rect& frame) { Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top, frame.right, frame.bottom}; - auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId, - mId, hwcRect); + auto intError = mComposer.setLayerDisplayFrame(mDisplayId, mId, hwcRect); return static_cast<Error>(intError); } Error Layer::setPlaneAlpha(float alpha) { - auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId, - mId, alpha); + auto intError = mComposer.setLayerPlaneAlpha(mDisplayId, mId, alpha); return static_cast<Error>(intError); } Error Layer::setSidebandStream(const native_handle_t* stream) { - if (!mDevice.hasCapability(Capability::SidebandStream)) { + if (mCapabilities.count(Capability::SidebandStream) == 0) { ALOGE("Attempted to call setSidebandStream without checking that the " "device supports sideband streams"); return Error::Unsupported; } - auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId, - mId, stream); + auto intError = mComposer.setLayerSidebandStream(mDisplayId, mId, stream); return static_cast<Error>(intError); } @@ -926,16 +838,14 @@ Error Layer::setSourceCrop(const FloatRect& crop) { Hwc2::IComposerClient::FRect hwcRect{ crop.left, crop.top, crop.right, crop.bottom}; - auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId, - mId, hwcRect); + auto intError = mComposer.setLayerSourceCrop(mDisplayId, mId, hwcRect); return static_cast<Error>(intError); } Error Layer::setTransform(Transform transform) { auto intTransform = static_cast<Hwc2::Transform>(transform); - auto intError = mDevice.mComposer->setLayerTransform(mDisplayId, - mId, intTransform); + auto intError = mComposer.setLayerTransform(mDisplayId, mId, intTransform); return static_cast<Error>(intError); } @@ -950,20 +860,19 @@ Error Layer::setVisibleRegion(const Region& region) rectArray[rect].right, rectArray[rect].bottom}); } - auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId, - mId, hwcRects); + auto intError = mComposer.setLayerVisibleRegion(mDisplayId, mId, hwcRects); return static_cast<Error>(intError); } Error Layer::setZOrder(uint32_t z) { - auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z); + auto intError = mComposer.setLayerZOrder(mDisplayId, mId, z); return static_cast<Error>(intError); } Error Layer::setInfo(uint32_t type, uint32_t appId) { - auto intError = mDevice.mComposer->setLayerInfo(mDisplayId, mId, type, appId); + auto intError = mComposer.setLayerInfo(mDisplayId, mId, type, appId); return static_cast<Error>(intError); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 404bb284c5..fbe4c7ebed 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -53,24 +53,37 @@ namespace HWC2 { class Display; class Layer; -typedef std::function<void(std::shared_ptr<Display>, Connection)> - HotplugCallback; -typedef std::function<void(std::shared_ptr<Display>)> RefreshCallback; -typedef std::function<void(std::shared_ptr<Display>, nsecs_t)> VsyncCallback; +// Implement this interface to receive hardware composer events. +// +// These callback functions will generally be called on a hwbinder thread, but +// when first registering the callback the onHotplugReceived() function will +// immediately be called on the thread calling registerCallback(). +// +// All calls receive a sequenceId, which will be the value that was supplied to +// HWC2::Device::registerCallback(). It's used to help differentiate callbacks +// from different hardware composer instances. +class ComposerCallback { + public: + virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, + Connection connection, + bool primaryDisplay) = 0; + virtual void onRefreshReceived(int32_t sequenceId, + hwc2_display_t display) = 0; + virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, + int64_t timestamp) = 0; + virtual ~ComposerCallback() = default; +}; // C++ Wrapper around hwc2_device_t. Load all functions pointers // and handle callback registration. class Device { public: - // useVrComposer is passed to the composer HAL. When true, the composer HAL - // will use the vr composer service, otherwise it uses the real hardware - // composer. - Device(bool useVrComposer); - ~Device(); + // Service name is expected to be 'default' or 'vr' for normal use. + // 'vr' will slightly modify the behavior of the mComposer. + Device(const std::string& serviceName); - friend class HWC2::Display; - friend class HWC2::Layer; + void registerCallback(ComposerCallback* callback, int32_t sequenceId); // Required by HWC2 @@ -82,27 +95,14 @@ public: uint32_t getMaxVirtualDisplayCount() const; Error createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, - std::shared_ptr<Display>* outDisplay); - - void registerHotplugCallback(HotplugCallback hotplug); - void registerRefreshCallback(RefreshCallback refresh); - void registerVsyncCallback(VsyncCallback vsync); + android_pixel_format_t* format, Display** outDisplay); + void destroyDisplay(hwc2_display_t displayId); - // For use by callbacks - - void callHotplug(std::shared_ptr<Display> display, Connection connected); - void callRefresh(std::shared_ptr<Display> display); - void callVsync(std::shared_ptr<Display> display, nsecs_t timestamp); + void onHotplug(hwc2_display_t displayId, Connection connection); // Other Device methods - // This will create a Display if one is not found, but it will not be marked - // as connected. This Display may be null if the display has been torn down - // but has not been removed from the map yet. - std::shared_ptr<Display> getDisplayById(hwc2_display_t id); - - bool hasCapability(HWC2::Capability capability) const; + Display* getDisplayById(hwc2_display_t id); android::Hwc2::Composer* getComposer() { return mComposer.get(); } @@ -110,37 +110,23 @@ private: // Initialization methods void loadCapabilities(); - void registerCallbacks(); - - // For use by Display - - void destroyVirtualDisplay(hwc2_display_t display); // Member variables std::unique_ptr<android::Hwc2::Composer> mComposer; - std::unordered_set<Capability> mCapabilities; - std::unordered_map<hwc2_display_t, std::weak_ptr<Display>> mDisplays; - - HotplugCallback mHotplug; - std::vector<std::pair<std::shared_ptr<Display>, Connection>> - mPendingHotplugs; - RefreshCallback mRefresh; - std::vector<std::shared_ptr<Display>> mPendingRefreshes; - VsyncCallback mVsync; - std::vector<std::pair<std::shared_ptr<Display>, nsecs_t>> mPendingVsyncs; + std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays; + bool mRegisteredCallback; }; // Convenience C++ class to access hwc2_device_t Display functions directly. -class Display : public std::enable_shared_from_this<Display> +class Display { public: - Display(Device& device, hwc2_display_t id); + Display(android::Hwc2::Composer& composer, + const std::unordered_set<Capability>& capabilities, + hwc2_display_t id, DisplayType type); ~Display(); - friend class HWC2::Device; - friend class HWC2::Layer; - class Config { public: @@ -213,12 +199,12 @@ public: // Required by HWC2 [[clang::warn_unused_result]] Error acceptChanges(); - [[clang::warn_unused_result]] Error createLayer( - std::shared_ptr<Layer>* outLayer); + [[clang::warn_unused_result]] Error createLayer(Layer** outLayer); + [[clang::warn_unused_result]] Error destroyLayer(Layer* layer); [[clang::warn_unused_result]] Error getActiveConfig( std::shared_ptr<const Config>* outConfig) const; [[clang::warn_unused_result]] Error getChangedCompositionTypes( - std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes); + std::unordered_map<Layer*, Composition>* outTypes); [[clang::warn_unused_result]] Error getColorModes( std::vector<android_color_mode_t>* outModes) const; @@ -228,14 +214,13 @@ public: [[clang::warn_unused_result]] Error getName(std::string* outName) const; [[clang::warn_unused_result]] Error getRequests( DisplayRequest* outDisplayRequests, - std::unordered_map<std::shared_ptr<Layer>, LayerRequest>* - outLayerRequests); + std::unordered_map<Layer*, LayerRequest>* outLayerRequests); [[clang::warn_unused_result]] Error getType(DisplayType* outType) const; [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const; [[clang::warn_unused_result]] Error getHdrCapabilities( std::unique_ptr<android::HdrCapabilities>* outCapabilities) const; [[clang::warn_unused_result]] Error getReleaseFences( - std::unordered_map<std::shared_ptr<Layer>, + std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const; [[clang::warn_unused_result]] Error present( android::sp<android::Fence>* outPresentFence); @@ -267,32 +252,31 @@ public: // Other Display methods - Device& getDevice() const { return mDevice; } hwc2_display_t getId() const { return mId; } bool isConnected() const { return mIsConnected; } + void setConnected(bool connected); // For use by Device only private: - // For use by Device - - void setConnected(bool connected) { mIsConnected = connected; } int32_t getAttribute(hwc2_config_t configId, Attribute attribute); void loadConfig(hwc2_config_t configId); void loadConfigs(); - // For use by Layer - void destroyLayer(hwc2_layer_t layerId); - // This may fail (and return a null pointer) if no layer with this ID exists // on this display - std::shared_ptr<Layer> getLayerById(hwc2_layer_t id) const; + Layer* getLayerById(hwc2_layer_t id) const; // Member variables - Device& mDevice; + // These are references to data owned by HWC2::Device, which will outlive + // this HWC2::Display, so these references are guaranteed to be valid for + // the lifetime of this object. + android::Hwc2::Composer& mComposer; + const std::unordered_set<Capability>& mCapabilities; + hwc2_display_t mId; bool mIsConnected; DisplayType mType; - std::unordered_map<hwc2_layer_t, std::weak_ptr<Layer>> mLayers; + std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers; // The ordering in this map matters, for getConfigs(), when it is // converted to a vector std::map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs; @@ -302,12 +286,18 @@ private: class Layer { public: - Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id); + Layer(android::Hwc2::Composer& composer, + const std::unordered_set<Capability>& capabilities, + hwc2_display_t displayId, hwc2_layer_t layerId); ~Layer(); - bool isAbandoned() const { return mDisplay.expired(); } hwc2_layer_t getId() const { return mId; } + // Register a listener to be notified when the layer is destroyed. When the + // listener function is called, the Layer will be in the process of being + // destroyed, so it's not safe to call methods on it. + void setLayerDestroyedListener(std::function<void(Layer*)> listener); + [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y); [[clang::warn_unused_result]] Error setBuffer(uint32_t slot, const android::sp<android::GraphicBuffer>& buffer, @@ -334,11 +324,16 @@ public: [[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId); private: - std::weak_ptr<Display> mDisplay; + // These are references to data owned by HWC2::Device, which will outlive + // this HWC2::Layer, so these references are guaranteed to be valid for + // the lifetime of this object. + android::Hwc2::Composer& mComposer; + const std::unordered_set<Capability>& mCapabilities; + hwc2_display_t mDisplayId; - Device& mDevice; hwc2_layer_t mId; android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + std::function<void(Layer*)> mLayerDestroyedListener; }; } // namespace HWC2 diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index ac2dde29d4..b096a3ae57 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -59,13 +59,12 @@ namespace android { // --------------------------------------------------------------------------- -HWComposer::HWComposer(bool useVrComposer) +HWComposer::HWComposer(const std::string& serviceName) : mHwcDevice(), mDisplayData(2), mFreeDisplaySlots(), mHwcDisplaySlots(), mCBContext(), - mEventHandler(nullptr), mVSyncCounts(), mRemainingHwcVirtualDisplays(0) { @@ -74,40 +73,15 @@ HWComposer::HWComposer(bool useVrComposer) mVSyncCounts[i] = 0; } - loadHwcModule(useVrComposer); + mHwcDevice = std::make_unique<HWC2::Device>(serviceName); + mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); } HWComposer::~HWComposer() {} -void HWComposer::setEventHandler(EventHandler* handler) -{ - if (handler == nullptr) { - ALOGE("setEventHandler: Rejected attempt to clear handler"); - return; - } - - bool wasNull = (mEventHandler == nullptr); - mEventHandler = handler; - - if (wasNull) { - auto hotplugHook = std::bind(&HWComposer::hotplug, this, - std::placeholders::_1, std::placeholders::_2); - mHwcDevice->registerHotplugCallback(hotplugHook); - auto invalidateHook = std::bind(&HWComposer::invalidate, this, - std::placeholders::_1); - mHwcDevice->registerRefreshCallback(invalidateHook); - auto vsyncHook = std::bind(&HWComposer::vsync, this, - std::placeholders::_1, std::placeholders::_2); - mHwcDevice->registerVsyncCallback(vsyncHook); - } -} - -// Load and prepare the hardware composer module. Sets mHwc. -void HWComposer::loadHwcModule(bool useVrComposer) -{ - ALOGV("loadHwcModule"); - mHwcDevice = std::make_unique<HWC2::Device>(useVrComposer); - mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); +void HWComposer::registerCallback(HWC2::ComposerCallback* callback, + int32_t sequenceId) { + mHwcDevice->registerCallback(callback, sequenceId); } bool HWComposer::hasCapability(HWC2::Capability capability) const @@ -145,54 +119,51 @@ void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) { } } -void HWComposer::hotplug(const std::shared_ptr<HWC2::Display>& display, - HWC2::Connection connected) { - ALOGV("hotplug: %" PRIu64 ", %s", display->getId(), - to_string(connected).c_str()); - int32_t disp = 0; +void HWComposer::onHotplug(hwc2_display_t displayId, + HWC2::Connection connection) { + ALOGV("hotplug: %" PRIu64 ", %s", displayId, + to_string(connection).c_str()); + mHwcDevice->onHotplug(displayId, connection); if (!mDisplayData[0].hwcDisplay) { - ALOGE_IF(connected != HWC2::Connection::Connected, "Assumed primary" + ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary" " display would be connected"); - mDisplayData[0].hwcDisplay = display; - mHwcDisplaySlots[display->getId()] = 0; - disp = DisplayDevice::DISPLAY_PRIMARY; + mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId); + mHwcDisplaySlots[displayId] = 0; } else { // Disconnect is handled through HWComposer::disconnectDisplay via // SurfaceFlinger's onHotplugReceived callback handling - if (connected == HWC2::Connection::Connected) { - mDisplayData[1].hwcDisplay = display; - mHwcDisplaySlots[display->getId()] = 1; + if (connection == HWC2::Connection::Connected) { + mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId); + mHwcDisplaySlots[displayId] = 1; } - disp = DisplayDevice::DISPLAY_EXTERNAL; } - mEventHandler->onHotplugReceived(this, disp, - connected == HWC2::Connection::Connected); -} - -void HWComposer::invalidate(const std::shared_ptr<HWC2::Display>& /*display*/) { - mEventHandler->onInvalidateReceived(this); } -void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display, - int64_t timestamp) { +bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp, + int32_t* outDisplay) { + auto display = mHwcDevice->getDisplayById(displayId); + if (!display) { + ALOGE("onVsync Failed to find display %" PRIu64, displayId); + return false; + } auto displayType = HWC2::DisplayType::Invalid; auto error = display->getType(&displayType); if (error != HWC2::Error::None) { - ALOGE("vsync: Failed to determine type of display %" PRIu64, + ALOGE("onVsync: Failed to determine type of display %" PRIu64, display->getId()); - return; + return false; } if (displayType == HWC2::DisplayType::Virtual) { ALOGE("Virtual display %" PRIu64 " passed to vsync callback", display->getId()); - return; + return false; } if (mHwcDisplaySlots.count(display->getId()) == 0) { ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback", display->getId()); - return; + return false; } int32_t disp = mHwcDisplaySlots[display->getId()]; @@ -206,17 +177,21 @@ void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display, if (timestamp == mLastHwVSync[disp]) { ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", timestamp); - return; + return false; } mLastHwVSync[disp] = timestamp; } + if (outDisplay) { + *outDisplay = disp; + } + char tag[16]; snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); - mEventHandler->onVSyncReceived(this, disp, timestamp); + return true; } status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, @@ -235,7 +210,7 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, return INVALID_OPERATION; } - std::shared_ptr<HWC2::Display> display; + HWC2::Display* display; auto error = mHwcDevice->createVirtualDisplay(width, height, format, &display); if (error != HWC2::Error::None) { @@ -264,13 +239,13 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, return NO_ERROR; } -std::shared_ptr<HWC2::Layer> HWComposer::createLayer(int32_t displayId) { +HWC2::Layer* HWComposer::createLayer(int32_t displayId) { if (!isValidDisplay(displayId)) { ALOGE("Failed to create layer on invalid display %d", displayId); return nullptr; } auto display = mDisplayData[displayId].hwcDisplay; - std::shared_ptr<HWC2::Layer> layer; + HWC2::Layer* layer; auto error = display->createLayer(&layer); if (error != HWC2::Error::None) { ALOGE("Failed to create layer on display %d: %s (%d)", displayId, @@ -280,6 +255,19 @@ std::shared_ptr<HWC2::Layer> HWComposer::createLayer(int32_t displayId) { return layer; } +void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) { + if (!isValidDisplay(displayId)) { + ALOGE("Failed to destroy layer on invalid display %d", displayId); + return; + } + auto display = mDisplayData[displayId].hwcDisplay; + auto error = display->destroyLayer(layer); + if (error != HWC2::Error::None) { + ALOGE("Failed to destroy layer on display %d: %s (%d)", displayId, + to_string(error).c_str(), static_cast<int32_t>(error)); + } +} + nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const { // this returns the last refresh timestamp. // if the last one is not available, we estimate it based on @@ -347,10 +335,8 @@ std::vector<android_color_mode_t> HWComposer::getColorModes(int32_t displayId) c displayId); return modes; } - const std::shared_ptr<HWC2::Display>& hwcDisplay = - mDisplayData[displayId].hwcDisplay; - auto error = hwcDisplay->getColorModes(&modes); + auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes); if (error != HWC2::Error::None) { ALOGE("getColorModes failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast<int32_t>(error)); @@ -470,7 +456,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { return UNKNOWN_ERROR; } if (state == 1) { //Present Succeeded. - std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences; + std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); displayData.releaseFences = std::move(releaseFences); displayData.lastPresentFence = outPresentFence; @@ -489,8 +475,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { return BAD_INDEX; } - std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::Composition> - changedTypes; + std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes; changedTypes.reserve(numTypes); error = hwcDisplay->getChangedCompositionTypes(&changedTypes); if (error != HWC2::Error::None) { @@ -502,8 +487,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0); - std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::LayerRequest> - layerRequests; + std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests; layerRequests.reserve(numRequests); error = hwcDisplay->getRequests(&displayData.displayRequests, &layerRequests); @@ -597,7 +581,7 @@ sp<Fence> HWComposer::getPresentFence(int32_t displayId) const { } sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId, - const std::shared_ptr<HWC2::Layer>& layer) const { + HWC2::Layer* layer) const { if (!isValidDisplay(displayId)) { ALOGE("getLayerReleaseFence: Invalid display"); return Fence::NO_FENCE; @@ -638,7 +622,7 @@ status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) { return UNKNOWN_ERROR; } - std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences; + std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); if (error != HWC2::Error::None) { ALOGE("presentAndGetReleaseFences: Failed to get release fences " @@ -786,6 +770,8 @@ void HWComposer::disconnectDisplay(int displayId) { auto hwcId = displayData.hwcDisplay->getId(); mHwcDisplaySlots.erase(hwcId); displayData.reset(); + + mHwcDevice->destroyDisplay(hwcId); } status_t HWComposer::setOutputBuffer(int32_t displayId, @@ -884,7 +870,7 @@ void HWComposer::dump(String8& result) const { HWComposer::DisplayData::DisplayData() : hasClientComposition(false), hasDeviceComposition(false), - hwcDisplay(), + hwcDisplay(nullptr), lastPresentFence(Fence::NO_FENCE), outbufHandle(nullptr), outbufAcquireFence(Fence::NO_FENCE), diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 7463362c35..3640bb5a98 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -65,24 +65,14 @@ class String8; class HWComposer { public: - class EventHandler { - friend class HWComposer; - virtual void onVSyncReceived( - HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0; - virtual void onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) = 0; - virtual void onInvalidateReceived(HWComposer* composer) = 0; - protected: - virtual ~EventHandler() {} - }; - - // useVrComposer is passed to the composer HAL. When true, the composer HAL - // will use the vr composer service, otherwise it uses the real hardware - // composer. - HWComposer(bool useVrComposer); + // Uses the named composer service. Valid choices for normal use + // are 'default' and 'vr'. + HWComposer(const std::string& serviceName); ~HWComposer(); - void setEventHandler(EventHandler* handler); + void registerCallback(HWC2::ComposerCallback* callback, + int32_t sequenceId); bool hasCapability(HWC2::Capability capability) const; @@ -92,7 +82,9 @@ public: android_pixel_format_t* format, int32_t* outId); // Attempts to create a new layer on this display - std::shared_ptr<HWC2::Layer> createLayer(int32_t displayId); + HWC2::Layer* createLayer(int32_t displayId); + // Destroy a previously created layer + void destroyLayer(int32_t displayId, HWC2::Layer* layer); // Asks the HAL what it can do status_t prepare(DisplayDevice& displayDevice); @@ -127,7 +119,7 @@ public: // Get last release fence for the given layer sp<Fence> getLayerReleaseFence(int32_t displayId, - const std::shared_ptr<HWC2::Layer>& layer) const; + HWC2::Layer* layer) const; // Set the output buffer and acquire fence for a virtual display. // Returns INVALID_OPERATION if displayId is not a virtual display. @@ -143,6 +135,12 @@ public: // Events handling --------------------------------------------------------- + // Returns true if successful, false otherwise. The + // DisplayDevice::DisplayType of the display is returned as an output param. + bool onVsync(hwc2_display_t displayId, int64_t timestamp, + int32_t* outDisplay); + void onHotplug(hwc2_display_t displayId, HWC2::Connection connection); + void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled); // Query display parameters. Pass in a display index (e.g. @@ -170,19 +168,11 @@ public: private: static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2; - void loadHwcModule(bool useVrComposer); - bool isValidDisplay(int32_t displayId) const; static void validateChange(HWC2::Composition from, HWC2::Composition to); struct cb_context; - void invalidate(const std::shared_ptr<HWC2::Display>& display); - void vsync(const std::shared_ptr<HWC2::Display>& display, - int64_t timestamp); - void hotplug(const std::shared_ptr<HWC2::Display>& display, - HWC2::Connection connected); - struct DisplayData { DisplayData(); ~DisplayData(); @@ -190,11 +180,10 @@ private: bool hasClientComposition; bool hasDeviceComposition; - std::shared_ptr<HWC2::Display> hwcDisplay; + HWC2::Display* hwcDisplay; HWC2::DisplayRequest displayRequests; sp<Fence> lastPresentFence; // signals when the last set op retires - std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> - releaseFences; + std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; buffer_handle_t outbufHandle; sp<Fence> outbufAcquireFence; mutable std::unordered_map<int32_t, @@ -215,7 +204,6 @@ private: mutable Mutex mDisplayLock; cb_context* mCBContext; - EventHandler* mEventHandler; size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]; uint32_t mRemainingHwcVirtualDisplays; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 34f1cecfde..1de5e48cb9 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -627,6 +627,10 @@ status_t VirtualDisplaySurface::getUniqueId(uint64_t* /*outId*/) const { return INVALID_OPERATION; } +status_t VirtualDisplaySurface::getConsumerUsage(uint64_t* outUsage) const { + return mSource[SOURCE_SINK]->getConsumerUsage(outUsage); +} + void VirtualDisplaySurface::updateQueueBufferOutput( QueueBufferOutput&& qbo) { mQueueBufferOutput = std::move(qbo); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index ac200caea5..1671aba1d8 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -130,6 +130,7 @@ private: virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) override; virtual status_t getUniqueId(uint64_t* outId) const override; + virtual status_t getConsumerUsage(uint64_t* outUsage) const override; // // Utility methods diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp index ee6e886d12..052a959724 100644 --- a/services/surfaceflinger/EventControlThread.cpp +++ b/services/surfaceflinger/EventControlThread.cpp @@ -31,34 +31,35 @@ void EventControlThread::setVsyncEnabled(bool enabled) { } bool EventControlThread::threadLoop() { - Mutex::Autolock lock(mMutex); - - bool vsyncEnabled = mVsyncEnabled; - -#ifdef USE_HWC2 - mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); -#else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, - mVsyncEnabled); -#endif + enum class VsyncState {Unset, On, Off}; + auto currentVsyncState = VsyncState::Unset; while (true) { - status_t err = mCond.wait(mMutex); - if (err != NO_ERROR) { - ALOGE("error waiting for new events: %s (%d)", - strerror(-err), err); - return false; + auto requestedVsyncState = VsyncState::On; + { + Mutex::Autolock lock(mMutex); + requestedVsyncState = + mVsyncEnabled ? VsyncState::On : VsyncState::Off; + while (currentVsyncState == requestedVsyncState) { + status_t err = mCond.wait(mMutex); + if (err != NO_ERROR) { + ALOGE("error waiting for new events: %s (%d)", + strerror(-err), err); + return false; + } + requestedVsyncState = + mVsyncEnabled ? VsyncState::On : VsyncState::Off; + } } - if (vsyncEnabled != mVsyncEnabled) { + bool enable = requestedVsyncState == VsyncState::On; #ifdef USE_HWC2 - mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); + mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable); #else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, - SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled); + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, + SurfaceFlinger::EVENT_VSYNC, enable); #endif - vsyncEnabled = mVsyncEnabled; - } + currentVsyncState = requestedVsyncState; } return false; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 8eb406747a..e92565fd9c 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -40,6 +40,7 @@ #include <gui/BufferItem.h> #include <gui/BufferQueue.h> +#include <gui/LayerDebugInfo.h> #include <gui/Surface.h> #include "clz.h" @@ -200,6 +201,14 @@ Layer::~Layer() { } mFlinger->deleteTextureAsync(mTextureName); mFrameTracker.logAndResetStats(mName); + +#ifdef USE_HWC2 + if (!mHwcLayers.empty()) { + ALOGE("Found stale hardware composer layers when destroying " + "surface flinger layer %s", mName.string()); + destroyAllHwcLayers(); + } +#endif } // --------------------------------------------------------------------------- @@ -287,22 +296,29 @@ void Layer::onSidebandStreamChanged() { } } -// called with SurfaceFlinger::mStateLock from the drawing thread after -// the layer has been remove from the current state list (and just before -// it's removed from the drawing state list) -void Layer::onRemoved() { +void Layer::onRemovedFromCurrentState() { + // the layer is removed from SF mCurrentState to mLayersPendingRemoval + if (mCurrentState.zOrderRelativeOf != nullptr) { sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote(); if (strongRelative != nullptr) { strongRelative->removeZOrderRelative(this); + mFlinger->setTransactionFlags(eTraversalNeeded); } mCurrentState.zOrderRelativeOf = nullptr; } - mSurfaceFlingerConsumer->abandon(); + for (const auto& child : mCurrentChildren) { + child->onRemovedFromCurrentState(); + } +} +void Layer::onRemoved() { + // the layer is removed from SF mLayersPendingRemoval + + mSurfaceFlingerConsumer->abandon(); #ifdef USE_HWC2 - clearHwcLayers(); + destroyAllHwcLayers(); #endif for (const auto& child : mCurrentChildren) { @@ -363,6 +379,48 @@ sp<IGraphicBufferProducer> Layer::getProducer() const { // h/w composer set-up // --------------------------------------------------------------------------- +#ifdef USE_HWC2 +bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) { + LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, + "Already have a layer for hwcId %d", hwcId); + HWC2::Layer* layer = hwc->createLayer(hwcId); + if (!layer) { + return false; + } + HWCInfo& hwcInfo = mHwcLayers[hwcId]; + hwcInfo.hwc = hwc; + hwcInfo.layer = layer; + layer->setLayerDestroyedListener( + [this, hwcId] (HWC2::Layer* /*layer*/){mHwcLayers.erase(hwcId);}); + return true; +} + +void Layer::destroyHwcLayer(int32_t hwcId) { + if (mHwcLayers.count(hwcId) == 0) { + return; + } + auto& hwcInfo = mHwcLayers[hwcId]; + LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, + "Attempt to destroy null layer"); + LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer"); + hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer); + // The layer destroyed listener should have cleared the entry from + // mHwcLayers. Verify that. + LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, + "Stale layer entry in mHwcLayers"); +} + +void Layer::destroyAllHwcLayers() { + size_t numLayers = mHwcLayers.size(); + for (size_t i = 0; i < numLayers; ++i) { + LOG_ALWAYS_FATAL_IF(mHwcLayers.empty(), "destroyAllHwcLayers failed"); + destroyHwcLayer(mHwcLayers.begin()->first); + } + LOG_ALWAYS_FATAL_IF(!mHwcLayers.empty(), + "All hardware composer layers should have been destroyed"); +} +#endif + Rect Layer::getContentCrop() const { // this is the crop rectangle that applies to the buffer // itself (as opposed to the window) @@ -2363,71 +2421,51 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { // debugging // ---------------------------------------------------------------------------- -void Layer::dump(String8& result, Colorizer& colorizer) const -{ - const Layer::State& s(getDrawingState()); - - colorizer.colorize(result, Colorizer::GREEN); - result.appendFormat( - "+ %s %p (%s)\n", - getTypeId(), this, getName().string()); - colorizer.reset(result); - - s.activeTransparentRegion.dump(result, "transparentRegion"); - visibleRegion.dump(result, "visibleRegion"); - surfaceDamageRegion.dump(result, "surfaceDamageRegion"); - sp<Client> client(mClientRef.promote()); - PixelFormat pf = PIXEL_FORMAT_UNKNOWN; - const sp<GraphicBuffer>& buffer(getActiveBuffer()); - if (buffer != NULL) { - pf = buffer->getPixelFormat(); - } - +LayerDebugInfo Layer::getLayerDebugInfo() const { + LayerDebugInfo info; + const Layer::State& ds = getDrawingState(); + info.mName = getName(); sp<Layer> parent = getParent(); - - result.appendFormat( " " - "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), " - "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), " - "isOpaque=%1d, invalidate=%1d, " - "dataspace=%s, pixelformat=%s " -#ifdef USE_HWC2 - "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" -#else - "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" -#endif - " client=%p parent=%s\n", - getLayerStack(), s.z, - s.active.transform.tx(), s.active.transform.ty(), - s.active.w, s.active.h, - s.crop.left, s.crop.top, - s.crop.right, s.crop.bottom, - s.finalCrop.left, s.finalCrop.top, - s.finalCrop.right, s.finalCrop.bottom, - isOpaque(s), contentDirty, - dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(), - s.alpha, s.flags, - s.active.transform[0][0], s.active.transform[0][1], - s.active.transform[1][0], s.active.transform[1][1], - client.get(), parent == nullptr ? "none" : parent->getName().string()); - - sp<const GraphicBuffer> buf0(mActiveBuffer); - uint32_t w0=0, h0=0, s0=0, f0=0; - if (buf0 != 0) { - w0 = buf0->getWidth(); - h0 = buf0->getHeight(); - s0 = buf0->getStride(); - f0 = buf0->format; - } - result.appendFormat( - " " - "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," - " queued-frames=%d, mRefreshPending=%d\n", - mFormat, w0, h0, s0,f0, - mQueuedFrames, mRefreshPending); - - if (mSurfaceFlingerConsumer != 0) { - mSurfaceFlingerConsumer->dumpState(result, " "); + info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string()); + info.mType = String8(getTypeId()); + info.mTransparentRegion = ds.activeTransparentRegion; + info.mVisibleRegion = visibleRegion; + info.mSurfaceDamageRegion = surfaceDamageRegion; + info.mLayerStack = getLayerStack(); + info.mX = ds.active.transform.tx(); + info.mY = ds.active.transform.ty(); + info.mZ = ds.z; + info.mWidth = ds.active.w; + info.mHeight = ds.active.h; + info.mCrop = ds.crop; + info.mFinalCrop = ds.finalCrop; + info.mAlpha = ds.alpha; + info.mFlags = ds.flags; + info.mPixelFormat = getPixelFormat(); + info.mDataSpace = getDataSpace(); + info.mMatrix[0][0] = ds.active.transform[0][0]; + info.mMatrix[0][1] = ds.active.transform[0][1]; + info.mMatrix[1][0] = ds.active.transform[1][0]; + info.mMatrix[1][1] = ds.active.transform[1][1]; + { + sp<const GraphicBuffer> activeBuffer = getActiveBuffer(); + if (activeBuffer != 0) { + info.mActiveBufferWidth = activeBuffer->getWidth(); + info.mActiveBufferHeight = activeBuffer->getHeight(); + info.mActiveBufferStride = activeBuffer->getStride(); + info.mActiveBufferFormat = activeBuffer->format; + } else { + info.mActiveBufferWidth = 0; + info.mActiveBufferHeight = 0; + info.mActiveBufferStride = 0; + info.mActiveBufferFormat = 0; + } } + info.mNumQueuedFrames = getQueuedFrameCount(); + info.mRefreshPending = isBufferLatched(); + info.mIsOpaque = isOpaque(ds); + info.mContentDirty = contentDirty; + return info; } #ifdef USE_HWC2 diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2306d1a43a..f7b82e4fb7 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -60,6 +60,7 @@ class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; +class LayerDebugInfo; // --------------------------------------------------------------------------- @@ -419,8 +420,14 @@ public: bool isPotentialCursor() const { return mPotentialCursor;} /* - * called with the state lock when the surface is removed from the - * current list + * called with the state lock from a binder thread when the layer is + * removed from the current list to the pending removal list + */ + void onRemovedFromCurrentState(); + + /* + * called with the state lock from the main thread when the layer is + * removed from the pending removal list */ void onRemoved(); @@ -441,40 +448,26 @@ public: bool hasQueuedFrame() const { return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; } + int32_t getQueuedFrameCount() const { return mQueuedFrames; } + #ifdef USE_HWC2 // ----------------------------------------------------------------------- + bool createHwcLayer(HWComposer* hwc, int32_t hwcId); + void destroyHwcLayer(int32_t hwcId); + void destroyAllHwcLayers(); + bool hasHwcLayer(int32_t hwcId) { - if (mHwcLayers.count(hwcId) == 0) { - return false; - } - if (mHwcLayers[hwcId].layer->isAbandoned()) { - ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId); - mHwcLayers.erase(hwcId); - return false; - } - return true; + return mHwcLayers.count(hwcId) > 0; } - std::shared_ptr<HWC2::Layer> getHwcLayer(int32_t hwcId) { + HWC2::Layer* getHwcLayer(int32_t hwcId) { if (mHwcLayers.count(hwcId) == 0) { return nullptr; } return mHwcLayers[hwcId].layer; } - void setHwcLayer(int32_t hwcId, std::shared_ptr<HWC2::Layer>&& layer) { - if (layer) { - mHwcLayers[hwcId].layer = layer; - } else { - mHwcLayers.erase(hwcId); - } - } - - void clearHwcLayers() { - mHwcLayers.clear(); - } - #endif // ----------------------------------------------------------------------- @@ -489,9 +482,9 @@ public: inline const State& getCurrentState() const { return mCurrentState; } inline State& getCurrentState() { return mCurrentState; } + LayerDebugInfo getLayerDebugInfo() const; /* always call base class first */ - void dump(String8& result, Colorizer& colorizer) const; #ifdef USE_HWC2 static void miniDumpHeader(String8& result); void miniDump(String8& result, int32_t hwcId) const; @@ -689,6 +682,9 @@ public: sp<IGraphicBufferProducer> getProducer() const; const String8& getName() const; void notifyAvailableFrames(); + + PixelFormat getPixelFormat() const { return mFormat; } + private: // ----------------------------------------------------------------------- @@ -760,12 +756,14 @@ private: // HWC items, accessed from the main thread struct HWCInfo { HWCInfo() - : layer(), + : hwc(nullptr), + layer(nullptr), forceClientComposition(false), compositionType(HWC2::Composition::Invalid), clearClientTarget(false) {} - std::shared_ptr<HWC2::Layer> layer; + HWComposer* hwc; + HWC2::Layer* layer; bool forceClientComposition; HWC2::Composition compositionType; bool clearClientTarget; diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index d1038202d4..1a5a85e079 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -158,6 +158,10 @@ status_t MonitoredProducer::getUniqueId(uint64_t* outId) const { return mProducer->getUniqueId(outId); } +status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const { + return mProducer->getConsumerUsage(outUsage); +} + IBinder* MonitoredProducer::onAsBinder() { return this; } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index ff7f0f0e8c..1246d142f3 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -68,6 +68,7 @@ public: virtual status_t setAutoRefresh(bool autoRefresh) override; virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override; virtual status_t getUniqueId(uint64_t* outId) const override; + virtual status_t getConsumerUsage(uint64_t* outUsage) const override; // The Layer which created this producer, and on which queued Buffer's will be displayed. sp<Layer> getLayer() const; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index ac2d8b2aba..56e9ac07ad 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -26,7 +26,7 @@ #include <vector> #include <SurfaceFlinger.h> -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); // --------------------------------------------------------------------------- namespace android { @@ -64,7 +64,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f "EGL_ANDROIDX_no_config_context") && !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), "EGL_KHR_no_config_context")) { - config = chooseEglConfig(display, hwcFormat); + config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint renderableType = 0; @@ -108,7 +108,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f EGLConfig dummyConfig = config; if (dummyConfig == EGL_NO_CONFIG) { - dummyConfig = chooseEglConfig(display, hwcFormat); + dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs); @@ -406,7 +406,8 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, return err; } -EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { +EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, + bool logConfig) { status_t err; EGLConfig config; @@ -427,18 +428,20 @@ EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { } } - // print some debugging info - EGLint r,g,b,a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); - ALOGI("EGL information:"); - ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); - ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); - ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); - ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + if (logConfig) { + // print some debugging info + EGLint r,g,b,a; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); + ALOGI("EGL information:"); + ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); + ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); + ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + } return config; } diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 56f582755e..954457946e 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -64,7 +64,7 @@ public: }; static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags); - static EGLConfig chooseEglConfig(EGLDisplay display, int format); + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); void primeCache() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index aaaafbfa9e..6a01f308a3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -46,6 +46,7 @@ #include <gui/BufferQueue.h> #include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> +#include <gui/LayerDebugInfo.h> #include <gui/Surface.h> #include <ui/GraphicBufferAllocator.h> @@ -76,6 +77,7 @@ #include "MonitoredProducer.h" #include "SurfaceFlinger.h" +#include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" @@ -96,14 +98,28 @@ */ #define DEBUG_SCREENSHOTS false -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { - using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +namespace { +class ConditionalLock { +public: + ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) { + if (lock) { + mMutex.lock(); + } + } + ~ConditionalLock() { if (mLocked) mMutex.unlock(); } +private: + Mutex& mMutex; + bool mLocked; +}; +} // namespace anonymous + // --------------------------------------------------------------------------- const String16 sHardwareTest("android.permission.HARDWARE_TEST"); @@ -123,6 +139,21 @@ bool SurfaceFlinger::useVrFlinger; int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; bool SurfaceFlinger::hasWideColorDisplay; + +std::string getHwcServiceName() { + char value[PROPERTY_VALUE_MAX] = {}; + property_get("debug.sf.hwc_service_name", value, "default"); + ALOGI("Using HWComposer service: '%s'", value); + return std::string(value); +} + +bool useTrebleTestingOverride() { + char value[PROPERTY_VALUE_MAX] = {}; + property_get("debug.sf.treble_testing_override", value, "false"); + ALOGI("Treble testing override: '%s'", value); + return std::string(value) == "true"; +} + SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), mTransactionFlags(0), @@ -131,9 +162,7 @@ SurfaceFlinger::SurfaceFlinger() mLayersRemoved(false), mLayersAdded(false), mRepaintEverything(0), - mHwc(nullptr), - mRealHwc(nullptr), - mVrHwc(nullptr), + mHwcServiceName(getHwcServiceName()), mRenderEngine(nullptr), mBootTime(systemTime()), mBuiltinDisplays(), @@ -160,7 +189,9 @@ SurfaceFlinger::SurfaceFlinger() mTotalTime(0), mLastSwapTime(0), mNumLayers(0), - mVrFlingerRequestsDisplay(false) + mVrFlingerRequestsDisplay(false), + mMainThreadId(std::this_thread::get_id()), + mComposerSequenceId(0) { ALOGI("SurfaceFlinger is starting"); @@ -233,6 +264,15 @@ SurfaceFlinger::SurfaceFlinger() // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is // instead read after the boot animation + + if (useTrebleTestingOverride()) { + // Without the override SurfaceFlinger cannot connect to HIDL + // services that are not listed in the manifests. Considered + // deriving the setting from the set service name, but it + // would be brittle if the name that's not 'default' is used + // for production purposes later on. + setenv("TREBLE_TESTING_OVERRIDE", "true", true); + } } void SurfaceFlinger::onFirstRef() @@ -377,20 +417,10 @@ void SurfaceFlinger::bootFinished() LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); - sp<LambdaMessage> bootFinished = new LambdaMessage([&]() { - mBootFinished = true; - + sp<LambdaMessage> readProperties = new LambdaMessage([&]() { readPersistentProperties(); - -#ifdef USE_HWC2 - sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); - if (hw->getWideColorSupport()) { - hw->setCompositionDataSpace(HAL_DATASPACE_V0_SRGB); - setActiveColorModeInternal(hw, HAL_COLOR_MODE_SRGB); - } -#endif }); - postMessageAsync(bootFinished); + postMessageAsync(readProperties); } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { @@ -555,50 +585,48 @@ void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); - ALOGI("Phase offset NS: %" PRId64 "", vsyncPhaseOffsetNs); + ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs); - { // Autolock scope - Mutex::Autolock _l(mStateLock); + Mutex::Autolock _l(mStateLock); - // initialize EGL for the default display - mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(mEGLDisplay, NULL, NULL); - - // start the EventThread - sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, - vsyncPhaseOffsetNs, true, "app"); - mEventThread = new EventThread(vsyncSrc, *this, false); - sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, - sfVsyncPhaseOffsetNs, true, "sf"); - mSFEventThread = new EventThread(sfVsyncSrc, *this, true); - mEventQueue.setEventThread(mSFEventThread); + // initialize EGL for the default display + mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEGLDisplay, NULL, NULL); - // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter - struct sched_param param = {0}; - param.sched_priority = 2; - if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); - } - if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for EventThread"); - } + // start the EventThread + sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, + vsyncPhaseOffsetNs, true, "app"); + mEventThread = new EventThread(vsyncSrc, *this, false); + sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, + sfVsyncPhaseOffsetNs, true, "sf"); + mSFEventThread = new EventThread(sfVsyncSrc, *this, true); + mEventQueue.setEventThread(mSFEventThread); - // Get a RenderEngine for the given display / config (can't fail) - mRenderEngine = RenderEngine::create(mEGLDisplay, - HAL_PIXEL_FORMAT_RGBA_8888, - hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); + // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter + struct sched_param param = {0}; + param.sched_priority = 2; + if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); + } + if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for EventThread"); } - // Drop the state lock while we initialize the hardware composer. We drop - // the lock because on creation, it will call back into SurfaceFlinger to - // initialize the primary display. - LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, - "Starting with vr flinger active is not currently supported."); - mRealHwc = new HWComposer(false); - mHwc = mRealHwc; - mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this)); + // Get a RenderEngine for the given display / config (can't fail) + mRenderEngine = RenderEngine::create(mEGLDisplay, + HAL_PIXEL_FORMAT_RGBA_8888, + hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); - Mutex::Autolock _l(mStateLock); + // retrieve the EGL context that was selected/created + mEGLContext = mRenderEngine->getEGLContext(); + + LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, + "couldn't create EGLContext"); + + LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, + "Starting with vr flinger active is not currently supported."); + mHwc.reset(new HWComposer(mHwcServiceName)); + mHwc->registerCallback(this, mComposerSequenceId); if (useVrFlinger) { auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { @@ -613,16 +641,6 @@ void SurfaceFlinger::init() { } } - // retrieve the EGL context that was selected/created - mEGLContext = mRenderEngine->getEGLContext(); - - LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, - "couldn't create EGLContext"); - - // make the GLContext current so that we can create textures when creating - // Layers (which may happens before we render something) - getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext); - mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); @@ -1055,6 +1073,33 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { return NO_ERROR; } +status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + + // Try to acquire a lock for 1s, fail gracefully + const status_t err = mStateLock.timedLock(s2ns(1)); + const bool locked = (err == NO_ERROR); + if (!locked) { + ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err); + return TIMED_OUT; + } + + outLayers->clear(); + mCurrentState.traverseInZOrder([&](Layer* layer) { + outLayers->push_back(layer->getLayerDebugInfo()); + }); + + mStateLock.unlock(); + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( @@ -1165,11 +1210,16 @@ void SurfaceFlinger::resyncWithRateLimit() { sLastResyncAttempted = now; } -void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type, - nsecs_t timestamp) { +void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, + hwc2_display_t displayId, int64_t timestamp) { Mutex::Autolock lock(mStateLock); - // Ignore any vsyncs from the non-active hardware composer. - if (composer != mHwc) { + // Ignore any vsyncs from a previous hardware composer. + if (sequenceId != mComposerSequenceId) { + return; + } + + int32_t type; + if (!mHwc->onVsync(displayId, timestamp, &type)) { return; } @@ -1177,7 +1227,7 @@ void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type, { // Scope for the lock Mutex::Autolock _l(mHWVsyncLock); - if (type == 0 && mPrimaryHWVsyncEnabled) { + if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) { needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); } } @@ -1195,7 +1245,7 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { } void SurfaceFlinger::createDefaultDisplayDevice() { - const int32_t type = DisplayDevice::DISPLAY_PRIMARY; + const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY; wp<IBinder> token = mBuiltinDisplays[type]; // All non-virtual displays are currently considered secure. @@ -1224,30 +1274,55 @@ void SurfaceFlinger::createDefaultDisplayDevice() { token, fbs, producer, mRenderEngine->getEGLConfig(), hasWideColorModes && hasWideColorDisplay); mDisplays.add(token, hw); - setActiveColorModeInternal(hw, HAL_COLOR_MODE_NATIVE); + android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE; + if (hasWideColorModes && hasWideColorDisplay) { + defaultColorMode = HAL_COLOR_MODE_SRGB; + } + setActiveColorModeInternal(hw, defaultColorMode); hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN); -} -void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) { - ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false"); + // Add the primary display token to mDrawingState so we don't try to + // recreate the DisplayDevice for the primary display. + mDrawingState.displays.add(token, DisplayDeviceState(type, true)); - if (composer->isUsingVrComposer()) { - // We handle initializing the primary display device for the VR - // window manager hwc explicitly at the time of transition. - if (disp != DisplayDevice::DISPLAY_PRIMARY) { - ALOGE("External displays are not supported by the vr hardware composer."); - } - return; - } + // make the GLContext current so that we can create textures when creating + // Layers (which may happens before we render something) + hw->makeCurrent(mEGLDisplay, mEGLContext); +} - if (disp == DisplayDevice::DISPLAY_PRIMARY) { - Mutex::Autolock lock(mStateLock); - createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); +void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, + hwc2_display_t display, HWC2::Connection connection, + bool primaryDisplay) { + ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)", + sequenceId, display, + connection == HWC2::Connection::Connected ? + "connected" : "disconnected", + primaryDisplay ? "primary" : "external"); + + // Only lock if we're not on the main thread. This function is normally + // called on a hwbinder thread, but for the primary display it's called on + // the main thread with the state lock already held, so don't attempt to + // acquire it here. + ConditionalLock lock(mStateLock, + std::this_thread::get_id() != mMainThreadId); + + if (primaryDisplay) { + mHwc->onHotplug(display, connection); + if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) { + createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); + } createDefaultDisplayDevice(); } else { + if (sequenceId != mComposerSequenceId) { + return; + } + if (mHwc->isUsingVrComposer()) { + ALOGE("External displays are not supported by the vr hardware composer."); + return; + } + mHwc->onHotplug(display, connection); auto type = DisplayDevice::DISPLAY_EXTERNAL; - Mutex::Autolock _l(mStateLock); - if (connected) { + if (connection == HWC2::Connection::Connected) { createBuiltinDisplayLocked(type); } else { mCurrentState.displays.removeItem(mBuiltinDisplays[type]); @@ -1259,46 +1334,31 @@ void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool } } -void SurfaceFlinger::onInvalidateReceived(HWComposer* composer) { +void SurfaceFlinger::onRefreshReceived(int sequenceId, + hwc2_display_t /*display*/) { Mutex::Autolock lock(mStateLock); - if (composer == mHwc) { - repaintEverything(); - } else { - // This isn't from our current hardware composer. If it's a callback - // from the real composer, forward the refresh request to vr - // flinger. Otherwise ignore it. - if (!composer->isUsingVrComposer()) { - mVrFlinger->OnHardwareComposerRefresh(); - } + if (sequenceId != mComposerSequenceId) { + return; } + repaintEverything(); } void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) { ATRACE_CALL(); + Mutex::Autolock lock(mStateLock); getHwComposer().setVsyncEnabled(disp, enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); } // Note: it is assumed the caller holds |mStateLock| when this is called -void SurfaceFlinger::resetHwcLocked() { +void SurfaceFlinger::resetDisplayState() { disableHardwareVsync(true); - clearHwcLayers(mDrawingState.layersSortedByZ); - clearHwcLayers(mCurrentState.layersSortedByZ); - for (size_t disp = 0; disp < mDisplays.size(); ++disp) { - clearHwcLayers(mDisplays[disp]->getVisibleLayersSortedByZ()); - } // Clear the drawing state so that the logic inside of // handleTransactionLocked will fire. It will determine the delta between // mCurrentState and mDrawingState and re-apply all changes when we make the // transition. mDrawingState.displays.clear(); - // Release virtual display hwcId during vr mode transition. - for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { - const sp<DisplayDevice>& displayDevice = mDisplays[displayId]; - if (displayDevice->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL) { - displayDevice->disconnect(getHwComposer()); - } - } + eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); mDisplays.clear(); } @@ -1310,57 +1370,54 @@ void SurfaceFlinger::updateVrFlinger() { return; } - if (vrFlingerRequestsDisplay && !mVrHwc) { - // Construct new HWComposer without holding any locks. - mVrHwc = new HWComposer(true); - - // Set up the event handlers. This step is neccessary to initialize the internal state of - // the hardware composer object properly. Our callbacks are designed such that if they are - // triggered between now and the point where the display is properly re-initialized, they - // will not have any effect, so this is safe to do here, before the lock is aquired. - mVrHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this)); - ALOGV("Vr HWC created"); + if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) { + ALOGE("Vr flinger is only supported for remote hardware composer" + " service connections. Ignoring request to transition to vr" + " flinger."); + mVrFlingerRequestsDisplay = false; + return; } Mutex::Autolock _l(mStateLock); - if (vrFlingerRequestsDisplay) { - resetHwcLocked(); - - mHwc = mVrHwc; - mVrFlinger->GrantDisplayOwnership(); + int currentDisplayPowerMode = getDisplayDeviceLocked( + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode(); - } else { + if (!vrFlingerRequestsDisplay) { mVrFlinger->SeizeDisplayOwnership(); + } - resetHwcLocked(); + resetDisplayState(); + mHwc.reset(); // Delete the current instance before creating the new one + mHwc.reset(new HWComposer( + vrFlingerRequestsDisplay ? "vr" : mHwcServiceName)); + mHwc->registerCallback(this, ++mComposerSequenceId); - mHwc = mRealHwc; + LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(), + "Switched to non-remote hardware composer"); + + if (vrFlingerRequestsDisplay) { + mVrFlinger->GrantDisplayOwnership(); + } else { enableHardwareVsync(); } mVisibleRegionsDirty = true; invalidateHwcGeometry(); - // Explicitly re-initialize the primary display. This is because some other - // parts of this class rely on the primary display always being available. - createDefaultDisplayDevice(); - // Re-enable default display. - sp<LambdaMessage> requestMessage = new LambdaMessage([&]() { - sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); - setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL); - - // Reset the timing values to account for the period of the swapped in HWC - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); - const nsecs_t period = activeConfig->getVsyncPeriod(); - mAnimFrameTracker.setDisplayRefreshPeriod(period); - - // Use phase of 0 since phase is not known. - // Use latency of 0, which will snap to the ideal latency. - setCompositorTimingSnapped(0, period, 0); - }); - postMessageAsync(requestMessage); + sp<DisplayDevice> hw(getDisplayDeviceLocked( + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); + setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true); + + // Reset the timing values to account for the period of the swapped in HWC + const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const nsecs_t period = activeConfig->getVsyncPeriod(); + mAnimFrameTracker.setDisplayRefreshPeriod(period); + + // Use phase of 0 since phase is not known. + // Use latency of 0, which will snap to the ideal latency. + setCompositorTimingSnapped(0, period, 0); android_atomic_or(1, &mRepaintEverything); setTransactionFlags(eDisplayTransactionNeeded); @@ -1696,15 +1753,14 @@ void SurfaceFlinger::rebuildLayerStacks() { } else { // Clear out the HWC layer if this layer was // previously visible, but no longer is - layer->setHwcLayer(displayDevice->getHwcDisplayId(), - nullptr); + layer->destroyHwcLayer( + displayDevice->getHwcDisplayId()); } } else { // WM changes displayDevice->layerStack upon sleep/awake. // Here we make sure we delete the HWC layers even if // WM changed their layer stack. - layer->setHwcLayer(displayDevice->getHwcDisplayId(), - nullptr); + layer->destroyHwcLayer(displayDevice->getHwcDisplayId()); } }); } @@ -1819,10 +1875,7 @@ void SurfaceFlinger::setUpHWComposer() { for (size_t i = 0; i < currentLayers.size(); i++) { const auto& layer = currentLayers[i]; if (!layer->hasHwcLayer(hwcId)) { - auto hwcLayer = mHwc->createLayer(hwcId); - if (hwcLayer) { - layer->setHwcLayer(hwcId, std::move(hwcLayer)); - } else { + if (!layer->createHwcLayer(mHwc.get(), hwcId)) { layer->forceClientComposition(hwcId); continue; } @@ -1869,12 +1922,7 @@ void SurfaceFlinger::setUpHWComposer() { } newColorMode = pickColorMode(newDataSpace); - // We want the color mode of the boot animation to match that of the bootloader - // To achieve this we suppress color mode changes until after the boot animation - if (mBootFinished) { - setActiveColorModeInternal(displayDevice, newColorMode); - displayDevice->setCompositionDataSpace(newDataSpace); - } + setActiveColorModeInternal(displayDevice, newColorMode); } } @@ -2108,7 +2156,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (state.surface != NULL) { // Allow VR composer to use virtual displays. - if (mUseHwcVirtualDisplays || mHwc == mVrHwc) { + if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) { int width = 0; int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); @@ -2785,6 +2833,7 @@ status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) return NO_ERROR; } + layer->onRemovedFromCurrentState(); mLayersPendingRemoval.add(layer); mLayersRemoved = true; mNumLayers -= 1 + layer->getChildrenCount(); @@ -2860,10 +2909,12 @@ void SurfaceFlinger::setTransactionState( } } - // If a synchronous transaction is explicitly requested without any changes, - // force a transaction anyway. This can be used as a flush mechanism for - // previous async transactions. - if (transactionFlags == 0 && (flags & eSynchronous)) { + // If a synchronous transaction is explicitly requested without any changes, force a transaction + // anyway. This can be used as a flush mechanism for previous async transactions. + // Empty animation transaction can be used to simulate back-pressure, so also force a + // transaction for empty animation transactions. + if (transactionFlags == 0 && + ((flags & eSynchronous) || (flags & eAnimation))) { transactionFlags = eTransactionNeeded; } @@ -3232,7 +3283,8 @@ void SurfaceFlinger::onInitializeDisplays() { d.height = 0; displays.add(d); setTransactionState(state, displays, 0); - setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL); + setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL, + /*stateLockHeld*/ false); const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); @@ -3258,7 +3310,7 @@ void SurfaceFlinger::initializeDisplays() { } void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, - int mode) { + int mode, bool stateLockHeld) { ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), this); int32_t type = hw->getDisplayType(); @@ -3275,7 +3327,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, } if (mInterceptor.isEnabled()) { - Mutex::Autolock _l(mStateLock); + ConditionalLock lock(mStateLock, !stateLockHeld); ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken()); if (idx < 0) { ALOGW("Surface Interceptor SavePowerMode: invalid display token"); @@ -3361,7 +3413,8 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) { ALOGW("Attempt to set power mode = %d for virtual display", mMode); } else { - mFlinger.setPowerModeInternal(hw, mMode); + mFlinger.setPowerModeInternal( + hw, mMode, /*stateLockHeld*/ false); } return true; } @@ -3706,7 +3759,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, result.appendFormat("Visible layers (count = %zu)\n", mNumLayers); colorizer.reset(result); mCurrentState.traverseInZOrder([&](Layer* layer) { - layer->dump(result, colorizer); + result.append(to_string(layer->getLayerDebugInfo()).c_str()); }); /* @@ -4394,7 +4447,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& bool secureLayerIsVisible = false; for (const auto& layer : mDrawingState.layersSortedByZ) { const Layer::State& state(layer->getDrawingState()); - if (layer->belongsToDisplay(hw->getLayerStack(), false) || + if (!layer->belongsToDisplay(hw->getLayerStack(), false) || (state.z < minLayerZ || state.z > maxLayerZ)) { continue; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index acfad46526..058f4a1d3b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -60,13 +60,20 @@ #include "SurfaceInterceptor.h" #include "StartPropertySetThread.h" +#ifdef USE_HWC2 +#include "DisplayHardware/HWC2.h" #include "DisplayHardware/HWComposer.h" +#else +#include "DisplayHardware/HWComposer_hwc1.h" +#endif + #include "Effects/Daltonizer.h" #include <map> #include <mutex> #include <queue> #include <string> +#include <thread> #include <utility> namespace android { @@ -99,7 +106,11 @@ enum { class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, +#ifdef USE_HWC2 + private HWC2::ComposerCallback +#else private HWComposer::EventHandler +#endif { public: @@ -300,6 +311,7 @@ private: HdrCapabilities* outCapabilities) const; virtual status_t enableVSyncInjections(bool enable); virtual status_t injectVSync(nsecs_t when); + virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const; /* ------------------------------------------------------------------------ @@ -313,11 +325,20 @@ private: virtual void onFirstRef(); /* ------------------------------------------------------------------------ - * HWComposer::EventHandler interface + * HWC2::ComposerCallback / HWComposer::EventHandler interface */ - virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp); - virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected); - virtual void onInvalidateReceived(HWComposer* composer); +#ifdef USE_HWC2 + void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, + int64_t timestamp) override; + void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, + HWC2::Connection connection, + bool primaryDisplay) override; + void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override; +#else + void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp) override; + void onHotplugReceived(HWComposer* composer, int disp, bool connected) override; + void onInvalidateReceived(HWComposer* composer) override; +#endif /* ------------------------------------------------------------------------ * Message handling @@ -332,7 +353,12 @@ private: // called on the main thread in response to setActiveConfig() void setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode); // called on the main thread in response to setPowerMode() +#ifdef USE_HWC2 + void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode, + bool stateLockHeld); +#else void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode); +#endif // Called on the main thread in response to setActiveColorMode() void setActiveColorModeInternal(const sp<DisplayDevice>& hw, android_color_mode_t colorMode); @@ -590,13 +616,7 @@ private: /* ------------------------------------------------------------------------ * VrFlinger */ - template<typename T> - void clearHwcLayers(const T& layers) { - for (size_t i = 0; i < layers.size(); ++i) { - layers[i]->clearHwcLayers(); - } - } - void resetHwcLocked(); + void resetDisplayState(); // Check to see if we should handoff to vr flinger. void updateVrFlinger(); @@ -623,12 +643,14 @@ private: // access must be protected by mInvalidateLock volatile int32_t mRepaintEverything; - // current, real and vr hardware composers. - HWComposer* mHwc; + // The current hardware composer interface. When switching into and out of + // vr, our HWComposer instance will be recreated. + std::unique_ptr<HWComposer> mHwc; + #ifdef USE_HWC2 - HWComposer* mRealHwc; - HWComposer* mVrHwc; + const std::string mHwcServiceName; // "default" for real use, something else for testing. #endif + // constant members (no synchronization needed for access) RenderEngine* mRenderEngine; nsecs_t mBootTime; @@ -642,10 +664,6 @@ private: EGLDisplay mEGLDisplay; sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES]; -#ifdef USE_HWC2 - std::unique_ptr<dvr::VrFlinger> mVrFlinger; -#endif - // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState{LayerVector::StateSet::Drawing}; @@ -767,8 +785,14 @@ private: status_t CheckTransactCodeCredentials(uint32_t code); #ifdef USE_HWC2 + std::unique_ptr<dvr::VrFlinger> mVrFlinger; std::atomic<bool> mVrFlingerRequestsDisplay; static bool useVrFlinger; + std::thread::id mMainThreadId; + // The composer sequence id is a monotonically increasing integer that we + // use to differentiate callbacks from different hardware composer + // instances. Each hardware composer instance gets a different sequence id. + int32_t mComposerSequenceId; #endif float mSaturation = 1.0f; diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index dae03b3c25..a92e1f9f89 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -41,6 +41,7 @@ #include <gui/BufferQueue.h> #include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> +#include <gui/LayerDebugInfo.h> #include <gui/Surface.h> #include <ui/GraphicBufferAllocator.h> @@ -94,7 +95,7 @@ */ #define DEBUG_SCREENSHOTS false -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { // --------------------------------------------------------------------------- @@ -534,8 +535,8 @@ void SurfaceFlinger::init() { // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. - mHwc = new HWComposer(this, - *static_cast<HWComposer::EventHandler *>(this)); + mHwc.reset(new HWComposer(this, + *static_cast<HWComposer::EventHandler *>(this))); // get a RenderEngine for the given display / config (can't fail) mRenderEngine = RenderEngine::create(mEGLDisplay, @@ -931,6 +932,34 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { return NO_ERROR; } +status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + + // Try to acquire a lock for 1s, fail gracefully + status_t err = mStateLock.timedLock(s2ns(1)); + bool locked = (err == NO_ERROR); + if (!locked) { + ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err); + return TIMED_OUT; + } + + outLayers->clear(); + mCurrentState.traverseInZOrder([&](Layer* layer) { + outLayers->push_back(layer->getLayerDebugInfo()); + }); + + mStateLock.unlock(); + + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( @@ -2382,6 +2411,7 @@ status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) return NO_ERROR; } + layer->onRemovedFromCurrentState(); mLayersPendingRemoval.add(layer); mLayersRemoved = true; mNumLayers -= 1 + layer->getChildrenCount(); @@ -3261,7 +3291,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, result.appendFormat("Visible layers (count = %zu)\n", mNumLayers); colorizer.reset(result); mCurrentState.traverseInZOrder([&](Layer* layer) { - layer->dump(result, colorizer); + result.append(to_string(layer->getLayerDebugInfo()).c_str()); }); /* diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp new file mode 100644 index 0000000000..94f3f2561a --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -0,0 +1,35 @@ +cc_test { + name: "sffakehwc_test", + srcs: [ + "FakeComposerClient.cpp", + "FakeComposerService.cpp", + "FakeComposerUtils.cpp", + "SFFakeHwc_test.cpp" + ], + shared_libs: [ + "libcutils", + "libutils", + "libbinder", + "libui", + "libgui", + "liblog", + "libnativewindow", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0", + "libhwbinder", + "libhardware", + "libhidlbase", + "libsync", + "libfmq", + "libbase", + "libhidltransport" + ], + static_libs: [ + "libhwcomposer-client", + "libsurfaceflingerincludes", + "libtrace_proto", + "libgmock" + ], + tags: ["tests"], + test_suites: ["device-tests"] +}
\ No newline at end of file diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp new file mode 100644 index 0000000000..d97ffa3148 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp @@ -0,0 +1,612 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeComposer" + +#include "FakeComposerClient.h" + +#include <gui/SurfaceComposerClient.h> + +#include <log/log.h> + +#include <gtest/gtest.h> + +#include <inttypes.h> +#include <time.h> +#include <algorithm> +#include <condition_variable> +#include <iostream> +#include <mutex> +#include <set> +#include <thread> + +constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0); + +using namespace sftest; + +using android::Condition; +using android::Mutex; + +using Clock = std::chrono::steady_clock; +using TimePoint = std::chrono::time_point<Clock>; + +namespace { + +// Internal state of a layer in the HWC API. +class LayerImpl { +public: + LayerImpl() = default; + + bool mValid = true; + RenderState mRenderState; + uint32_t mZ = 0; +}; + +// Struct for storing per frame rectangle state. Contains the render +// state shared to the test case. Basically a snapshot and a subset of +// LayerImpl sufficient to re-create the pixels of a layer for the +// frame. +struct FrameRect { +public: + FrameRect(Layer layer_, const RenderState& state, uint32_t z_) + : layer(layer_), renderState(state), z(z_) {} + + const Layer layer; + const RenderState renderState; + const uint32_t z; +}; + +// Collection of FrameRects forming one rendered frame. Could store +// related fences and other data in the future. +class Frame { +public: + Frame() = default; + std::vector<std::unique_ptr<FrameRect>> rectangles; +}; + +class DelayedEventGenerator { +public: + DelayedEventGenerator(std::function<void()> onTimerExpired) + : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {} + + ~DelayedEventGenerator() { + ALOGI("DelayedEventGenerator exiting."); + { + std::unique_lock<std::mutex> lock(mMutex); + mRunning = false; + mWakeups.clear(); + mCondition.notify_one(); + } + mThread.join(); + ALOGI("DelayedEventGenerator exited."); + } + + void wakeAfter(std::chrono::nanoseconds waitTime) { + std::unique_lock<std::mutex> lock(mMutex); + mWakeups.insert(Clock::now() + waitTime); + mCondition.notify_one(); + } + +private: + void loop() { + while (true) { + // Lock scope + { + std::unique_lock<std::mutex> lock(mMutex); + mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); }); + if (!mRunning && mWakeups.empty()) { + // This thread should only exit once the destructor has been called and all + // wakeups have been processed + return; + } + + // At this point, mWakeups will not be empty + + TimePoint target = *(mWakeups.begin()); + auto status = mCondition.wait_until(lock, target); + while (status == std::cv_status::no_timeout) { + // This was either a spurious wakeup or another wakeup was added, so grab the + // oldest point and wait again + target = *(mWakeups.begin()); + status = mCondition.wait_until(lock, target); + } + + // status must have been timeout, so we can finally clear this point + mWakeups.erase(target); + } + // Callback *without* locks! + mOnTimerExpired(); + } + } + + std::function<void()> mOnTimerExpired; + std::thread mThread; + std::mutex mMutex; + std::condition_variable mCondition; + bool mRunning = true; + std::set<TimePoint> mWakeups; +}; + +} // namespace + +FakeComposerClient::FakeComposerClient() + : mCallbacksOn(false), + mClient(nullptr), + mCurrentConfig(NULL_DISPLAY_CONFIG), + mVsyncEnabled(false), + mLayers(), + mDelayedEventGenerator( + std::make_unique<DelayedEventGenerator>([this]() { this->requestVSync(); })), + mSurfaceComposer(nullptr) {} + +FakeComposerClient::~FakeComposerClient() {} + +void FakeComposerClient::removeClient() { + ALOGV("removeClient"); + // TODO: Ahooga! Only thing current lifetime management choices in + // APIs make possible. Sad. + delete this; +} + +void FakeComposerClient::enableCallback(bool enable) { + ALOGV("enableCallback"); + mCallbacksOn = enable; + if (mCallbacksOn) { + mClient->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED); + } +} + +void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) { + if (mCallbacksOn) { + mClient->onHotplug(display, state); + } +} + +uint32_t FakeComposerClient::getMaxVirtualDisplayCount() { + ALOGV("getMaxVirtualDisplayCount"); + return 1; +} + +Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/, + PixelFormat* /*format*/, Display* /*outDisplay*/) { + ALOGV("createVirtualDisplay"); + return Error::NONE; +} + +Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) { + ALOGV("destroyVirtualDisplay"); + return Error::NONE; +} + +Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) { + ALOGV("createLayer"); + *outLayer = mLayers.size(); + auto newLayer = std::make_unique<LayerImpl>(); + mLayers.push_back(std::move(newLayer)); + return Error::NONE; +} + +Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) { + ALOGV("destroyLayer"); + mLayers[layer]->mValid = false; + return Error::NONE; +} + +Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) { + ALOGV("getActiveConfig"); + + // TODO Assert outConfig != nullptr + + // TODO This is my reading of the + // IComposerClient::getActiveConfig, but returning BAD_CONFIG + // seems to not fit SurfaceFlinger plans. See version 2 below. + // if (mCurrentConfig == NULL_DISPLAY_CONFIG) { + // return Error::BAD_CONFIG; + // } + //*outConfig = mCurrentConfig; + *outConfig = 1; // Very special config for you my friend + return Error::NONE; +} + +Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/, + uint32_t /*height*/, PixelFormat /*format*/, + Dataspace /*dataspace*/) { + ALOGV("getClientTargetSupport"); + return Error::NONE; +} + +Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec<ColorMode>* /*outModes*/) { + ALOGV("getColorModes"); + return Error::NONE; +} + +Error FakeComposerClient::getDisplayAttribute(Display display, Config config, + IComposerClient::Attribute attribute, + int32_t* outValue) { + ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display), + static_cast<int>(config), static_cast<int>(attribute), outValue); + + // TODO: SOOO much fun to be had with these alone + switch (attribute) { + case IComposerClient::Attribute::WIDTH: + *outValue = 1920; + break; + case IComposerClient::Attribute::HEIGHT: + *outValue = 1080; + break; + case IComposerClient::Attribute::VSYNC_PERIOD: + *outValue = 1666666666; + break; // TOOD: Tests break down if lowered to 16ms? + case IComposerClient::Attribute::DPI_X: + *outValue = 240; + break; + case IComposerClient::Attribute::DPI_Y: + *outValue = 240; + break; + default: + LOG_ALWAYS_FATAL("Say what!?! New attribute"); + } + + return Error::NONE; +} + +Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec<Config>* outConfigs) { + ALOGV("getDisplayConfigs"); + // TODO assert display == 1, outConfigs != nullptr + + outConfigs->resize(1); + (*outConfigs)[0] = 1; + + return Error::NONE; +} + +Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) { + ALOGV("getDisplayName"); + return Error::NONE; +} + +Error FakeComposerClient::getDisplayType(Display /*display*/, + IComposerClient::DisplayType* outType) { + ALOGV("getDisplayType"); + // TODO: This setting nothing on the output had no effect on initial trials. Is first display + // assumed to be physical? + *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL); + return Error::NONE; +} + +Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) { + ALOGV("getDozeSupport"); + return Error::NONE; +} + +Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec<Hdr>* /*outTypes*/, + float* /*outMaxLuminance*/, + float* /*outMaxAverageLuminance*/, + float* /*outMinLuminance*/) { + ALOGV("getHdrCapabilities"); + return Error::NONE; +} + +Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) { + ALOGV("setActiveConfig"); + mCurrentConfig = config; + return Error::NONE; +} + +Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) { + ALOGV("setColorMode"); + return Error::NONE; +} + +Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) { + ALOGV("setPowerMode"); + return Error::NONE; +} + +Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) { + mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE); + ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE"); + return Error::NONE; +} + +Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/, + int32_t /*hint*/) { + ALOGV("setColorTransform"); + return Error::NONE; +} + +Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/, + int32_t /*acquireFence*/, int32_t /*dataspace*/, + const std::vector<hwc_rect_t>& /*damage*/) { + ALOGV("setClientTarget"); + return Error::NONE; +} + +Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/, + int32_t /*releaseFence*/) { + ALOGV("setOutputBuffer"); + return Error::NONE; +} + +Error FakeComposerClient::validateDisplay( + Display /*display*/, std::vector<Layer>* /*outChangedLayers*/, + std::vector<IComposerClient::Composition>* /*outCompositionTypes*/, + uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/, + std::vector<uint32_t>* /*outRequestMasks*/) { + ALOGV("validateDisplay"); + // TODO: Assume touching nothing means All Korrekt! + return Error::NONE; +} + +Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) { + ALOGV("acceptDisplayChanges"); + // Didn't ask for changes because software is omnipotent. + return Error::NONE; +} + +bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) { + return a->z <= b->z; +} + +Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/, + std::vector<Layer>* /*outLayers*/, + std::vector<int32_t>* /*outReleaseFences*/) { + ALOGV("presentDisplay"); + // TODO Leaving layers and their fences out for now. Doing so + // means that we've already processed everything. Important to + // test that the fences are respected, though. (How?) + + std::unique_ptr<Frame> newFrame(new Frame); + for (uint64_t layer = 0; layer < mLayers.size(); layer++) { + const LayerImpl& layerImpl = *mLayers[layer]; + + if (!layerImpl.mValid) continue; + + auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ); + newFrame->rectangles.push_back(std::move(rect)); + } + std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering); + { + Mutex::Autolock _l(mStateMutex); + mFrames.push_back(std::move(newFrame)); + mFramesAvailable.broadcast(); + } + return Error::NONE; +} + +Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/, + int32_t /*x*/, int32_t /*y*/) { + ALOGV("setLayerCursorPosition"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer, + int32_t acquireFence) { + ALOGV("setLayerBuffer"); + LayerImpl& l = getLayerImpl(layer); + if (buffer != l.mRenderState.mBuffer) { + l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not? + } + l.mRenderState.mBuffer = buffer; + l.mRenderState.mAcquireFence = acquireFence; + + return Error::NONE; +} + +Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/, + const std::vector<hwc_rect_t>& /*damage*/) { + ALOGV("setLayerSurfaceDamage"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) { + ALOGV("setLayerBlendMode"); + getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode); + return Error::NONE; +} + +Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer, + IComposerClient::Color color) { + ALOGV("setLayerColor"); + getLayerImpl(layer).mRenderState.mLayerColor.r = color.r; + getLayerImpl(layer).mRenderState.mLayerColor.g = color.g; + getLayerImpl(layer).mRenderState.mLayerColor.b = color.b; + getLayerImpl(layer).mRenderState.mLayerColor.a = color.a; + return Error::NONE; +} + +Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/, + int32_t /*type*/) { + ALOGV("setLayerCompositionType"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/, + int32_t /*dataspace*/) { + ALOGV("setLayerDataspace"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer, + const hwc_rect_t& frame) { + ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right, + frame.bottom); + getLayerImpl(layer).mRenderState.mDisplayFrame = frame; + return Error::NONE; +} + +Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) { + ALOGV("setLayerPlaneAlpha"); + getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha; + return Error::NONE; +} + +Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/, + buffer_handle_t /*stream*/) { + ALOGV("setLayerSidebandStream"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer, + const hwc_frect_t& crop) { + ALOGV("setLayerSourceCrop"); + getLayerImpl(layer).mRenderState.mSourceCrop = crop; + return Error::NONE; +} + +Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) { + ALOGV("setLayerTransform"); + getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform); + return Error::NONE; +} + +Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer, + const std::vector<hwc_rect_t>& visible) { + ALOGV("setLayerVisibleRegion"); + getLayerImpl(layer).mRenderState.mVisibleRegion = visible; + return Error::NONE; +} + +Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) { + ALOGV("setLayerZOrder"); + getLayerImpl(layer).mZ = z; + return Error::NONE; +} + +////////////////////////////////////////////////////////////////// + +void FakeComposerClient::setClient(ComposerClient* client) { + mClient = client; +} + +void FakeComposerClient::requestVSync(uint64_t vsyncTime) { + if (mCallbacksOn) { + uint64_t timestamp = vsyncTime; + ALOGV("Vsync"); + if (timestamp == 0) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; + } + if (mSurfaceComposer != nullptr) { + mSurfaceComposer->injectVSync(timestamp); + } else { + mClient->onVsync(PRIMARY_DISPLAY, timestamp); + } + } +} + +void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) { + mDelayedEventGenerator->wakeAfter(wait); +} + +LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) { + // TODO Change these to an internal state check that can be + // invoked from the gtest? GTest macros do not seem all that safe + // when used outside the test class + EXPECT_GE(handle, static_cast<Layer>(0)); + EXPECT_LT(handle, mLayers.size()); + return *(mLayers[handle]); +} + +int FakeComposerClient::getFrameCount() const { + return mFrames.size(); +} + +static std::vector<RenderState> extractRenderState( + const std::vector<std::unique_ptr<FrameRect>>& internalRects) { + std::vector<RenderState> result; + result.reserve(internalRects.size()); + for (const std::unique_ptr<FrameRect>& rect : internalRects) { + result.push_back(rect->renderState); + } + return result; +} + +std::vector<RenderState> FakeComposerClient::getFrameRects(int frame) const { + Mutex::Autolock _l(mStateMutex); + return extractRenderState(mFrames[frame]->rectangles); +} + +std::vector<RenderState> FakeComposerClient::getLatestFrame() const { + Mutex::Autolock _l(mStateMutex); + return extractRenderState(mFrames[mFrames.size() - 1]->rectangles); +} + +void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) { + int currentFrame = 0; + { + Mutex::Autolock _l(mStateMutex); // I hope this is ok... + currentFrame = static_cast<int>(mFrames.size()); + requestVSync(); + } + waitUntilFrame(currentFrame + 1, maxWait); +} + +void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const { + Mutex::Autolock _l(mStateMutex); + while (mFrames.size() < static_cast<size_t>(targetFrame)) { + android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count()); + if (result == android::TIMED_OUT) { + ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame, + mFrames.size(), maxWait.count()); + return; + } + } +} + +void FakeComposerClient::clearFrames() { + Mutex::Autolock _l(mStateMutex); + mFrames.clear(); + for (const std::unique_ptr<LayerImpl>& layer : mLayers) { + if (layer->mValid) { + layer->mRenderState.mSwapCount = 0; + } + } +} + +void FakeComposerClient::onSurfaceFlingerStart() { + mSurfaceComposer == nullptr; + do { + mSurfaceComposer = new android::SurfaceComposerClient; + android::status_t initResult = mSurfaceComposer->initCheck(); + if (initResult != android::NO_ERROR) { + ALOGD("Init result: %d", initResult); + mSurfaceComposer = nullptr; + std::this_thread::sleep_for(10ms); + } + } while (mSurfaceComposer == nullptr); + ALOGD("SurfaceComposerClient created"); + mSurfaceComposer->enableVSyncInjections(true); +} + +void FakeComposerClient::onSurfaceFlingerStop() { + mSurfaceComposer->dispose(); + mSurfaceComposer.clear(); +} + +// Includes destroyed layers, stored in order of creation. +int FakeComposerClient::getLayerCount() const { + return mLayers.size(); +} + +Layer FakeComposerClient::getLayer(size_t index) const { + // NOTE: If/when passing calls through to actual implementation, + // this might get more involving. + return static_cast<Layer>(index); +} diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h new file mode 100644 index 0000000000..2a5a8ad03f --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h @@ -0,0 +1,156 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ComposerClient.h" +#include "RenderState.h" + +// Needed for display type/ID enums +#include <hardware/hwcomposer_defs.h> + +#include <utils/Condition.h> + +#include <chrono> + +using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_1::implementation; +using namespace android::hardware; +using namespace std::chrono_literals; + +namespace { +class LayerImpl; +class Frame; +class DelayedEventGenerator; +} // namespace + +namespace android { +class SurfaceComposerClient; +} // namespace android + +namespace sftest { + +// NOTE: The ID's need to be exactly these. VR composer and parts of +// the SurfaceFlinger assume the display IDs to have these values +// despite the enum being documented as a display type. +// TODO: Reference to actual documentation +constexpr Display PRIMARY_DISPLAY = static_cast<Display>(HWC_DISPLAY_PRIMARY); +constexpr Display EXTERNAL_DISPLAY = static_cast<Display>(HWC_DISPLAY_EXTERNAL); + +class FakeComposerClient : public ComposerBase { +public: + FakeComposerClient(); + virtual ~FakeComposerClient(); + + void removeClient() override; + void enableCallback(bool enable) override; + uint32_t getMaxVirtualDisplayCount() override; + Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, + Display* outDisplay) override; + Error destroyVirtualDisplay(Display display) override; + Error createLayer(Display display, Layer* outLayer) override; + Error destroyLayer(Display display, Layer layer) override; + + Error getActiveConfig(Display display, Config* outConfig) override; + Error getClientTargetSupport(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) override; + Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override; + Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, + int32_t* outValue) override; + Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override; + Error getDisplayName(Display display, hidl_string* outName) override; + Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override; + Error getDozeSupport(Display display, bool* outSupport) override; + Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance, + float* outMaxAverageLuminance, float* outMinLuminance) override; + + Error setActiveConfig(Display display, Config config) override; + Error setColorMode(Display display, ColorMode mode) override; + Error setPowerMode(Display display, IComposerClient::PowerMode mode) override; + Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override; + + Error setColorTransform(Display display, const float* matrix, int32_t hint) override; + Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence, + int32_t dataspace, const std::vector<hwc_rect_t>& damage) override; + Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override; + Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers, + std::vector<IComposerClient::Composition>* outCompositionTypes, + uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers, + std::vector<uint32_t>* outRequestMasks) override; + Error acceptDisplayChanges(Display display) override; + Error presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers, + std::vector<int32_t>* outReleaseFences) override; + + Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override; + Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer, + int32_t acquireFence) override; + Error setLayerSurfaceDamage(Display display, Layer layer, + const std::vector<hwc_rect_t>& damage) override; + Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override; + Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override; + Error setLayerCompositionType(Display display, Layer layer, int32_t type) override; + Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override; + Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override; + Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override; + Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override; + Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override; + Error setLayerTransform(Display display, Layer layer, int32_t transform) override; + Error setLayerVisibleRegion(Display display, Layer layer, + const std::vector<hwc_rect_t>& visible) override; + Error setLayerZOrder(Display display, Layer layer, uint32_t z) override; + + void setClient(ComposerClient* client); + + void requestVSync(uint64_t vsyncTime = 0); + // We don't want tests hanging, so always use a timeout. Remember + // to always check the number of frames with test ASSERT_! + // Wait until next frame is rendered after requesting vsync. + void runVSyncAndWait(std::chrono::nanoseconds maxWait = 100ms); + void runVSyncAfter(std::chrono::nanoseconds wait); + + int getFrameCount() const; + // We don't want tests hanging, so always use a timeout. Remember + // to always check the number of frames with test ASSERT_! + void waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait = 100ms) const; + std::vector<RenderState> getFrameRects(int frame) const; + std::vector<RenderState> getLatestFrame() const; + void clearFrames(); + + void onSurfaceFlingerStart(); + void onSurfaceFlingerStop(); + + int getLayerCount() const; + Layer getLayer(size_t index) const; + + void hotplugDisplay(Display display, IComposerCallback::Connection state); + +private: + LayerImpl& getLayerImpl(Layer handle); + + bool mCallbacksOn; + ComposerClient* mClient; + Config mCurrentConfig; + bool mVsyncEnabled; + std::vector<std::unique_ptr<LayerImpl>> mLayers; + std::vector<std::unique_ptr<Frame>> mFrames; + // Using a pointer to hide the implementation into the CPP file. + std::unique_ptr<DelayedEventGenerator> mDelayedEventGenerator; + android::sp<android::SurfaceComposerClient> mSurfaceComposer; // For VSync injections + mutable android::Mutex mStateMutex; + mutable android::Condition mFramesAvailable; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp new file mode 100644 index 0000000000..c411604587 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcService" +#include <log/log.h> + +#include "FakeComposerService.h" + +using namespace android::hardware; + +namespace sftest { + +FakeComposerService::FakeComposerService(android::sp<ComposerClient>& client) : mClient(client) {} + +FakeComposerService::~FakeComposerService() { + ALOGI("Maybe killing client %p", mClient.get()); + // Rely on sp to kill the client. +} + +Return<void> FakeComposerService::getCapabilities(getCapabilities_cb hidl_cb) { + ALOGI("FakeComposerService::getCapabilities"); + hidl_cb(hidl_vec<Capability>()); + return Void(); +} + +Return<void> FakeComposerService::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) { + ALOGI("FakeComposerService::dumpDebugInfo"); + hidl_cb(hidl_string()); + return Void(); +} + +Return<void> FakeComposerService::createClient(createClient_cb hidl_cb) { + ALOGI("FakeComposerService::createClient %p", mClient.get()); + mClient->initialize(); + hidl_cb(Error::NONE, mClient); + return Void(); +} + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h new file mode 100644 index 0000000000..520408496f --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ComposerClient.h" + +using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_1::implementation; +using android::hardware::Return; + +namespace sftest { + +class FakeComposerService : public IComposer { +public: + FakeComposerService(android::sp<ComposerClient>& client); + virtual ~FakeComposerService(); + + Return<void> getCapabilities(getCapabilities_cb hidl_cb) override; + Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; + Return<void> createClient(createClient_cb hidl_cb) override; + +private: + android::sp<ComposerClient> mClient; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp new file mode 100644 index 0000000000..51956ec970 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp @@ -0,0 +1,183 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcUtil" +#include <log/log.h> + +#include "FakeComposerUtils.h" +#include "RenderState.h" + +#include "SurfaceFlinger.h" // Get the name of the service... + +#include <binder/IServiceManager.h> + +#include <cutils/properties.h> + +#include <iomanip> +#include <thread> + +using android::String16; +using android::sp; +using namespace std::chrono_literals; +using namespace sftest; +using std::setw; + +namespace sftest { + +// clang-format off +inline void printSourceRectAligned(::std::ostream& os, const hwc_frect_t& sourceRect, int align) { + os << std::fixed << std::setprecision(1) << "(" + << setw(align) << sourceRect.left << setw(0) << "," + << setw(align) << sourceRect.top << setw(0) << "," + << setw(align) << sourceRect.right << setw(0) << "," + << setw(align) << sourceRect.bottom << setw(0) << ")"; +} + +inline void printDisplayRectAligned(::std::ostream& os, const hwc_rect_t& displayRect, int align) { + os << "(" + << setw(align) << displayRect.left << setw(0) << "," + << setw(align) << displayRect.top << setw(0) << "," + << setw(align) << displayRect.right << setw(0) << "," + << setw(align) << displayRect.bottom << setw(0) << ")"; +} +// clang-format on + +inline ::std::ostream& operator<<(::std::ostream& os, const sftest::RenderState& state) { + printSourceRectAligned(os, state.mSourceCrop, 7); + os << "->"; + printDisplayRectAligned(os, state.mDisplayFrame, 5); + return os << " Swaps:" << state.mSwapCount << " Alpha:" << std::setprecision(3) + << state.mPlaneAlpha << " Xform:" << state.mTransform; +} + +// Helper for verifying the parts of the RenderState +template <typename T> +bool valuesMatch(::testing::AssertionResult& message, const T& ref, const T& val, + const char* name) { + if (ref != val) { + message = message << "Expected " << name << ":" << ref << ", got:" << val << "."; + return false; + } + return true; +} + +::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val) { + // TODO: Message could start as success and be assigned as failure. + // Only problem is that utility assumes it to be failure and just adds stuff. Would + // need still special case the initial failure in the utility? + // TODO: ... or would it be possible to break this back to gtest primitives? + ::testing::AssertionResult message = ::testing::AssertionFailure(); + bool passes = true; + + // The work here is mostly about providing good log strings for differences + passes &= valuesMatch(message, ref.mDisplayFrame, val.mDisplayFrame, "display frame"); + passes &= valuesMatch(message, ref.mPlaneAlpha, val.mPlaneAlpha, "alpha"); + passes &= valuesMatch(message, ref.mSwapCount, val.mSwapCount, "swap count"); + passes &= valuesMatch(message, ref.mSourceCrop, val.mSourceCrop, "source crop"); + // ... add more + if (passes) { + return ::testing::AssertionSuccess(); + } + return message; +} + +::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref, + const std::vector<RenderState>& val) { + ::testing::AssertionResult message = ::testing::AssertionFailure(); + bool passed = true; + if (ref.size() != val.size()) { + message << "Expected " << ref.size() << " rects, got " << val.size() << "."; + passed = false; + } + for (size_t rectIndex = 0; rectIndex < std::min(ref.size(), val.size()); rectIndex++) { + ::testing::AssertionResult rectResult = rectsAreSame(ref[rectIndex], val[rectIndex]); + if (rectResult == false) { + message << "First different rect at " << rectIndex << ": " << rectResult.message(); + passed = false; + break; + } + } + + if (passed) { + return ::testing::AssertionSuccess(); + } else { + message << "\nReference:"; + for (auto state = ref.begin(); state != ref.end(); ++state) { + message << "\n" << *state; + } + message << "\nActual:"; + for (auto state = val.begin(); state != val.end(); ++state) { + message << "\n" << *state; + } + } + return message; +} + +void startSurfaceFlinger() { + ALOGI("Start SurfaceFlinger"); + system("start surfaceflinger"); + + sp<android::IServiceManager> sm(android::defaultServiceManager()); + sp<android::IBinder> sf; + while (sf == nullptr) { + std::this_thread::sleep_for(10ms); + sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName())); + } + ALOGV("SurfaceFlinger running"); +} + +void stopSurfaceFlinger() { + ALOGI("Stop SurfaceFlinger"); + system("stop surfaceflinger"); + sp<android::IServiceManager> sm(android::defaultServiceManager()); + sp<android::IBinder> sf; + while (sf != nullptr) { + std::this_thread::sleep_for(10ms); + sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName())); + } + ALOGV("SurfaceFlinger stopped"); +} + +//////////////////////////////////////////////// + +void FakeHwcEnvironment::SetUp() { + ALOGI("Test env setup"); + system("setenforce 0"); + system("stop"); + property_set("debug.sf.nobootanimation", "1"); + { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.nobootanimation", value, "0"); + LOG_FATAL_IF(atoi(value) != 1, "boot skip not set"); + } + // TODO: Try registering the mock as the default service instead. + property_set("debug.sf.hwc_service_name", "mock"); + // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files. + property_set("debug.sf.treble_testing_override", "true"); +} + +void FakeHwcEnvironment::TearDown() { + ALOGI("Test env tear down"); + system("stop"); + // Wait for mock call signaling teardown? + property_set("debug.sf.nobootanimation", "0"); + property_set("debug.sf.hwc_service_name", "default"); + ALOGI("Test env tear down - done"); +} + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h new file mode 100644 index 0000000000..74dc0e51bb --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h @@ -0,0 +1,119 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "FakeComposerClient.h" + +#include <gui/SurfaceComposerClient.h> + +#include <hardware/hwcomposer_defs.h> + +#include <log/log.h> + +#include <gtest/gtest.h> + +// clang-format off +// Note: This needs to reside in the global namespace for the GTest to use it +inline ::std::ostream& operator<<(::std::ostream& os, const hwc_rect_t& rect) { + return os << "(" << rect.left << "," + << rect.top << "," + << rect.right << "," + << rect.bottom << ")"; +} + +inline ::std::ostream& operator<<(::std::ostream& os, const hwc_frect_t& rect) { + return os << "(" << rect.left << "," + << rect.top << "," + << rect.right << "," + << rect.bottom << ")"; +} +// clang-format on + +namespace sftest { + +class RenderState; + +// clang-format off +inline bool operator==(const hwc_rect_t& a, const hwc_rect_t& b) { + return a.top == b.top && + a.left == b.left && + a.bottom == b.bottom && + a.right == b.right; +} + +inline bool operator==(const hwc_frect_t& a, const hwc_frect_t& b) { + return a.top == b.top && + a.left == b.left && + a.bottom == b.bottom && + a.right == b.right; +} +// clang-format on + +inline bool operator!=(const hwc_rect_t& a, const hwc_rect_t& b) { + return !(a == b); +} + +inline bool operator!=(const hwc_frect_t& a, const hwc_frect_t& b) { + return !(a == b); +} + +::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val); +::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref, + const std::vector<RenderState>& val); + +void startSurfaceFlinger(); +void stopSurfaceFlinger(); + +class FakeHwcEnvironment : public ::testing::Environment { +public: + virtual ~FakeHwcEnvironment() {} + void SetUp() override; + void TearDown() override; +}; + +/* + * All surface state changes are supposed to happen inside a global + * transaction. GlobalTransactionScope object at the beginning of + * scope automates the process. The resulting scope gives a visual cue + * on the span of the transaction as well. + * + * Closing the transaction is synchronous, i.e., it waits for + * SurfaceFlinger to composite one frame. Now, the FakeComposerClient + * is built to explicitly request vsyncs one at the time. A delayed + * request must be made before closing the transaction or the test + * thread stalls until SurfaceFlinger does an emergency vsync by + * itself. GlobalTransactionScope encapsulates this vsync magic. + */ +class GlobalTransactionScope { +public: + GlobalTransactionScope(FakeComposerClient& composer) : mComposer(composer) { + android::SurfaceComposerClient::openGlobalTransaction(); + } + ~GlobalTransactionScope() { + int frameCount = mComposer.getFrameCount(); + mComposer.runVSyncAfter(1ms); + android::SurfaceComposerClient::closeGlobalTransaction(true); + // Make sure that exactly one frame has been rendered. + mComposer.waitUntilFrame(frameCount + 1); + LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(), + "Unexpected frame advance. Delta: %d", + mComposer.getFrameCount() - frameCount); + } + FakeComposerClient& mComposer; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h new file mode 100644 index 0000000000..0059289d4f --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/RenderState.h @@ -0,0 +1,44 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <hardware/hwcomposer2.h> + +#include <vector> + +namespace sftest { +// Description of a rendered rectangle. Should only contain +// instructions necessary to rasterize the rectangle. The full scene +// is given as a sorted list of rectangles, bottom layer at index 0. +class RenderState { +public: + RenderState() = default; + // Default copy-ctor + + hwc_rect_t mDisplayFrame = {0, 0, 0, 0}; + hwc_frect_t mSourceCrop = {0.f, 0.f, 0.f, 0.f}; + std::vector<hwc_rect_t> mVisibleRegion; + hwc2_blend_mode_t mBlendMode = HWC2_BLEND_MODE_NONE; + buffer_handle_t mBuffer = 0; + uint32_t mSwapCount = 0; // How many set buffer calls to the layer. + int32_t mAcquireFence = 0; // Probably should not be here. + float mPlaneAlpha = 0.f; + hwc_color_t mLayerColor = {0, 0, 0, 0}; + hwc_transform_t mTransform = static_cast<hwc_transform_t>(0); +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp new file mode 100644 index 0000000000..9ac3331892 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -0,0 +1,1302 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcTest" + +#include "FakeComposerClient.h" +#include "FakeComposerService.h" +#include "FakeComposerUtils.h" + +#include <gui/ISurfaceComposer.h> +#include <gui/LayerDebugInfo.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> + +#include <private/gui/ComposerService.h> +#include <private/gui/LayerState.h> + +#include <ui/DisplayInfo.h> + +#include <android/native_window.h> + +#include <android/hidl/manager/1.0/IServiceManager.h> + +#include <hwbinder/ProcessState.h> + +#include <binder/ProcessState.h> + +#include <log/log.h> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <limits> + +using namespace std::chrono_literals; + +using namespace android; +using namespace android::hardware; + +using namespace sftest; + +namespace { + +// Mock test helpers +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::_; + +/////////////////////////////////////////////// + +struct TestColor { +public: + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +constexpr static TestColor RED = {195, 63, 63, 255}; +constexpr static TestColor LIGHT_RED = {255, 177, 177, 255}; +constexpr static TestColor GREEN = {63, 195, 63, 255}; +constexpr static TestColor BLUE = {63, 63, 195, 255}; +constexpr static TestColor DARK_GRAY = {63, 63, 63, 255}; +constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255}; + +// Fill an RGBA_8888 formatted surface with a single color. +static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const TestColor& color, + bool unlock = true) { + ANativeWindow_Buffer outBuffer; + sp<Surface> s = sc->getSurface(); + ASSERT_TRUE(s != nullptr); + ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr)); + uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits); + for (int y = 0; y < outBuffer.height; y++) { + for (int x = 0; x < outBuffer.width; x++) { + uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); + pixel[0] = color.r; + pixel[1] = color.g; + pixel[2] = color.b; + pixel[3] = color.a; + } + } + if (unlock) { + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); + } +} + +inline RenderState makeSimpleRect(int left, int top, int right, int bottom) { + RenderState res; + res.mDisplayFrame = hwc_rect_t{left, top, right, bottom}; + res.mPlaneAlpha = 1.0f; + res.mSwapCount = 0; + res.mSourceCrop = hwc_frect_t{0.f, 0.f, static_cast<float>(right - left), + static_cast<float>(bottom - top)}; + return res; +} + +inline RenderState makeSimpleRect(unsigned int left, unsigned int top, unsigned int right, + unsigned int bottom) { + EXPECT_LE(left, static_cast<unsigned int>(INT_MAX)); + EXPECT_LE(top, static_cast<unsigned int>(INT_MAX)); + EXPECT_LE(right, static_cast<unsigned int>(INT_MAX)); + EXPECT_LE(bottom, static_cast<unsigned int>(INT_MAX)); + return makeSimpleRect(static_cast<int>(left), static_cast<int>(top), static_cast<int>(right), + static_cast<int>(bottom)); +} + +//////////////////////////////////////////////// + +class DisplayTest : public ::testing::Test { +public: + class MockComposerClient : public FakeComposerClient { + public: + MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType)); + MOCK_METHOD4(getDisplayAttribute, + Error(Display display, Config config, IComposerClient::Attribute attribute, + int32_t* outValue)); + + // Re-routing to basic fake implementation + Error getDisplayAttributeFake(Display display, Config config, + IComposerClient::Attribute attribute, int32_t* outValue) { + return FakeComposerClient::getDisplayAttribute(display, config, attribute, outValue); + } + }; + +protected: + void SetUp() override; + void TearDown() override; + + sp<IComposer> mFakeService; + sp<SurfaceComposerClient> mComposerClient; + + MockComposerClient* mMockComposer; +}; + +void DisplayTest::SetUp() { + // TODO: The mMockComposer should be a unique_ptr, but it needs to + // outlive the test class. Currently ComposerClient only dies + // when the service is replaced. The Mock deletes itself when + // removeClient is called on it, which is ugly. This can be + // changed if HIDL ServiceManager allows removing services or + // ComposerClient starts taking the ownership of the contained + // implementation class. Moving the fake class to the HWC2 + // interface instead of the current Composer interface might also + // change the situation. + mMockComposer = new MockComposerClient; + sp<ComposerClient> client = new ComposerClient(*mMockComposer); + mMockComposer->setClient(client.get()); + mFakeService = new FakeComposerService(client); + mFakeService->registerAsService("mock"); + + android::hardware::ProcessState::self()->startThreadPool(); + android::ProcessState::self()->startThreadPool(); + + EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _)) + .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), + Return(Error::NONE))); + // Primary display will be queried twice for all 5 attributes. One + // set of queries comes from the SurfaceFlinger proper an the + // other set from the VR composer. + // TODO: Is VR composer always present? Change to atLeast(5)? + EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _)) + .Times(2 * 5) + .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); + + startSurfaceFlinger(); + + // Fake composer wants to enable VSync injection + mMockComposer->onSurfaceFlingerStart(); + + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); +} + +void DisplayTest::TearDown() { + mComposerClient->dispose(); + mComposerClient = nullptr; + + // Fake composer needs to release SurfaceComposerClient before the stop. + mMockComposer->onSurfaceFlingerStop(); + stopSurfaceFlinger(); + + mFakeService = nullptr; + // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime + // management. + mMockComposer = nullptr; +} + +TEST_F(DisplayTest, Hotplug) { + ALOGD("DisplayTest::Hotplug"); + + EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), + Return(Error::NONE))); + // The attribute queries will get done twice. This is for defaults + EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _)) + .Times(2 * 3) + .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); + // ... and then special handling for dimensions. Specifying this + // rules later means that gmock will try them first, i.e., + // ordering of width/height vs. the default implementation for + // other queries is significant. + EXPECT_CALL(*mMockComposer, + getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE))); + + EXPECT_CALL(*mMockComposer, + getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE))); + + // TODO: Width and height queries are not actually called. Display + // info returns dimensions 0x0 in display info. Why? + + mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED); + + { + sp<android::IBinder> display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(400u, info.w); + ASSERT_EQ(200u, info.h); + + auto surfaceControl = + mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w, info.h, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(surfaceControl != nullptr); + ASSERT_TRUE(surfaceControl->isValid()); + fillSurfaceRGBA8(surfaceControl, BLUE); + + { + GlobalTransactionScope gts(*mMockComposer); + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, surfaceControl->show()); + } + } + + mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED); + + mMockComposer->clearFrames(); + + mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED); + + { + sp<android::IBinder> display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(400u, info.w); + ASSERT_EQ(200u, info.h); + + auto surfaceControl = + mComposerClient->createSurface(String8("Display Test Surface Bar"), info.w, info.h, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(surfaceControl != nullptr); + ASSERT_TRUE(surfaceControl->isValid()); + fillSurfaceRGBA8(surfaceControl, BLUE); + + { + GlobalTransactionScope gts(*mMockComposer); + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, surfaceControl->show()); + } + } + mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED); +} + +//////////////////////////////////////////////// + +class TransactionTest : public ::testing::Test { +protected: + // Layer array indexing constants. + constexpr static int BG_LAYER = 0; + constexpr static int FG_LAYER = 1; + + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; + + sp<SurfaceComposerClient> mComposerClient; + sp<SurfaceControl> mBGSurfaceControl; + sp<SurfaceControl> mFGSurfaceControl; + std::vector<RenderState> mBaseFrame; + uint32_t mDisplayWidth; + uint32_t mDisplayHeight; + + static FakeComposerClient* sFakeComposer; +}; + +FakeComposerClient* TransactionTest::sFakeComposer; + +void TransactionTest::SetUpTestCase() { + // TODO: See TODO comment at DisplayTest::SetUp for background on + // the lifetime of the FakeComposerClient. + sFakeComposer = new FakeComposerClient; + sp<ComposerClient> client = new ComposerClient(*sFakeComposer); + sFakeComposer->setClient(client.get()); + sp<IComposer> fakeService = new FakeComposerService(client); + fakeService->registerAsService("mock"); + + android::hardware::ProcessState::self()->startThreadPool(); + android::ProcessState::self()->startThreadPool(); + + startSurfaceFlinger(); + + // Fake composer wants to enable VSync injection + sFakeComposer->onSurfaceFlingerStart(); +} + +void TransactionTest::TearDownTestCase() { + // Fake composer needs to release SurfaceComposerClient before the stop. + sFakeComposer->onSurfaceFlingerStop(); + stopSurfaceFlinger(); + // TODO: This is deleted when the ComposerClient calls + // removeClient. Devise better lifetime control. + sFakeComposer = nullptr; +} + +void TransactionTest::SetUp() { + ALOGI("TransactionTest::SetUp"); + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + + ALOGI("TransactionTest::SetUp - display"); + sp<android::IBinder> display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + + mDisplayWidth = info.w; + mDisplayHeight = info.h; + + // Background surface + mBGSurfaceControl = mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth, + mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mBGSurfaceControl != nullptr); + ASSERT_TRUE(mBGSurfaceControl->isValid()); + fillSurfaceRGBA8(mBGSurfaceControl, BLUE); + + // Foreground surface + mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mFGSurfaceControl != nullptr); + ASSERT_TRUE(mFGSurfaceControl->isValid()); + + fillSurfaceRGBA8(mFGSurfaceControl, RED); + + SurfaceComposerClient::openGlobalTransaction(); + + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); + + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX - 1)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + + // Synchronous transaction will stop this thread, so we set up a + // delayed, off-thread vsync request before closing the + // transaction. In the test code this is usually done with + // GlobalTransactionScope. Leaving here in the 'vanilla' form for + // reference. + ASSERT_EQ(0, sFakeComposer->getFrameCount()); + sFakeComposer->runVSyncAfter(1ms); + SurfaceComposerClient::closeGlobalTransaction(true); + sFakeComposer->waitUntilFrame(1); + + // Reference data. This is what the HWC should see. + static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing"); + mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight)); + mBaseFrame[BG_LAYER].mSwapCount = 1; + mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64)); + mBaseFrame[FG_LAYER].mSwapCount = 1; + + auto frame = sFakeComposer->getFrameRects(0); + ASSERT_TRUE(framesAreSame(mBaseFrame, frame)); +} + +void TransactionTest::TearDown() { + ALOGD("TransactionTest::TearDown"); + + mComposerClient->dispose(); + mBGSurfaceControl = 0; + mFGSurfaceControl = 0; + mComposerClient = 0; + + sFakeComposer->runVSyncAndWait(); + mBaseFrame.clear(); + sFakeComposer->clearFrames(); + ASSERT_EQ(0, sFakeComposer->getFrameCount()); + + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + std::vector<LayerDebugInfo> layers; + status_t result = sf->getLayerDebugInfo(&layers); + if (result != NO_ERROR) { + ALOGE("Failed to get layers %s %d", strerror(-result), result); + } else { + // If this fails, the test being torn down leaked layers. + EXPECT_EQ(0u, layers.size()); + if (layers.size() > 0) { + for (auto layer = layers.begin(); layer != layers.end(); ++layer) { + std::cout << to_string(*layer).c_str(); + } + // To ensure the next test has clean slate, will run the class + // tear down and setup here. + TearDownTestCase(); + SetUpTestCase(); + } + } + ALOGD("TransactionTest::TearDown - complete"); +} + +TEST_F(TransactionTest, LayerMove) { + ALOGD("TransactionTest::LayerMove"); + + // The scope opens and closes a global transaction and, at the + // same time, makes sure the SurfaceFlinger progresses one frame + // after the transaction closes. The results of the transaction + // should be available in the latest frame stored by the fake + // composer. + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); + // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls. + // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?) + // + // sFakeComposer->runVSyncAndWait(); + } + + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + + ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's + // no extra frames. + + // NOTE: Frame 0 is produced in the SetUp. + auto frame1Ref = mBaseFrame; + frame1Ref[FG_LAYER].mDisplayFrame = + hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves. + EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1))); + + auto frame2Ref = frame1Ref; + frame2Ref[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); +} + +TEST_F(TransactionTest, LayerResize) { + ALOGD("TransactionTest::LayerResize"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128)); + } + + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + + ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's + // no extra frames. + + auto frame1Ref = mBaseFrame; + // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size posted. + EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1))); + + auto frame2Ref = frame1Ref; + frame2Ref[FG_LAYER].mSwapCount++; + frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128}; + frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f}; + EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); +} + +TEST_F(TransactionTest, LayerCrop) { + // TODO: Add scaling to confirm that crop happens in buffer space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(16, 16, 32, 32); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f}; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerFinalCrop) { + // TODO: Add scaling to confirm that crop happens in display space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(32, 32, 32 + 64, 32 + 64); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // In display space we are cropping with [32, 32, 96, 96] against display rect + // [64, 64, 128, 128]. Should yield display rect [64, 64, 96, 96] + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f}; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 32, 64 + 32}; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerFinalCropEmpty) { + // TODO: Add scaling to confirm that crop happens in display space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(16, 16, 32, 32); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // In display space we are cropping with [16, 16, 32, 32] against display rect + // [64, 64, 128, 128]. The intersection is empty and only the background layer is composited. + std::vector<RenderState> referenceFrame(1); + referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetLayer) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // The layers will switch order, but both are rendered because the background layer is + // transparent (RGBA8888). + std::vector<RenderState> referenceFrame(2); + referenceFrame[0] = mBaseFrame[FG_LAYER]; + referenceFrame[1] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetLayerOpaque) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); + ASSERT_EQ(NO_ERROR, + mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, + layer_state_t::eLayerOpaque)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // The former foreground layer is now covered with opaque layer - it should have disappeared + std::vector<RenderState> referenceFrame(1); + referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, SetLayerStack) { + ALOGD("TransactionTest::SetLayerStack"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1)); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector<RenderState> refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerShowHide) { + ALOGD("TransactionTest::LayerShowHide"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide()); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector<RenderState> refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + } + + // Foreground layer should be back + ASSERT_EQ(3, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetAlpha) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f)); + } + + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetFlags) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, + mFGSurfaceControl->setFlags(layer_state_t::eLayerHidden, + layer_state_t::eLayerHidden)); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector<RenderState> refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetMatrix) { + struct matrixTestData { + float matrix[4]; + hwc_transform_t expectedTransform; + hwc_rect_t expectedDisplayFrame; + }; + + // The matrix operates on the display frame and is applied before + // the position is added. So, the foreground layer rect is (0, 0, + // 64, 64) is first transformed, potentially yielding negative + // coordinates and then the position (64, 64) is added yielding + // the final on-screen rectangles given. + + const matrixTestData MATRIX_TESTS[7] = // clang-format off + {{{-1.f, 0.f, 0.f, 1.f}, HWC_TRANSFORM_FLIP_H, {0, 64, 64, 128}}, + {{1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_FLIP_V, {64, 0, 128, 64}}, + {{0.f, 1.f, -1.f, 0.f}, HWC_TRANSFORM_ROT_90, {0, 64, 64, 128}}, + {{-1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_ROT_180, {0, 0, 64, 64}}, + {{0.f, -1.f, 1.f, 0.f}, HWC_TRANSFORM_ROT_270, {64, 0, 128, 64}}, + {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}}, + {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}}; + // clang-format on + constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData); + + for (int i = 0; i < TEST_COUNT; i++) { + // TODO: How to leverage the HWC2 stringifiers? + const matrixTestData& xform = MATRIX_TESTS[i]; + SCOPED_TRACE(i); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, + mFGSurfaceControl->setMatrix(xform.matrix[0], xform.matrix[1], + xform.matrix[2], xform.matrix[3])); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mTransform = xform.expectedTransform; + referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + } +} + +#if 0 +TEST_F(TransactionTest, LayerSetMatrix2) { + { + GlobalTransactionScope gts(*sFakeComposer); + // TODO: PLEASE SPEC THE FUNCTION! + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(0.11f, 0.123f, + -2.33f, 0.22f)); + } + auto referenceFrame = mBaseFrame; + // TODO: Is this correct for sure? + //referenceFrame[FG_LAYER].mTransform = HWC_TRANSFORM_FLIP_V & HWC_TRANSFORM_ROT_90; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} +#endif + +TEST_F(TransactionTest, DeferredTransaction) { + // Synchronization surface + constexpr static int SYNC_LAYER = 2; + auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(syncSurfaceControl != nullptr); + ASSERT_TRUE(syncSurfaceControl->isValid()); + + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->setLayer(INT32_MAX - 1)); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->setPosition(mDisplayWidth - 2, mDisplayHeight - 2)); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->show()); + } + auto referenceFrame = mBaseFrame; + referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2, + mDisplayWidth - 1, mDisplayHeight - 1)); + referenceFrame[SYNC_LAYER].mSwapCount = 1; + EXPECT_EQ(2, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // set up two deferred transactions on different frames - these should not yield composited + // frames + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75)); + mFGSurfaceControl + ->deferTransactionUntil(syncSurfaceControl->getHandle(), + syncSurfaceControl->getSurface()->getNextFrameNumber()); + } + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); + mFGSurfaceControl + ->deferTransactionUntil(syncSurfaceControl->getHandle(), + syncSurfaceControl->getSurface()->getNextFrameNumber() + 1); + } + EXPECT_EQ(4, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // should trigger the first deferred transaction, but not the second one + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + sFakeComposer->runVSyncAndWait(); + EXPECT_EQ(5, sFakeComposer->getFrameCount()); + + referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f; + referenceFrame[SYNC_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // should show up immediately since it's not deferred + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0)); + } + referenceFrame[FG_LAYER].mPlaneAlpha = 1.f; + EXPECT_EQ(6, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // trigger the second deferred transaction + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + sFakeComposer->runVSyncAndWait(); + // TODO: Compute from layer size? + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64}; + referenceFrame[SYNC_LAYER].mSwapCount++; + EXPECT_EQ(7, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, SetRelativeLayer) { + constexpr int RELATIVE_LAYER = 2; + auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, 64, + PIXEL_FORMAT_RGBA_8888, 0); + fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED); + + // Now we stack the surface above the foreground surface and make sure it is visible. + { + GlobalTransactionScope gts(*sFakeComposer); + relativeSurfaceControl->setPosition(64, 64); + relativeSurfaceControl->show(); + relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1); + } + auto referenceFrame = mBaseFrame; + // NOTE: All three layers will be visible as the surfaces are + // transparent because of the RGBA format. + referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64)); + referenceFrame[RELATIVE_LAYER].mSwapCount = 1; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // A call to setLayer will override a call to setRelativeLayer + { + GlobalTransactionScope gts(*sFakeComposer); + relativeSurfaceControl->setLayer(0); + } + + // Previous top layer will now appear at the bottom. + auto referenceFrame2 = mBaseFrame; + referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]); + EXPECT_EQ(3, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +class ChildLayerTest : public TransactionTest { +protected: + constexpr static int CHILD_LAYER = 2; + + void SetUp() override { + TransactionTest::SetUp(); + mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(mChild, LIGHT_GRAY); + + sFakeComposer->runVSyncAndWait(); + mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10)); + mBaseFrame[CHILD_LAYER].mSwapCount = 1; + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + } + void TearDown() override { + mChild = 0; + TransactionTest::TearDown(); + } + + sp<SurfaceControl> mChild; +}; + +TEST_F(ChildLayerTest, Positioning) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + // Move to the same position as in the original setup. + mFGSurfaceControl->setPosition(64, 64); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0)); + } + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Cropping) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5)); + } + // NOTE: The foreground surface would be occluded by the child + // now, but is included in the stack because the child is + // transparent. + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, FinalCropping) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5)); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Constraints) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mFGSurfaceControl->setPosition(0, 0); + mChild->setPosition(63, 63); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Scaling) { + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setPosition(0, 0); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0); + } + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, LayerAlpha) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5)); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5)); + } + + auto referenceFrame2 = referenceFrame; + referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f; + referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, ReparentChildren) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + mFGSurfaceControl->setPosition(64, 64); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle()); + } + + auto referenceFrame2 = referenceFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, DetachChildren) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + mFGSurfaceControl->setPosition(64, 64); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->detachChildren(); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->hide(); + } + + // Nothing should have changed. The child control becomes a no-op + // zombie on detach. See comments for detachChildren in the + // SurfaceControl.h file. + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + // We cause scaling by 2. + mFGSurfaceControl->setSize(128, 128); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +// Regression test for b/37673612 +TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + } + + // We set things up as in b/37673612 so that there is a mismatch between the buffer size and + // the WM specified state size. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 64); + } + + sp<Surface> s = mFGSurfaceControl->getSurface(); + auto anw = static_cast<ANativeWindow*>(s.get()); + native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); + native_window_set_buffers_dimensions(anw, 64, 128); + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + + // The child should still be in the same place and not have any strange scaling as in + // b/37673612. + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f}; + referenceFrame[FG_LAYER].mSwapCount++; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Bug36858924) { + // Destroy the child layer + mChild.clear(); + + // Now recreate it as hidden + mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden, + mFGSurfaceControl.get()); + + // Show the child layer in a deferred transaction + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(), + mFGSurfaceControl->getSurface()->getNextFrameNumber()); + mChild->show(); + } + + // Render the foreground surface a few times + // + // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third + // frame because SurfaceFlinger would never process the deferred transaction and would therefore + // never acquire/release the first buffer + ALOGI("Filling 1"); + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 2"); + fillSurfaceRGBA8(mFGSurfaceControl, BLUE); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 3"); + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 4"); + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); +} + +class LatchingTest : public TransactionTest { +protected: + void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); } + + void unlockFGBuffer() { + sp<Surface> s = mFGSurfaceControl->getSurface(); + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); + sFakeComposer->runVSyncAndWait(); + } + + void completeFGResize() { + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + } + void restoreInitialState() { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(64, 64); + mFGSurfaceControl->setPosition(64, 64); + mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64)); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); + } +}; + +TEST_F(LatchingTest, SurfacePositionLatching) { + // By default position can be updated even while + // a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(32, 32); + mFGSurfaceControl->setPosition(100, 100); + } + + // The size should not have updated as we have not provided a new buffer. + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + // Now we repeat with setGeometryAppliesWithResize + // and verify the position DOESN'T latch. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setSize(32, 32); + mFGSurfaceControl->setPosition(100, 100); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32}; + referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, CropLatching) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; + referenceFrame1[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; + referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, FinalCropLatching) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame1[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame2[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +// In this test we ensure that setGeometryAppliesWithResize actually demands +// a buffer of the new size, and not just any size. +TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame1[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + // In order to prepare to submit a buffer at the wrong size, we acquire it prior to + // initiating the resize. + lockAndFillFGBuffer(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + // We now submit our old buffer, at the old size, and ensure it doesn't + // trigger geometry latching. + unlockFGBuffer(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); + + completeFGResize(); + auto referenceFrame3 = referenceFrame2; + referenceFrame3[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame3[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)}; + referenceFrame3[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame3, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) { + // In this scenario, we attempt to set the final crop a second time while the resize + // is still pending, and ensure we are successful. Success meaning the second crop + // is the one which eventually latches and not the first. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +} // namespace + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + sftest::FakeHwcEnvironment* fakeEnvironment = new sftest::FakeHwcEnvironment; + ::testing::AddGlobalTestEnvironment(fakeEnvironment); + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp index 062485ea52..4055527b13 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp @@ -382,7 +382,9 @@ public: if (outErr) { *outErr = err; } else { - ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set cursor position"; + ASSERT_TRUE((err == HWC2_ERROR_NONE) || + (err == HWC2_ERROR_BAD_LAYER)) << + "failed to set cursor position"; } } @@ -652,7 +654,7 @@ public: hwc2_layer_request_t request = requests.at(i); EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer), - 0) << "get display requests returned an unknown layer"; + 1) << "get display requests returned an unknown layer"; EXPECT_NE(request, 0) << "returned empty request for layer " << requestedLayer; @@ -1603,9 +1605,10 @@ protected: EXPECT_EQ(layers.size(), fences.size()); for (int32_t fence : fences) { - EXPECT_GE(sync_wait(fence, msWait), 0); - if (fence >= 0) + if (fence >= 0) { + EXPECT_GE(sync_wait(fence, msWait), 0); close(fence); + } } } @@ -1643,8 +1646,9 @@ protected: testLayers->getBlendMode(layer))); EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer, testLayers->getColor(layer))); - EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, cursor.left, - cursor.top)); + if (composition == HWC2_COMPOSITION_CURSOR) + EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, + cursor.left, cursor.top)); EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer, testLayers->getDataspace(layer))); EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer, @@ -2895,7 +2899,6 @@ TEST_F(Hwc2Test, SET_CURSOR_POSITION_composition_type_unset) ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { - const hwc_rect_t cursorPosition = testLayer->getCursorPosition(); EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer, cursorPosition.left, cursorPosition.top, outErr)); @@ -4406,11 +4409,11 @@ TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_display) /* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */ TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter) { - hwc2_display_t display = HWC_DISPLAY_PRIMARY; hwc2_error_t err = HWC2_ERROR_NONE; - - ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err)); - EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code"; + for (auto display : mDisplays) { + ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code"; + } } /* TESTCASE: Tests that the HWC2 can get the max virtual display count. */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp index 1d3a1d38ac..6873c455e9 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp @@ -570,8 +570,8 @@ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, * (100x50) at the end of the transformation. */ if (transform & HWC_TRANSFORM_ROT_90) { float tmp = xPos; - xPos = -yPos * dfW / dfH; - yPos = tmp * dfH / dfW; + xPos = yPos * dfW / dfH; + yPos = -tmp * dfH / dfW; } /* Change origin back to the top left corner of the diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp index c31417bcc7..abe571ae9e 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.cpp +++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp @@ -161,6 +161,10 @@ void VrComposerClient::onHotplug(Display display, client_->onHotplug(display, connected); } +void VrComposerClient::onRefresh(Display display) { + client_->onRefresh(display); +} + Return<void> VrComposerClient::registerCallback( const sp<IComposerCallback>& callback) { return client_->registerCallback(callback); diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h index f492230215..dfc656a0f1 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.h +++ b/services/vr/hardware_composer/impl/vr_composer_client.h @@ -35,6 +35,7 @@ class VrComposerClient : public IVrComposerClient { virtual ~VrComposerClient(); void onHotplug(Display display, IComposerCallback::Connection connected); + void onRefresh(Display display); // IComposerClient Return<void> registerCallback(const sp<IComposerCallback>& callback) override; diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp index 45471d70b0..fd271d0fe2 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.cpp +++ b/services/vr/hardware_composer/impl/vr_hwc.cpp @@ -855,6 +855,14 @@ Return<void> VrHwc::createClient(createClient_cb hidl_cb) { return Void(); } +void VrHwc::ForceDisplaysRefresh() { + std::lock_guard<std::mutex> guard(mutex_); + if (client_ != nullptr) { + for (const auto& pair : displays_) + client_.promote()->onRefresh(pair.first); + } +} + void VrHwc::RegisterObserver(Observer* observer) { std::lock_guard<std::mutex> guard(mutex_); if (observer_) diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h index 523cda3f69..fce9a063e0 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.h +++ b/services/vr/hardware_composer/impl/vr_hwc.h @@ -103,6 +103,7 @@ class ComposerView { virtual ~ComposerView() {} + virtual void ForceDisplaysRefresh() = 0; virtual void RegisterObserver(Observer* observer) = 0; virtual void UnregisterObserver(Observer* observer) = 0; }; @@ -288,6 +289,7 @@ class VrHwc : public IComposer, public ComposerBase, public ComposerView { Return<void> createClient(createClient_cb hidl_cb) override; // ComposerView: + void ForceDisplaysRefresh() override; void RegisterObserver(Observer* observer) override; void UnregisterObserver(Observer* observer) override; @@ -295,7 +297,6 @@ class VrHwc : public IComposer, public ComposerBase, public ComposerView { HwcDisplay* FindDisplay(Display display); wp<VrComposerClient> client_; - sp<IComposerCallback> callbacks_; // Guard access to internal state from binder threads. std::mutex mutex_; diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp index d082f4bc92..2e70928662 100644 --- a/services/vr/hardware_composer/tests/vr_composer_test.cpp +++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp @@ -10,6 +10,24 @@ namespace { const char kVrDisplayName[] = "VrDisplay_Test"; +class TestComposerView : public ComposerView { + public: + TestComposerView() {} + ~TestComposerView() override = default; + + size_t display_refresh_count() const { return display_refresh_count_; } + + void ForceDisplaysRefresh() override { display_refresh_count_++; } + void RegisterObserver(Observer* observer) override {} + void UnregisterObserver(Observer* observer) override {} + + TestComposerView(const TestComposerView&) = delete; + void operator=(const TestComposerView&) = delete; + + private: + size_t display_refresh_count_ = 0; +}; + class TestComposerCallback : public BnVrComposerCallback { public: TestComposerCallback() {} @@ -57,7 +75,7 @@ sp<GraphicBuffer> CreateBuffer() { class VrComposerTest : public testing::Test { public: - VrComposerTest() : composer_(new VrComposer()) {} + VrComposerTest() : composer_(new VrComposer(&composer_view_)) {} ~VrComposerTest() override = default; sp<IVrComposer> GetComposerProxy() const { @@ -72,6 +90,7 @@ class VrComposerTest : public testing::Test { } protected: + TestComposerView composer_view_; sp<VrComposer> composer_; VrComposerTest(const VrComposerTest&) = delete; @@ -89,7 +108,9 @@ TEST_F(VrComposerTest, TestWithoutObserver) { TEST_F(VrComposerTest, TestWithObserver) { sp<IVrComposer> composer = GetComposerProxy(); sp<TestComposerCallback> callback = new TestComposerCallback(); + ASSERT_EQ(0, composer_view_.display_refresh_count()); ASSERT_TRUE(composer->registerObserver(callback).isOk()); + ASSERT_EQ(1, composer_view_.display_refresh_count()); ComposerView::Frame frame; base::unique_fd fence = composer_->OnNewFrame(frame); diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp index 36a313ae24..d93f370945 100644 --- a/services/vr/hardware_composer/vr_composer.cpp +++ b/services/vr/hardware_composer/vr_composer.cpp @@ -21,24 +21,36 @@ bool CheckPermission() { } // namespace -VrComposer::VrComposer() {} +VrComposer::VrComposer(ComposerView* composer_view) + : composer_view_(composer_view) { + composer_view_->RegisterObserver(this); +} -VrComposer::~VrComposer() {} +VrComposer::~VrComposer() { + composer_view_->UnregisterObserver(this); +} binder::Status VrComposer::registerObserver( const sp<IVrComposerCallback>& callback) { - std::lock_guard<std::mutex> guard(mutex_); + { + std::lock_guard<std::mutex> guard(mutex_); + + if (!CheckPermission()) + return binder::Status::fromStatusT(PERMISSION_DENIED); - if (!CheckPermission()) - return binder::Status::fromStatusT(PERMISSION_DENIED); + if (callback_.get()) { + ALOGE("Failed to register callback, already registered"); + return binder::Status::fromStatusT(ALREADY_EXISTS); + } - if (callback_.get()) { - ALOGE("Failed to register callback, already registered"); - return binder::Status::fromStatusT(ALREADY_EXISTS); + callback_ = callback; + IInterface::asBinder(callback_)->linkToDeath(this); } - callback_ = callback; - IInterface::asBinder(callback_)->linkToDeath(this); + // Don't take the lock to force display refresh otherwise it could end in a + // deadlock since HWC calls this with new frames and it has a lock of its own + // to serialize access to the display information. + composer_view_->ForceDisplaysRefresh(); return binder::Status::ok(); } diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h index 7b580c6cba..1273352ad0 100644 --- a/services/vr/hardware_composer/vr_composer.h +++ b/services/vr/hardware_composer/vr_composer.h @@ -20,7 +20,7 @@ class VrComposer public ComposerView::Observer, public IBinder::DeathRecipient { public: - VrComposer(); + explicit VrComposer(ComposerView* composer_view); ~VrComposer() override; // BnVrComposer: @@ -40,6 +40,8 @@ class VrComposer sp<IVrComposerCallback> callback_; + ComposerView* composer_view_; // Not owned. + VrComposer(const VrComposer&) = delete; void operator=(const VrComposer&) = delete; }; diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp index e36b0ae3f1..7701847120 100644 --- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp +++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp @@ -36,8 +36,7 @@ int main() { "Failed to register service"); android::sp<android::dvr::VrComposer> composer = - new android::dvr::VrComposer(); - service->RegisterObserver(composer.get()); + new android::dvr::VrComposer(service.get()); android::sp<android::IServiceManager> sm(android::defaultServiceManager()); @@ -52,7 +51,5 @@ int main() { android::hardware::ProcessState::self()->startThreadPool(); android::hardware::IPCThreadState::self()->joinThreadPool(); - service->UnregisterObserver(composer.get()); - return 0; } diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp index 4b9fbe047d..4c26671b11 100644 --- a/services/vr/performanced/performance_service.cpp +++ b/services/vr/performanced/performance_service.cpp @@ -22,13 +22,15 @@ using android::dvr::Task; using android::pdx::ErrorStatus; using android::pdx::Message; using android::pdx::Status; -using android::pdx::rpc::DispatchRemoteMethod; using android::pdx::default_transport::Endpoint; +using android::pdx::rpc::DispatchRemoteMethod; namespace { const char kCpuSetBasePath[] = "/dev/cpuset"; +const char kRootCpuSet[] = "/"; + constexpr unsigned long kTimerSlackForegroundNs = 50000; constexpr unsigned long kTimerSlackBackgroundNs = 40000000; @@ -123,22 +125,22 @@ PerformanceService::PerformanceService() // hack for now to put some form of permission logic in place while a longer // term solution is developed. using AllowRootSystem = - CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>, - GroupId<AID_SYSTEM>>>; + CheckAnd<SameProcess, + CheckOr<UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>>; using AllowRootSystemGraphics = CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>, GroupId<AID_SYSTEM, AID_GRAPHICS>>>; using AllowRootSystemAudio = CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>, GroupId<AID_SYSTEM, AID_AUDIO>>>; - using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, - GroupId<AID_SYSTEM>>; + using AllowRootSystemTrusted = + CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>; partition_permission_check_ = AllowRootSystemTrusted::Check; // Setup the scheduler classes. // TODO(eieio): Replace this with a device-specific config file. - scheduler_classes_ = { + scheduler_policies_ = { {"audio:low", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, @@ -183,12 +185,14 @@ PerformanceService::PerformanceService() {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, .priority = fifo_medium + 2, - .permission_check = AllowRootSystemTrusted::Check}}, + .permission_check = AllowRootSystemTrusted::Check, + "/system/performance"}}, {"vr:app:render", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, .priority = fifo_medium + 1, - .permission_check = AllowRootSystemTrusted::Check}}, + .permission_check = AllowRootSystemTrusted::Check, + "/application/performance"}}, {"normal", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_NORMAL, @@ -219,14 +223,80 @@ std::string PerformanceService::DumpState(size_t /*max_length*/) { Status<void> PerformanceService::OnSetSchedulerPolicy( Message& message, pid_t task_id, const std::string& scheduler_policy) { - // Forward to scheduler class handler for now. In the future this method will - // subsume the others by unifying both scheduler class and cpu partiton into a - // single policy concept. ALOGI( "PerformanceService::OnSetSchedulerPolicy: task_id=%d " "scheduler_policy=%s", task_id, scheduler_policy.c_str()); - return OnSetSchedulerClass(message, task_id, scheduler_policy); + + Task task(task_id); + if (!task) { + ALOGE( + "PerformanceService::OnSetSchedulerPolicy: Unable to access /proc/%d " + "to gather task information.", + task_id); + return ErrorStatus(EINVAL); + } + + auto search = scheduler_policies_.find(scheduler_policy); + if (search != scheduler_policies_.end()) { + auto config = search->second; + + // Make sure the sending process is allowed to make the requested change to + // this task. + if (!config.IsAllowed(message, task)) + return ErrorStatus(EINVAL); + + // Get the thread group's cpu set. Policies that do not specify a cpuset + // should default to this cpuset. + std::string thread_group_cpuset; + Task thread_group{task.thread_group_id()}; + if (thread_group) { + thread_group_cpuset = thread_group.GetCpuSetPath(); + } else { + ALOGE( + "PerformanceService::OnSetSchedulerPolicy: Failed to get thread " + "group tgid=%d for task_id=%d", + task.thread_group_id(), task_id); + thread_group_cpuset = kRootCpuSet; + } + + std::string target_cpuset; + if (config.cpuset.empty()) { + target_cpuset = thread_group_cpuset; + } else { + target_cpuset = config.cpuset; + } + ALOGI("PerformanceService::OnSetSchedulerPolicy: Using cpuset=%s", + target_cpuset.c_str()); + + auto target_set = cpuset_.Lookup(target_cpuset); + if (target_set) { + auto attach_status = target_set->AttachTask(task_id); + ALOGW_IF(!attach_status, + "PerformanceService::OnSetSchedulerPolicy: Failed to attach " + "task=%d to cpuset=%s: %s", + task_id, target_cpuset.c_str(), + attach_status.GetErrorMessage().c_str()); + } else { + ALOGW( + "PerformanceService::OnSetSchedulerPolicy: Failed to lookup " + "cpuset=%s", + target_cpuset.c_str()); + } + + struct sched_param param; + param.sched_priority = config.priority; + + sched_setscheduler(task_id, config.scheduler_policy, ¶m); + prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id); + return {}; + } else { + ALOGE( + "PerformanceService::OnSetSchedulerPolicy: Invalid scheduler_policy=%s " + "requested by task=%d.", + scheduler_policy.c_str(), task_id); + return ErrorStatus(EINVAL); + } } Status<void> PerformanceService::OnSetCpuPartition( @@ -259,8 +329,8 @@ Status<void> PerformanceService::OnSetSchedulerClass( if (!task) return ErrorStatus(EINVAL); - auto search = scheduler_classes_.find(scheduler_class); - if (search != scheduler_classes_.end()) { + auto search = scheduler_policies_.find(scheduler_class); + if (search != scheduler_policies_.end()) { auto config = search->second; // Make sure the sending process is allowed to make the requested change to diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h index b28d94addb..6b519abac3 100644 --- a/services/vr/performanced/performance_service.h +++ b/services/vr/performanced/performance_service.h @@ -44,13 +44,13 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { int sched_fifo_min_priority_; int sched_fifo_max_priority_; - // Scheduler class config type. - struct SchedulerClassConfig { + struct SchedulerPolicyConfig { unsigned long timer_slack; int scheduler_policy; int priority; std::function<bool(const pdx::Message& message, const Task& task)> permission_check; + std::string cpuset; // Check the permisison of the given task to use this scheduler class. If a // permission check function is not set then operations are only allowed on @@ -65,7 +65,7 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { } }; - std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_; + std::unordered_map<std::string, SchedulerPolicyConfig> scheduler_policies_; std::function<bool(const pdx::Message& message, const Task& task)> partition_permission_check_; diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp index 274a1b36d4..4065785426 100644 --- a/services/vr/performanced/performance_service_tests.cpp +++ b/services/vr/performanced/performance_service_tests.cpp @@ -1,24 +1,65 @@ #include <errno.h> #include <sched.h> +#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <condition_variable> #include <cstdlib> +#include <iostream> #include <mutex> +#include <sstream> #include <thread> +#include <utility> +#include <android-base/unique_fd.h> #include <dvr/performance_client_api.h> #include <gtest/gtest.h> #include <private/android_filesystem_config.h> +#include "stdio_filebuf.h" +#include "string_trim.h" +#include "unique_file.h" + +using android::dvr::Trim; +using android::dvr::UniqueFile; +using android::dvr::stdio_filebuf; + namespace { const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID"; +const char kProcBase[] = "/proc"; + +std::pair<UniqueFile, int> OpenTaskFile(pid_t task_id, + const std::string& name) { + std::ostringstream stream; + stream << kProcBase << "/" << task_id << "/" << name; + + UniqueFile file{fopen(stream.str().c_str(), "r")}; + const int error = file ? 0 : errno; + return {std::move(file), error}; +} + +std::string GetTaskCpuSet(pid_t task_id) { + int error; + UniqueFile file; + + std::tie(file, error) = OpenTaskFile(task_id, "cpuset"); + if (!file) + return std::string("errno:") + strerror(error); + + stdio_filebuf<char> filebuf(file.get()); + std::istream file_stream(&filebuf); + + std::string line; + std::getline(file_stream, line); + return Trim(line); +} + } // anonymous namespace -TEST(DISABLED_PerformanceTest, SetCpuPartition) { +TEST(PerformanceTest, SetCpuPartition) { int error; // Test setting the the partition for the current task. @@ -59,13 +100,6 @@ TEST(DISABLED_PerformanceTest, SetCpuPartition) { } thread.join(); - // Test setting the partition for a task that isn't valid using - // the task id of the thread that we just joined. Technically the - // id could wrap around by the time we get here, but this is - // extremely unlikely. - error = dvrSetCpuPartition(task_id, "/application"); - EXPECT_EQ(-EINVAL, error); - // Test setting the partition for a task that doesn't belong to us. error = dvrSetCpuPartition(1, "/application"); EXPECT_EQ(-EINVAL, error); @@ -73,6 +107,10 @@ TEST(DISABLED_PerformanceTest, SetCpuPartition) { // Test setting the partition to one that doesn't exist. error = dvrSetCpuPartition(0, "/foobar"); EXPECT_EQ(-ENOENT, error); + + // Set the test back to the root partition. + error = dvrSetCpuPartition(0, "/"); + EXPECT_EQ(0, error); } TEST(PerformanceTest, SetSchedulerClass) { @@ -96,8 +134,6 @@ TEST(PerformanceTest, SetSchedulerClass) { EXPECT_EQ(-EINVAL, error); } -// This API mirrors SetSchedulerClass for now. Replace with with a more specific -// test once the policy API is fully implemented. TEST(PerformanceTest, SetSchedulerPolicy) { int error; @@ -115,6 +151,50 @@ TEST(PerformanceTest, SetSchedulerPolicy) { error = dvrSetSchedulerPolicy(0, "foobar"); EXPECT_EQ(-EINVAL, error); + + // Set the test back to the root partition. + error = dvrSetCpuPartition(0, "/"); + EXPECT_EQ(0, error); + + const std::string original_cpuset = GetTaskCpuSet(gettid()); + EXPECT_EQ("/", original_cpuset); + + error = dvrSetSchedulerPolicy(0, "vr:system:arp"); + EXPECT_EQ(0, error); + EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0)); + + const std::string new_cpuset = GetTaskCpuSet(gettid()); + EXPECT_NE(original_cpuset, new_cpuset); + + // The cpuset for the thread group is now new_cpuset. Scheduler profiles that + // do not specify a cpuset should not change the cpuset of a thread, except to + // restore it to the thread group cpuset. + std::string thread_original_cpuset; + std::string thread_new_cpuset; + std::string thread_final_cpuset; + + std::thread thread{ + [&thread_original_cpuset, &thread_new_cpuset, &thread_final_cpuset]() { + thread_original_cpuset = GetTaskCpuSet(gettid()); + + int error = dvrSetSchedulerPolicy(0, "vr:app:render"); + EXPECT_EQ(0, error); + + thread_new_cpuset = GetTaskCpuSet(gettid()); + + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + + thread_final_cpuset = GetTaskCpuSet(gettid()); + }}; + thread.join(); + + EXPECT_EQ(new_cpuset, thread_original_cpuset); + EXPECT_NE(new_cpuset, thread_new_cpuset); + EXPECT_EQ(new_cpuset, thread_final_cpuset); + + error = dvrSetCpuPartition(0, original_cpuset.c_str()); + EXPECT_EQ(0, error); } TEST(PerformanceTest, SchedulerClassResetOnFork) { @@ -424,11 +504,11 @@ TEST(PerformanceTest, Permissions) { error = dvrSetSchedulerPolicy(0, "audio:high"); EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "graphics"); - EXPECT_EQ(0, error); + EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "graphics:low"); - EXPECT_EQ(0, error); + EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "graphics:high"); - EXPECT_EQ(0, error); + EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "sensors"); EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "sensors:low"); diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp index 1175a7b12b..c2f078efb4 100644 --- a/services/vr/performanced/task.cpp +++ b/services/vr/performanced/task.cpp @@ -48,15 +48,18 @@ Task::Task(pid_t task_id) thread_count_(0), cpus_allowed_mask_(0) { task_fd_ = OpenTaskDirectory(task_id_); - ALOGE_IF(task_fd_.get() < 0, + const int error = errno; + ALOGE_IF(task_fd_.get() < 0 && error != EACCES, "Task::Task: Failed to open task directory for task_id=%d: %s", - task_id, strerror(errno)); - - ReadStatusFields(); - - ALOGD_IF(TRACE, "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x", - task_id_, name_.c_str(), thread_group_id_, parent_process_id_, - cpus_allowed_mask_); + task_id, strerror(error)); + + if (IsValid()) { + ReadStatusFields(); + ALOGD_IF(TRACE, + "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x", + task_id_, name_.c_str(), thread_group_id_, parent_process_id_, + cpus_allowed_mask_); + } } base::unique_fd Task::OpenTaskFile(const std::string& name) const { diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 069fb36fd0..a346c0ac76 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -430,6 +430,8 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { return HAL_DATASPACE_DISPLAY_P3; case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT: return HAL_DATASPACE_V0_SCRGB_LINEAR; + case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT: + return HAL_DATASPACE_V0_SCRGB; case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT: return HAL_DATASPACE_DCI_P3_LINEAR; case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT: |