Merge "Fix resampling logic for duplicate events."
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 9cdc9e9..a48dab9 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -481,8 +481,8 @@
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 @@
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 7e05d72..014c995 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 @@
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 657323d..9e77e8f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -691,7 +691,7 @@
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 @@
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 f0e7200..73c7f18 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -176,7 +176,7 @@
}
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 66beb6d..5ca2b57 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -95,7 +95,7 @@
}
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 3eb39b9..ea0cd9e 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -60,7 +60,7 @@
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 @@
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 a711813..af7455a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -311,6 +311,7 @@
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 @@
// 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 @@
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 @@
}
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 @@
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 @@
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 de86cdc..8c75ee5 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1143,10 +1143,9 @@
// (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 @@
// 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 @@
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 630c1f3..443dce6 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -5,13 +5,13 @@
srcs: ["installd_utils_test.cpp"],
shared_libs: [
"libbase",
- "liblog",
"libutils",
"libcutils",
],
static_libs: [
- "libinstalld",
"libdiskusage",
+ "libinstalld",
+ "liblog",
],
}
@@ -23,14 +23,14 @@
"libbase",
"libbinder",
"libcutils",
- "liblog",
- "liblogwrap",
"libselinux",
"libutils",
],
static_libs: [
- "libinstalld",
"libdiskusage",
+ "libinstalld",
+ "liblog",
+ "liblogwrap",
],
}
@@ -42,13 +42,13 @@
"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 aed068c..2d58515 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -99,7 +99,7 @@
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 dab3236..46ed85f 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 @@
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 @@
<< "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, 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 @@
"/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 7c05417..d277bd3 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -238,13 +238,38 @@
// 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_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 @@
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 @@
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 070da84..da3a293 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 e2d5f6d..0d4a1d1 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -69,7 +69,7 @@
" 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 @@
" 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 35b63ec..2b5389b 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -505,7 +505,7 @@
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 79ddb76..1a5ad17 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -58,6 +58,12 @@
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 @@
/** 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 7f46087..2db0ee7 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -197,7 +197,7 @@
* 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 @@
};
} 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 @@
#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 @@
* {@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 @@
/*****************************************************************************/
/**
- * 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 0000000..85ac78f
--- /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 09fd0cb..83b8021 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -69,8 +69,13 @@
"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 e832961..0b390c5 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -470,22 +470,33 @@
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 0000000..6b7254c
--- /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 34aec5b..1611e11 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
*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 @@
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 @@
public:
BinderLibTestCallBack()
: m_result(NOT_ENOUGH_DATA)
+ , m_prev_end(NULL)
{
}
status_t getResult(void)
@@ -298,16 +331,43 @@
(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, 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 @@
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, 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 @@
: 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 @@
{
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 @@
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 @@
} 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 @@
}
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 @@
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 @@
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 @@
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 @@
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 4558fe8..21debc1 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -20,6 +20,9 @@
cc_library_shared {
name: "libgui",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
clang: true,
cppflags: [
@@ -93,6 +96,7 @@
"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 d9d50db..da42956 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 3424012..c5cab2d 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -764,7 +764,7 @@
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 @@
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 @@
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 3d36376..7aa7872 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -335,16 +335,25 @@
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 @@
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 34c9d78..14d9937 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 @@
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 8406a52..71e22ce 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -62,7 +62,8 @@
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 @@
}
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 @@
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 @@
}
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 0a0d112..8e7f814 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 @@
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 @@
}
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 0000000..57ddde0
--- /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 78eb69d..6c9d88b 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -974,6 +974,9 @@
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 @@
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 @@
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 @@
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 187b211..afa15c5 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 4a023a6..3b89291 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 @@
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 217fe6a..d9c5775 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -52,7 +52,7 @@
// 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 d6f215e..5c7ffb4 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -183,6 +183,9 @@
// 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 2cf6162..75f2cca 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -210,7 +210,7 @@
// 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 @@
// 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 f231f95..039dc0d 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -593,6 +593,12 @@
// 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 f80ba00..b226742 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -39,6 +39,7 @@
struct DisplayState;
struct DisplayInfo;
struct DisplayStatInfo;
+class LayerDebugInfo;
class HdrCapabilities;
class IDisplayEventConnection;
class IGraphicBufferProducer;
@@ -195,6 +196,12 @@
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 @@
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 0000000..8453e04
--- /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 60eac0c..3fe29d9 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -159,6 +159,7 @@
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 @@
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 @@
// 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 8bb705c..c15209d 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -90,6 +90,16 @@
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 c1c3ae7..74850b4 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 @@
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 2b9fd5d..bb6b8a5 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -92,6 +92,9 @@
}
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 bd598e4..d5b2f00 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 e18af17..45e95a5 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -539,6 +539,9 @@
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 d8dc957..9abd04c 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -450,7 +450,7 @@
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 cc74b9b..a914408 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -105,7 +105,7 @@
// 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 3df97a1..6490804 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -115,7 +115,7 @@
* 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 @@
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_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 0000000..6a38a1f
--- /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 6630d90..cabe94e 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 6e31d2a..2d72944 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 @@
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 39adc5e..755e60c 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -76,7 +76,7 @@
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 30f4a59..dad9446 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 bfb9a55..f9f87ff 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -417,6 +417,28 @@
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 6613add..53eed89 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -206,11 +206,11 @@
// 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 @@
return BAD_VALUE;
}
+ FreeAllBuffers();
connected_api_ = kNoConnectedApi;
return NO_ERROR;
}
@@ -608,6 +609,14 @@
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 @@
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 d57c7af..3e93788 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 @@
// 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 @@
// 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 d33a831..7ed55fb 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 @@
// 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 @@
// 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 e0a4052..7581a06 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 @@
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 8f55125..28cd63a 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 @@
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 018abbb..e4e20f9 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -14,6 +14,8 @@
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 @@
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 d0dbd8d..451d037 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -159,6 +159,12 @@
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 72e0f67..da12c13 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 @@
// 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 e2127f8..b3b41e2 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 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 f75283d..7520eee 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 @@
}
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 @@
}
}
- 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 @@
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, 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, 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, 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, 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 @@
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 @@
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 @@
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, 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 = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
+ 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_, &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 @@
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 @@
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 @@
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 @@
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, 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, 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, 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 @@
// 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 @@
}
} // namespace
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 733edc6..af18e21 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -40,10 +40,8 @@
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 @@
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 @@
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 6efe264..55e33ab 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -72,8 +72,6 @@
void GrantDisplayOwnership() { hardware_composer_.Enable(); }
void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
- void OnHardwareComposerRefresh();
-
private:
friend BASE;
friend DisplaySurface;
@@ -119,7 +117,6 @@
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 4852fab..6853781 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -26,14 +26,12 @@
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 @@
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 @@
}
} 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 7a0fb18..c8b1a07 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -53,8 +53,7 @@
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 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 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 4479d1e..f9a5dcd 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 @@
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 @@
} // 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 @@
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 @@
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 @@
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::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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 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 @@
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 @@
}
}
-// 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 @@
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 @@
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 @@
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 @@
// 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,30 +866,6 @@
vsync_callback_ = callback;
}
-void HardwareComposer::HwcRefresh(hwc2_callback_data_t /*data*/,
- hwc2_display_t /*display*/) {
- // TODO(eieio): implement invalidate callbacks.
-}
-
-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.
-}
-
-void HardwareComposer::HwcHotplug(hwc2_callback_data_t /*callbackData*/,
- hwc2_display_t /*display*/,
- hwc2_connection_t /*connected*/) {
- // TODO(eieio): implement display hotplug callbacks.
-}
-
-void HardwareComposer::OnHardwareComposerRefresh() {
- // TODO(steventhomas): Handle refresh.
-}
-
void HardwareComposer::SetBacklightBrightness(int brightness) {
if (backlight_brightness_fd_) {
std::array<char, 32> text;
@@ -1010,18 +874,59 @@
}
}
-void Layer::InitializeGlobals(Hwc2::Composer* hwc2_hidl,
- const HWCDisplayMetrics* metrics) {
- hwc2_hidl_ = hwc2_hidl;
- display_metrics_ = metrics;
+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));
+}
+
+Return<void> HardwareComposer::ComposerCallback::onHotplug(
+ Hwc2::Display /*display*/,
+ IComposerCallback::Connection /*conn*/) {
+ return Void();
+}
+
+Return<void> HardwareComposer::ComposerCallback::onRefresh(
+ Hwc2::Display /*display*/) {
+ return hardware::Void();
+}
+
+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_;
+}
+
+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::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 @@
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 @@
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 @@
"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 @@
// 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 @@
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 @@
} 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 @@
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 a0c50e1..fc0efee 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -54,11 +54,6 @@
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 @@
// 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 @@
// |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 @@
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 @@
}
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 e7f41a7..33cbc84 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -29,9 +29,6 @@
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 56405de..fcf94f0 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -133,10 +133,6 @@
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 aec5a95..9ca8b0b 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -52,6 +52,30 @@
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 b4cc211..802b3b4 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -85,7 +85,6 @@
cc_defaults {
name: "egl_libs_defaults",
defaults: ["gl_libs_defaults"],
- vendor_available: true,
cflags: [
"-DLOG_TAG=\"libEGL\"",
],
@@ -152,7 +151,6 @@
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 0214b0e..94dfe6a 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1447,7 +1447,7 @@
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 89269a0..fa26e33 100644
--- a/opengl/libs/libEGL.map.txt
+++ b/opengl/libs/libEGL.map.txt
@@ -21,6 +21,7 @@
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 @@
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 ee88667..67c0969 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 69e56ff..5956366 100644
--- a/opengl/tests/hwc/hwcRects.cpp
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -170,7 +170,7 @@
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 @@
// 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 014c261..9dc6bcf 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 @@
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 @@
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 @@
}
}
- free(configs);
-
if (i<n) {
*outConfig = config;
return NO_ERROR;
@@ -137,6 +150,159 @@
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 0000000..6a38a1f
--- /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 7d9b0b7..da3b275 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -223,8 +223,13 @@
}
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 @@
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 @@
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 cc93105..4775e4e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -2,3 +2,5 @@
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 744dd50..0244c1b 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 @@
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 @@
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 @@
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 @@
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 e34fa16..433a224 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -157,15 +157,11 @@
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 @@
}
}
+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 96dd833..31a3c1d 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -136,13 +136,18 @@
// 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 270a732..78c0c85 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 = 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 @@
}
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 @@
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::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::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::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 {
- 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);
+ } 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);
+ }
}
}
// 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 @@
}
}
-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 @@
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 @@
{
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::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::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 @@
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::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 @@
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::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::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 @@
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 @@
{
// 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::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 @@
{
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::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 @@
{
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 @@
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 @@
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 @@
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 @@
}
}
-// 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 @@
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 @@
// 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 @@
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::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 @@
}
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 @@
{
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 @@
{
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 @@
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 404bb28..fbe4c7e 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -53,24 +53,37 @@
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 @@
uint32_t getMaxVirtualDisplayCount() const;
Error createVirtualDisplay(uint32_t width, uint32_t height,
- android_pixel_format_t* format,
- std::shared_ptr<Display>* outDisplay);
+ android_pixel_format_t* format, Display** outDisplay);
+ void destroyDisplay(hwc2_display_t displayId);
- void registerHotplugCallback(HotplugCallback hotplug);
- void registerRefreshCallback(RefreshCallback refresh);
- void registerVsyncCallback(VsyncCallback vsync);
-
- // 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 @@
// 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 @@
// 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 @@
[[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 @@
// 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 @@
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 @@
[[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 ac2dde2..b096a3a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -59,13 +59,12 @@
// ---------------------------------------------------------------------------
-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 @@
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::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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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::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 @@
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 @@
auto hwcId = displayData.hwcDisplay->getId();
mHwcDisplaySlots.erase(hwcId);
displayData.reset();
+
+ mHwcDevice->destroyDisplay(hwcId);
}
status_t HWComposer::setOutputBuffer(int32_t displayId,
@@ -884,7 +870,7 @@
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 7463362..3640bb5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -65,24 +65,14 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 34f1cec..1de5e48 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -627,6 +627,10 @@
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 ac200ca..1671aba 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -130,6 +130,7 @@
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 ee6e886..052a959 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -31,34 +31,35 @@
}
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 8eb4067..e92565f 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 @@
}
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 @@
}
}
-// 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 @@
// 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 @@
// 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;
+ 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;
+ }
}
- 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.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 2306d1a..f7b82e4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -60,6 +60,7 @@
class DisplayDevice;
class GraphicBuffer;
class SurfaceFlinger;
+class LayerDebugInfo;
// ---------------------------------------------------------------------------
@@ -419,8 +420,14 @@
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 @@
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 @@
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 @@
sp<IGraphicBufferProducer> getProducer() const;
const String8& getName() const;
void notifyAvailableFrames();
+
+ PixelFormat getPixelFormat() const { return mFormat; }
+
private:
// -----------------------------------------------------------------------
@@ -760,12 +756,14 @@
// 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 d103820..1a5a85e 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -158,6 +158,10 @@
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 ff7f0f0..1246d14 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -68,6 +68,7 @@
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 ac2d8b2..56e9ac0 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 @@
"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 @@
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 @@
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 @@
}
}
- // 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 56f5827..9544579 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -64,7 +64,7 @@
};
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 aaaafbf..6a01f30 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 @@
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 @@
mLayersRemoved(false),
mLayersAdded(false),
mRepaintEverything(0),
- mHwc(nullptr),
- mRealHwc(nullptr),
- mVrHwc(nullptr),
+ mHwcServiceName(getHwcServiceName()),
mRenderEngine(nullptr),
mBootTime(systemTime()),
mBuiltinDisplays(),
@@ -160,7 +189,9 @@
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 @@
// 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 @@
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,51 +585,49 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offset NS: %" PRId64 "", vsyncPhaseOffsetNs);
-
- { // Autolock scope
- 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);
-
- // 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");
- }
-
- // 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);
- }
-
- // 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));
+ ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
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);
+
+ // 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");
+ }
+
+ // 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);
+
+ // 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) {
ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
@@ -613,16 +641,6 @@
}
}
- // 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 @@
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 @@
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 @@
{ // 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::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 @@
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);
+
+ // 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));
+
+ // make the GLContext current so that we can create textures when creating
+ // Layers (which may happens before we render something)
+ hw->makeCurrent(mEGLDisplay, mEGLContext);
}
-void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) {
- ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false");
+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");
- 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.");
+ // 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);
}
- return;
- }
-
- if (disp == DisplayDevice::DISPLAY_PRIMARY) {
- Mutex::Autolock lock(mStateLock);
- 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::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 @@
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();
+ int currentDisplayPowerMode = getDisplayDeviceLocked(
+ mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode();
- mHwc = mVrHwc;
- mVrFlinger->GrantDisplayOwnership();
-
- } 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);
+ 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);
+ // 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);
+ // 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 @@
} 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 @@
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 @@
}
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 @@
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 @@
return NO_ERROR;
}
+ layer->onRemovedFromCurrentState();
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
mNumLayers -= 1 + layer->getChildrenCount();
@@ -2860,10 +2909,12 @@
}
}
- // 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 @@
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::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 @@
}
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 @@
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 @@
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 @@
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 acfad46..058f4a1 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 @@
class SurfaceFlinger : public BnSurfaceComposer,
private IBinder::DeathRecipient,
+#ifdef USE_HWC2
+ private HWC2::ComposerCallback
+#else
private HWComposer::EventHandler
+#endif
{
public:
@@ -300,6 +311,7 @@
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 @@
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 @@
// 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 @@
/* ------------------------------------------------------------------------
* 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 @@
// 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 @@
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 @@
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 dae03b3..a92e1f9 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 @@
// 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 @@
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 @@
return NO_ERROR;
}
+ layer->onRemovedFromCurrentState();
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
mNumLayers -= 1 + layer->getChildrenCount();
@@ -3261,7 +3291,7 @@
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 0000000..94f3f25
--- /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 0000000..d97ffa3
--- /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 0000000..2a5a8ad
--- /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 0000000..c411604
--- /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 0000000..5204084
--- /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 0000000..51956ec
--- /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 0000000..74dc0e5
--- /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 0000000..0059289
--- /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 0000000..9ac3331
--- /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 062485e..4055527 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -382,7 +382,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 1d3a1d3..6873c45 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -570,8 +570,8 @@
* (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 c31417b..abe571a 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 @@
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 f492230..dfc656a 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 @@
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 45471d7..fd271d0 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();
}
+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 523cda3..fce9a06 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -103,6 +103,7 @@
virtual ~ComposerView() {}
+ virtual void ForceDisplaysRefresh() = 0;
virtual void RegisterObserver(Observer* observer) = 0;
virtual void UnregisterObserver(Observer* observer) = 0;
};
@@ -288,6 +289,7 @@
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 @@
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 d082f4b..2e70928 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 @@
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 @@
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 @@
}
protected:
+ TestComposerView composer_view_;
sp<VrComposer> composer_;
VrComposerTest(const VrComposerTest&) = delete;
@@ -89,7 +108,9 @@
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 36a313a..d93f370 100644
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -21,24 +21,36 @@
} // 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 7b580c6..1273352 100644
--- a/services/vr/hardware_composer/vr_composer.h
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -20,7 +20,7 @@
public ComposerView::Observer,
public IBinder::DeathRecipient {
public:
- VrComposer();
+ explicit VrComposer(ComposerView* composer_view);
~VrComposer() override;
// BnVrComposer:
@@ -40,6 +40,8 @@
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 e36b0ae..7701847 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 @@
"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 @@
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 4b9fbe0..4c26671 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -22,13 +22,15 @@
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 @@
// 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 @@
{.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 @@
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 @@
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 b28d94a..6b519ab 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -44,13 +44,13 @@
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 @@
}
};
- 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 274a1b3..4065785 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 @@
}
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 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 @@
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 @@
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 @@
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 1175a7b..c2f078e 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -48,15 +48,18 @@
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));
+ task_id, strerror(error));
- 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_);
+ 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 069fb36..a346c0a 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -430,6 +430,8 @@
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: