diff options
155 files changed, 4621 insertions, 1784 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..03af56d640 --- /dev/null +++ b/.clang-format @@ -0,0 +1,13 @@ +BasedOnStyle: Google + +AccessModifierOffset: -4 +AlignOperands: false +AllowShortFunctionsOnASingleLine: Inline +AlwaysBreakBeforeMultilineStrings: false +ColumnLimit: 100 +CommentPragmas: NOLINT:.* +ConstructorInitializerIndentWidth: 6 +ContinuationIndentWidth: 8 +IndentWidth: 4 +PenaltyBreakBeforeFirstCallParameter: 100000 +SpacesBeforeTrailingComments: 1 diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index aa03709d41..8eefaba0ae 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -820,28 +820,33 @@ static void DoLogcat() { if (timeout < 20000) { timeout = 20000; } - RunCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"}, + RunCommand("SYSTEM LOG", + {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", + "-d", "*:v"}, CommandOptions::WithTimeout(timeout / 1000).Build()); timeout = logcat_timeout("events"); if (timeout < 20000) { timeout = 20000; } RunCommand("EVENT LOG", - {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"}, + {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", + "-d", "*:v"}, CommandOptions::WithTimeout(timeout / 1000).Build()); timeout = logcat_timeout("radio"); if (timeout < 20000) { timeout = 20000; } RunCommand("RADIO LOG", - {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"}, + {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", + "-d", "*:v"}, CommandOptions::WithTimeout(timeout / 1000).Build()); RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"}); /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */ RunCommand("LAST LOGCAT", - {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"}); + {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-v", "uid", + "-d", "*:v"}); } static void DumpIpTables() { diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 381e90c117..20b960d218 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -88,6 +88,7 @@ static constexpr int FLAG_USE_QUOTA = 1 << 12; static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13; static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14; static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15; +static constexpr int FLAG_FORCE = 1 << 16; namespace { @@ -289,6 +290,46 @@ static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t ui return 0; } +/** + * Ensure that we have a hard-limit quota to protect against abusive apps; + * they should never use more than 90% of blocks or 50% of inodes. + */ +static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device, + uid_t uid) { + if (device.empty()) return 0; + + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, + reinterpret_cast<char*>(&dq)) != 0) { + PLOG(WARNING) << "Failed to find quota for " << uid; + return -1; + } + + if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) { + auto path = create_data_path(uuid ? uuid->c_str() : nullptr); + struct statvfs stat; + if (statvfs(path.c_str(), &stat) != 0) { + PLOG(WARNING) << "Failed to statvfs " << path; + return -1; + } + + dq.dqb_valid = QIF_LIMITS; + dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE; + dq.dqb_ihardlimit = (stat.f_files / 2); + if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid, + reinterpret_cast<char*>(&dq)) != 0) { + PLOG(WARNING) << "Failed to set hard quota for " << uid; + return -1; + } else { + LOG(DEBUG) << "Applied hard quotas for " << uid; + return 0; + } + } else { + // Hard quota already set; assume it's reasonable + return 0; + } +} + binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) { @@ -358,6 +399,10 @@ binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::s return error("Failed to restorecon " + path); } + if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) { + return error("Failed to set hard quota " + path); + } + if (property_get_bool("dalvik.vm.usejitprofiles", false)) { const std::string profile_dir = create_primary_current_profile_package_dir_path(userId, pkgname); @@ -556,6 +601,113 @@ binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr<std:: return res; } +static gid_t get_cache_gid(uid_t uid) { + int32_t gid = multiuser_get_cache_gid(multiuser_get_user_id(uid), multiuser_get_app_id(uid)); + return (gid != -1) ? gid : uid; +} + +binder::Status InstalldNativeService::fixupAppData(const std::unique_ptr<std::string>& uuid, + int32_t flags) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_UUID(uuid); + std::lock_guard<std::recursive_mutex> lock(mLock); + + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + for (auto user : get_known_users(uuid_)) { + ATRACE_BEGIN("fixup user"); + FTS* fts; + FTSENT* p; + char *argv[] = { + (char*) create_data_user_ce_path(uuid_, user).c_str(), + (char*) create_data_user_de_path(uuid_, user).c_str(), + nullptr + }; + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + return error("Failed to fts_open"); + } + while ((p = fts_read(fts)) != nullptr) { + if (p->fts_info == FTS_D && p->fts_level == 1) { + // Track down inodes of cache directories + uint64_t raw = 0; + ino_t inode_cache = 0; + ino_t inode_code_cache = 0; + if (getxattr(p->fts_path, kXattrInodeCache, &raw, sizeof(raw)) == sizeof(raw)) { + inode_cache = raw; + } + if (getxattr(p->fts_path, kXattrInodeCodeCache, &raw, sizeof(raw)) == sizeof(raw)) { + inode_code_cache = raw; + } + + // Figure out expected GID of each child + FTSENT* child = fts_children(fts, 0); + while (child != nullptr) { + if ((child->fts_statp->st_ino == inode_cache) + || (child->fts_statp->st_ino == inode_code_cache) + || !strcmp(child->fts_name, "cache") + || !strcmp(child->fts_name, "code_cache")) { + child->fts_number = get_cache_gid(p->fts_statp->st_uid); + } else { + child->fts_number = p->fts_statp->st_uid; + } + child = child->fts_link; + } + } else if (p->fts_level >= 2) { + if (p->fts_level > 2) { + // Inherit GID from parent once we're deeper into tree + p->fts_number = p->fts_parent->fts_number; + } + + uid_t uid = p->fts_parent->fts_statp->st_uid; + gid_t cache_gid = get_cache_gid(uid); + gid_t expected = p->fts_number; + gid_t actual = p->fts_statp->st_gid; + if (actual == expected) { +#if FIXUP_DEBUG + LOG(DEBUG) << "Ignoring " << p->fts_path << " with expected GID " << expected; +#endif + if (!(flags & FLAG_FORCE)) { + fts_set(fts, p, FTS_SKIP); + } + } else if ((actual == uid) || (actual == cache_gid)) { + // Only consider fixing up when current GID belongs to app + if (p->fts_info != FTS_D) { + LOG(INFO) << "Fixing " << p->fts_path << " with unexpected GID " << actual + << " instead of " << expected; + } + switch (p->fts_info) { + case FTS_DP: + // If we're moving towards cache GID, we need to set S_ISGID + if (expected == cache_gid) { + if (chmod(p->fts_path, 02771) != 0) { + PLOG(WARNING) << "Failed to chmod " << p->fts_path; + } + } + // Intentional fall through to also set GID + case FTS_F: + if (chown(p->fts_path, -1, expected) != 0) { + PLOG(WARNING) << "Failed to chown " << p->fts_path; + } + break; + case FTS_SL: + case FTS_SLNONE: + if (lchown(p->fts_path, -1, expected) != 0) { + PLOG(WARNING) << "Failed to chown " << p->fts_path; + } + break; + } + } else { + // Ignore all other GID transitions, since they're kinda shady + LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected GID " << actual + << " instead of " << expected; + } + } + } + fts_close(fts); + ATRACE_END(); + } + return ok(); +} + binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid, const std::unique_ptr<std::string>& toUuid, const std::string& packageName, const std::string& dataAppName, int32_t appId, const std::string& seInfo, @@ -709,6 +861,14 @@ binder::Status InstalldNativeService::createUserData(const std::unique_ptr<std:: } } } + + // Data under /data/media doesn't have an app, but we still want + // to limit it to prevent abuse. + if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), + multiuser_get_uid(userId, AID_MEDIA_RW))) { + return error("Failed to set hard quota for media_rw"); + } + return ok(); } @@ -2006,6 +2166,17 @@ binder::Status InstalldNativeService::invalidateMounts() { reinterpret_cast<char*>(&dq)) == 0) { LOG(DEBUG) << "Found " << source << " with quota"; mQuotaDevices[target] = source; + + // ext4 only enables DQUOT_USAGE_ENABLED by default, so we + // need to kick it again to enable DQUOT_LIMITS_ENABLED. + if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0 + && errno != EBUSY) { + PLOG(ERROR) << "Failed to enable USRQUOTA on " << source; + } + if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0 + && errno != EBUSY) { + PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source; + } } } } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 7ad86878ca..f5b7142a12 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -58,6 +58,8 @@ public: binder::Status destroyAppData(const std::unique_ptr<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode); + binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags); + binder::Status getAppSize(const std::unique_ptr<std::string>& uuid, const std::vector<std::string>& packageNames, int32_t userId, int32_t flags, int32_t appId, const std::vector<int64_t>& ceDataInodes, diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 4195a0128c..03ff96e866 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -32,6 +32,8 @@ interface IInstalld { void destroyAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName, int userId, int flags, long ceDataInode); + void fixupAppData(@nullable @utf8InCpp String uuid, int flags); + long[] getAppSize(@nullable @utf8InCpp String uuid, in @utf8InCpp String[] packageNames, int userId, int flags, int appId, in long[] ceDataInodes, in @utf8InCpp String[] codePaths); diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp index b5b080d263..630c1f3652 100644 --- a/cmds/installd/tests/Android.bp +++ b/cmds/installd/tests/Android.bp @@ -33,3 +33,22 @@ cc_test { "libdiskusage", ], } + +cc_test { + name: "installd_service_test", + clang: true, + srcs: ["installd_service_test.cpp"], + shared_libs: [ + "libbase", + "libbinder", + "libcutils", + "liblog", + "liblogwrap", + "libselinux", + "libutils", + ], + static_libs: [ + "libinstalld", + "libdiskusage", + ], +} diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp index 360f71aaf5..174ce77026 100644 --- a/cmds/installd/tests/installd_cache_test.cpp +++ b/cmds/installd/tests/installd_cache_test.cpp @@ -99,7 +99,7 @@ static int64_t size(const char* path) { static int64_t free() { struct statvfs buf; if (!statvfs("/data/local/tmp", &buf)) { - return buf.f_bavail * buf.f_bsize; + return buf.f_bavail * buf.f_frsize; } else { PLOG(ERROR) << "Failed to statvfs"; return -1; diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp new file mode 100644 index 0000000000..4a1f333bae --- /dev/null +++ b/cmds/installd/tests/installd_service_test.cpp @@ -0,0 +1,155 @@ +/* + * 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 <stdlib.h> +#include <string.h> +#include <sys/statvfs.h> +#include <sys/xattr.h> + +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include <cutils/properties.h> +#include <gtest/gtest.h> + +#include "InstalldNativeService.h" +#include "globals.h" +#include "utils.h" + +using android::base::StringPrintf; + +namespace android { +namespace installd { + +constexpr const char* kTestUuid = "TEST"; + +static constexpr int FLAG_FORCE = 1 << 16; + +int get_property(const char *key, char *value, const char *default_value) { + return property_get(key, value, default_value); +} + +bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED, + const char *oat_dir ATTRIBUTE_UNUSED, + const char *apk_path ATTRIBUTE_UNUSED, + const char *instruction_set ATTRIBUTE_UNUSED) { + return false; +} + +bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED, + const char *apk_path ATTRIBUTE_UNUSED, + const char *instruction_set ATTRIBUTE_UNUSED) { + return false; +} + +bool create_cache_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED, + const char *src ATTRIBUTE_UNUSED, + const char *instruction_set ATTRIBUTE_UNUSED) { + return false; +} + +static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) { + const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str(); + ::mkdir(fullPath, mode); + ::chown(fullPath, owner, group); + ::chmod(fullPath, mode); +} + +static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) { + int fd = ::open(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), + O_RDWR | O_CREAT, mode); + ::fchown(fd, owner, group); + ::fchmod(fd, mode); + ::close(fd); +} + +static int stat_gid(const char* path) { + struct stat buf; + ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf); + return buf.st_gid; +} + +static int stat_mode(const char* path) { + struct stat buf; + ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf); + return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID); +} + +class ServiceTest : public testing::Test { +protected: + InstalldNativeService* service; + std::unique_ptr<std::string> testUuid; + + virtual void SetUp() { + setenv("ANDROID_LOG_TAGS", "*:v", 1); + android::base::InitLogging(nullptr); + + service = new InstalldNativeService(); + testUuid = std::make_unique<std::string>(); + *testUuid = std::string(kTestUuid); + system("mkdir -p /data/local/tmp/user/0"); + } + + virtual void TearDown() { + delete service; + system("rm -rf /data/local/tmp/user"); + } +}; + +TEST_F(ServiceTest, FixupAppData_Upgrade) { + LOG(INFO) << "FixupAppData_Upgrade"; + + mkdir("com.example", 10000, 10000, 0700); + mkdir("com.example/normal", 10000, 10000, 0700); + mkdir("com.example/cache", 10000, 10000, 0700); + touch("com.example/cache/file", 10000, 10000, 0700); + + service->fixupAppData(testUuid, 0); + + EXPECT_EQ(10000, stat_gid("com.example/normal")); + EXPECT_EQ(20000, stat_gid("com.example/cache")); + EXPECT_EQ(20000, stat_gid("com.example/cache/file")); + + EXPECT_EQ(0700, stat_mode("com.example/normal")); + EXPECT_EQ(02771, stat_mode("com.example/cache")); + EXPECT_EQ(0700, stat_mode("com.example/cache/file")); +} + +TEST_F(ServiceTest, FixupAppData_Moved) { + LOG(INFO) << "FixupAppData_Moved"; + + mkdir("com.example", 10000, 10000, 0700); + mkdir("com.example/foo", 10000, 10000, 0700); + touch("com.example/foo/file", 10000, 20000, 0700); + mkdir("com.example/bar", 10000, 20000, 0700); + touch("com.example/bar/file", 10000, 20000, 0700); + + service->fixupAppData(testUuid, 0); + + EXPECT_EQ(10000, stat_gid("com.example/foo")); + EXPECT_EQ(20000, stat_gid("com.example/foo/file")); + EXPECT_EQ(10000, stat_gid("com.example/bar")); + EXPECT_EQ(10000, stat_gid("com.example/bar/file")); + + service->fixupAppData(testUuid, FLAG_FORCE); + + EXPECT_EQ(10000, stat_gid("com.example/foo")); + EXPECT_EQ(10000, stat_gid("com.example/foo/file")); + EXPECT_EQ(10000, stat_gid("com.example/bar")); + EXPECT_EQ(10000, stat_gid("com.example/bar/file")); +} + +} // namespace installd +} // namespace android diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index fbe6edf712..c7920821c6 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -629,11 +629,10 @@ int copy_dir_files(const char *srcname, return res; } -int64_t data_disk_free(const std::string& data_path) -{ +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_bsize; + return sfs.f_bavail * sfs.f_frsize; } else { PLOG(ERROR) << "Couldn't statvfs " << data_path; return -1; @@ -1030,6 +1029,10 @@ int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t ta } else if (st.st_gid == gid && actual_mode == target_mode) { // Everything looks good! return 0; + } else { + // Mismatched GID/mode is recoverable; fall through to update + LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid + << " but expected " << gid; } // Directory is owned correctly, but GID or mode mismatch means it's @@ -1044,18 +1047,18 @@ int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t ta while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { case FTS_DP: - if (chmod(p->fts_accpath, target_mode) != 0) { + if (chmod(p->fts_path, target_mode) != 0) { PLOG(WARNING) << "Failed to chmod " << p->fts_path; } // Intentional fall through to also set GID case FTS_F: - if (chown(p->fts_accpath, -1, gid) != 0) { + if (chown(p->fts_path, -1, gid) != 0) { PLOG(WARNING) << "Failed to chown " << p->fts_path; } break; case FTS_SL: case FTS_SLNONE: - if (lchown(p->fts_accpath, -1, gid) != 0) { + if (lchown(p->fts_path, -1, gid) != 0) { PLOG(WARNING) << "Failed to chown " << p->fts_path; } break; diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 7ebfea213c..dd94da9e31 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -31,6 +31,7 @@ #include <installd_constants.h> #define MEASURE_DEBUG 0 +#define FIXUP_DEBUG 0 namespace android { namespace installd { diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 5431233b27..68d39dbb52 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -43,6 +43,9 @@ cc_binary { "service_manager.c", "binder.c", ], + cflags: [ + "-DVENDORSERVICEMANAGER=1", + ], shared_libs: ["libcutils", "libselinux"], init_rc: ["vndservicemanager.rc"], } diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index 5d44e87245..45bb1d05e8 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -17,13 +17,12 @@ #include "binder.h" -#if 0 -#define ALOGI(x...) fprintf(stderr, "svcmgr: " x) -#define ALOGE(x...) fprintf(stderr, "svcmgr: " x) +#ifdef VENDORSERVICEMANAGER +#define LOG_TAG "VendorServiceManager" #else #define LOG_TAG "ServiceManager" -#include <log/log.h> #endif +#include <log/log.h> struct audit_data { pid_t pid; @@ -374,7 +373,14 @@ int main(int argc, char** argv) bs = binder_open(driver, 128*1024); if (!bs) { +#ifdef VENDORSERVICEMANAGER + ALOGW("failed to open binder driver %s\n", driver); + while (true) { + sleep(UINT_MAX); + } +#else ALOGE("failed to open binder driver %s\n", driver); +#endif return -1; } @@ -388,7 +394,11 @@ int main(int argc, char** argv) cb.func_log = selinux_log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); +#ifdef VENDORSERVICEMANAGER + sehandle = selinux_android_vendor_service_context_handle(); +#else sehandle = selinux_android_service_context_handle(); +#endif selinux_status_open(true); if (sehandle == NULL) { diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc index aee7bd825e..aec211abac 100644 --- a/cmds/servicemanager/servicemanager.rc +++ b/cmds/servicemanager/servicemanager.rc @@ -1,5 +1,5 @@ service servicemanager /system/bin/servicemanager - class core + class core animation user system group system readproc critical @@ -12,4 +12,3 @@ service servicemanager /system/bin/servicemanager onrestart restart drm onrestart restart cameraserver writepid /dev/cpuset/system-background/tasks - diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h index 1ec2a67c3d..23b39aa41f 100644 --- a/include/android/native_window_jni.h +++ b/include/android/native_window_jni.h @@ -54,6 +54,17 @@ ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); ANativeWindow* ANativeWindow_fromSurfaceTexture(JNIEnv* env, jobject surfaceTexture); #endif +#if __ANDROID_API__ >= 26 +/** + * Return a Java Surface object derived from the ANativeWindow, for interacting + * with it through Java code. The returned Java object acquires a reference on + * the ANativeWindow; maintains it through general Java object's life cycle; + * and will automatically release the reference when the Java object gets garbage + * collected. + */ +jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window); +#endif + #ifdef __cplusplus }; #endif diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h index 1f4387d7c2..a680bc67c4 100644 --- a/include/gui/ISurfaceComposerClient.h +++ b/include/gui/ISurfaceComposerClient.h @@ -14,55 +14,52 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H -#define ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/RefBase.h> +#pragma once #include <binder/IInterface.h> - -#include <ui/FrameStats.h> +#include <binder/SafeInterface.h> #include <ui/PixelFormat.h> namespace android { -// ---------------------------------------------------------------------------- +class FrameStats; class IGraphicBufferProducer; -class ISurfaceComposerClient : public IInterface -{ +class ISurfaceComposerClient : public IInterface { public: DECLARE_META_INTERFACE(SurfaceComposerClient) + enum class Tag : uint32_t { + CreateSurface = IBinder::FIRST_CALL_TRANSACTION, + DestroySurface, + ClearLayerFrameStats, + GetLayerFrameStats, + Last, + }; + // flags for createSurface() enum { // (keep in sync with Surface.java) - eHidden = 0x00000004, - eDestroyBackbuffer = 0x00000020, - eSecure = 0x00000080, - eNonPremultiplied = 0x00000100, - eOpaque = 0x00000400, - eProtectedByApp = 0x00000800, - eProtectedByDRM = 0x00001000, - eCursorWindow = 0x00002000, - - eFXSurfaceNormal = 0x00000000, - eFXSurfaceDim = 0x00020000, - eFXSurfaceMask = 0x000F0000, + eHidden = 0x00000004, + eDestroyBackbuffer = 0x00000020, + eSecure = 0x00000080, + eNonPremultiplied = 0x00000100, + eOpaque = 0x00000400, + eProtectedByApp = 0x00000800, + eProtectedByDRM = 0x00001000, + eCursorWindow = 0x00002000, + + eFXSurfaceNormal = 0x00000000, + eFXSurfaceDim = 0x00020000, + eFXSurfaceMask = 0x000F0000, }; /* * Requires ACCESS_SURFACE_FLINGER permission */ - virtual status_t createSurface( - const String8& name, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, - const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid, - sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp) = 0; + virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, + uint32_t flags, const sp<IBinder>& parent, uint32_t windowType, + uint32_t ownerUid, sp<IBinder>* handle, + sp<IGraphicBufferProducer>* gbp) = 0; /* * Requires ACCESS_SURFACE_FLINGER permission @@ -78,21 +75,14 @@ public: * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0; - - virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle, - bool* outTransformToDisplayInverse) const = 0; }; -// ---------------------------------------------------------------------------- - -class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient> { +class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> { public: - virtual status_t onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags = 0); -}; + BnSurfaceComposerClient() + : SafeBnInterface<ISurfaceComposerClient>("BnSurfaceComposerClient") {} -// ---------------------------------------------------------------------------- - -}; // namespace android + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override; +}; -#endif // ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H +} // namespace android diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 62f6cadece..88ef010368 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -257,10 +257,25 @@ public: virtual int query(int what, int* value) const; virtual int connect(int api, const sp<IProducerListener>& listener); + + // When reportBufferRemoval is true, clients must call getAndFlushRemovedBuffers to fetch + // GraphicBuffers removed from this surface after a dequeueBuffer, detachNextBuffer or + // attachBuffer call. This allows clients with their own buffer caches to free up buffers no + // longer in use by this surface. + virtual int connect( + int api, const sp<IProducerListener>& listener, + bool reportBufferRemoval); virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); virtual int attachBuffer(ANativeWindowBuffer*); + // When client connects to Surface with reportBufferRemoval set to true, any buffers removed + // from this Surface will be collected and returned here. Once this method returns, these + // buffers will no longer be referenced by this Surface unless they are attached to this + // Surface later. The list of removed buffers will only be stored until the next dequeueBuffer, + // detachNextBuffer, or attachBuffer call. + status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out); + protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; @@ -414,6 +429,9 @@ protected: // A cached copy of the FrameEventHistory maintained by the consumer. bool mEnableFrameTimestamps = false; std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory; + + bool mReportRemovedBuffers = false; + std::vector<sp<GraphicBuffer>> mRemovedBuffers; }; } // namespace android diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h index 1e8cf76627..394425a328 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/include/gui/SurfaceComposerClient.h @@ -169,9 +169,6 @@ public: status_t clearLayerFrameStats(const sp<IBinder>& token) const; status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const; - status_t getTransformToDisplayInverse(const sp<IBinder>& token, - bool* outTransformToDisplayInverse) const; - static status_t clearAnimationFrameStats(); static status_t getAnimationFrameStats(FrameStats* outStats); diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h index 8ee35bc495..3cff7df260 100644 --- a/include/gui/SurfaceControl.h +++ b/include/gui/SurfaceControl.h @@ -119,8 +119,6 @@ public: status_t clearLayerFrameStats() const; status_t getLayerFrameStats(FrameStats* outStats) const; - status_t getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const; - private: // can't be copied SurfaceControl& operator = (SurfaceControl& rhs); diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index 040d1e7bac..af1d8be8b3 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -72,30 +72,69 @@ public: USAGE_CURSOR = GRALLOC_USAGE_CURSOR, }; - GraphicBuffer(); + static sp<GraphicBuffer> from(ANativeWindowBuffer *); - // creates w * h buffer - GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, - uint32_t inUsage, std::string requestorName = "<Unknown>"); - // creates w * h buffer with a layer count using gralloc1 + // Create a GraphicBuffer to be unflatten'ed into or be reallocated. + GraphicBuffer(); + + // Create a GraphicBuffer by allocating and managing a buffer internally. + // This function is privileged. See reallocate for details. GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inProducerUsage, uint64_t inConsumerUsage, std::string requestorName = "<Unknown>"); - // create a buffer from an existing handle + // Create a GraphicBuffer from an existing handle. + enum HandleWrapMethod : uint8_t { + // Wrap and use the handle directly. It assumes the handle has been + // registered and never fails. The handle must have a longer lifetime + // than this wrapping GraphicBuffer. + // + // This can be used when, for example, you want to wrap a handle that + // is already managed by another GraphicBuffer. + WRAP_HANDLE, + + // Take ownership of the handle and use it directly. It assumes the + // handle has been registered and never fails. + // + // This can be used to manage an already registered handle with + // GraphicBuffer. + TAKE_HANDLE, + + // Take onwership of an unregistered handle and use it directly. It + // can fail when the buffer does not register. There is no ownership + // transfer on failures. + // + // This can be used to, for example, create a GraphicBuffer from a + // handle returned by Parcel::readNativeHandle. + TAKE_UNREGISTERED_HANDLE, + + // Make a clone of the handle and use the cloned handle. It can fail + // when cloning fails or when the buffer does not register. There is + // never ownership transfer. + // + // This can be used to create a GraphicBuffer from a handle that + // cannot be used directly, such as one from hidl_handle. + CLONE_HANDLE, + }; + GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method, + uint32_t width, uint32_t height, + PixelFormat format, uint32_t layerCount, + uint64_t producerUsage, uint64_t consumerUsage, uint32_t stride); + + // These functions are deprecated because they do not distinguish producer + // and consumer usages. + GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method, + uint32_t width, uint32_t height, + PixelFormat format, uint32_t layerCount, + uint32_t usage, uint32_t stride) + : GraphicBuffer(handle, method, width, height, format, layerCount, + usage, usage, stride) {} GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle, bool keepOwnership); - - // create a buffer from an existing handle using gralloc1 GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, - uint32_t inLayerCount, uint32_t inProducerUsage, - uint32_t inConsumerUsage, uint32_t inStride, - native_handle_t* inHandle, bool keepOwnership); - - // create a buffer from an existing ANativeWindowBuffer - GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership); + uint32_t inUsage, std::string requestorName = "<Unknown>"); // return status status_t initCheck() const; @@ -114,6 +153,9 @@ public: mGenerationNumber = generation; } + // This function is privileged. It requires access to the allocator + // device or service, which usually involves adding suitable selinux + // rules. status_t reallocate(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage); @@ -175,19 +217,21 @@ private: GraphicBuffer& operator = (const GraphicBuffer& rhs); const GraphicBuffer& operator = (const GraphicBuffer& rhs) const; - status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, - uint32_t inLayerCount, uint64_t inProducerUsage, - uint64_t inConsumerUsage, std::string requestorName); + status_t initWithSize(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inLayerCount, + uint64_t inProducerUsage, uint64_t inConsumerUsage, + std::string requestorName); + + status_t initWithHandle(const native_handle_t* handle, + HandleWrapMethod method, uint32_t width, uint32_t height, + PixelFormat format, uint32_t layerCount, + uint64_t producerUsage, uint64_t consumerUsage, uint32_t stride); void free_handle(); GraphicBufferMapper& mBufferMapper; ssize_t mInitCheck; - // If we're wrapping another buffer then this reference will make sure it - // doesn't get freed. - sp<ANativeWindowBuffer> mWrappedBuffer; - uint64_t mId; // Stores the generation number of this buffer. If this number does not diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 93b8684ec4..b225128618 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -71,6 +71,10 @@ cc_library { "libutils", ], + export_include_dirs: [ + "include", + ], + clang: true, sanitize: { misc_undefined: ["integer"], diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h new file mode 100644 index 0000000000..0e723c59ee --- /dev/null +++ b/libs/binder/include/binder/SafeInterface.h @@ -0,0 +1,621 @@ +/* + * Copyright 2016 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/IInterface.h> +#include <binder/Parcel.h> +#include <cutils/compiler.h> + +// Set to 1 to enable CallStacks when logging errors +#define SI_DUMP_CALLSTACKS 0 +#if SI_DUMP_CALLSTACKS +#include <utils/CallStack.h> +#endif + +#include <functional> +#include <type_traits> + +namespace android { +namespace SafeInterface { + +// ParcelHandler is responsible for writing/reading various types to/from a Parcel in a generic way +class ParcelHandler { +public: + explicit ParcelHandler(const char* logTag) : mLogTag(logTag) {} + + // Specializations for types with dedicated handling in Parcel + status_t read(const Parcel& parcel, bool* b) const { + return callParcel("readBool", [&]() { return parcel.readBool(b); }); + } + status_t write(Parcel* parcel, bool b) const { + return callParcel("writeBool", [&]() { return parcel->writeBool(b); }); + } + template <typename T> + typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read( + const Parcel& parcel, T* t) const { + return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); }); + } + template <typename T> + typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type write( + Parcel* parcel, const T& t) const { + return callParcel("write(LightFlattenable)", [&]() { return parcel->write(t); }); + } + template <typename T> + typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read( + const Parcel& parcel, T* t) const { + return callParcel("readParcelable", [&]() { return parcel.readParcelable(t); }); + } + template <typename T> + typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write( + Parcel* parcel, const T& t) const { + return callParcel("writeParcelable", [&]() { return parcel->writeParcelable(t); }); + } + status_t read(const Parcel& parcel, String8* str) const { + return callParcel("readString8", [&]() { return parcel.readString8(str); }); + } + status_t write(Parcel* parcel, const String8& str) const { + return callParcel("writeString8", [&]() { return parcel->writeString8(str); }); + } + template <typename T> + status_t read(const Parcel& parcel, sp<T>* pointer) const { + return callParcel("readNullableStrongBinder", + [&]() { return parcel.readNullableStrongBinder(pointer); }); + } + template <typename T> + typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type write( + Parcel* parcel, const sp<T>& pointer) const { + return callParcel("writeStrongBinder", + [&]() { return parcel->writeStrongBinder(pointer); }); + } + template <typename T> + typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write( + Parcel* parcel, const sp<T>& interface) const { + return write(parcel, IInterface::asBinder(interface)); + } + + // Templates to handle integral types. We use a struct template to require that the called + // function exactly matches the signedness and size of the argument (e.g., the argument isn't + // silently widened). + template <bool isSigned, size_t size, typename I> + struct HandleInt; + template <typename I> + struct HandleInt<true, 4, I> { + static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) { + return handler.callParcel("readInt32", [&]() { return parcel.readInt32(i); }); + } + static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) { + return handler.callParcel("writeInt32", [&]() { return parcel->writeInt32(i); }); + } + }; + template <typename I> + struct HandleInt<false, 4, I> { + static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) { + return handler.callParcel("readUint32", [&]() { return parcel.readUint32(i); }); + } + static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) { + return handler.callParcel("writeUint32", [&]() { return parcel->writeUint32(i); }); + } + }; + template <typename I> + typename std::enable_if<std::is_integral<I>::value, status_t>::type read(const Parcel& parcel, + I* i) const { + return HandleInt<std::is_signed<I>::value, sizeof(I), I>::read(*this, parcel, i); + } + template <typename I> + typename std::enable_if<std::is_integral<I>::value, status_t>::type write(Parcel* parcel, + I i) const { + return HandleInt<std::is_signed<I>::value, sizeof(I), I>::write(*this, parcel, i); + } + +private: + const char* const mLogTag; + + // Helper to encapsulate error handling while calling the various Parcel methods + template <typename Function> + status_t callParcel(const char* name, Function f) const { + status_t error = f(); + if (CC_UNLIKELY(error != NO_ERROR)) { + ALOG(LOG_ERROR, mLogTag, "Failed to %s, (%d: %s)", name, error, strerror(-error)); +#if SI_DUMP_CALLSTACKS + CallStack callStack(mLogTag); +#endif + } + return error; + } +}; + +// Utility struct template which allows us to retrieve the types of the parameters of a member +// function pointer +template <typename T> +struct ParamExtractor; +template <typename Class, typename Return, typename... Params> +struct ParamExtractor<Return (Class::*)(Params...)> { + using ParamTuple = std::tuple<Params...>; +}; +template <typename Class, typename Return, typename... Params> +struct ParamExtractor<Return (Class::*)(Params...) const> { + using ParamTuple = std::tuple<Params...>; +}; + +} // namespace SafeInterface + +template <typename Interface> +class SafeBpInterface : public BpInterface<Interface> { +protected: + SafeBpInterface(const sp<IBinder>& impl, const char* logTag) + : BpInterface<Interface>(impl), mLogTag(logTag) {} + ~SafeBpInterface() override = default; + + // callRemote is used to invoke a synchronous procedure call over Binder + template <typename Method, typename TagType, typename... Args> + status_t callRemote(TagType tag, Args&&... args) const { + static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t"); + + // Verify that the arguments are compatible with the parameters + using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple; + static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value, + "Invalid argument type"); + + // Write the input arguments to the data Parcel + Parcel data; + data.writeInterfaceToken(this->getInterfaceDescriptor()); + + status_t error = writeInputs(&data, std::forward<Args>(args)...); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged by writeInputs + return error; + } + + // Send the data Parcel to the remote and retrieve the reply parcel + Parcel reply; + error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply); + if (CC_UNLIKELY(error != NO_ERROR)) { + ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error); +#if SI_DUMP_CALLSTACKS + CallStack callStack(mLogTag); +#endif + return error; + } + + // Read the outputs from the reply Parcel into the output arguments + error = readOutputs(reply, std::forward<Args>(args)...); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged by readOutputs + return error; + } + + // Retrieve the result code from the reply Parcel + status_t result = NO_ERROR; + error = reply.readInt32(&result); + if (CC_UNLIKELY(error != NO_ERROR)) { + ALOG(LOG_ERROR, mLogTag, "Failed to obtain result"); +#if SI_DUMP_CALLSTACKS + CallStack callStack(mLogTag); +#endif + return error; + } + return result; + } + + // callRemoteAsync is used to invoke an asynchronous procedure call over Binder + template <typename Method, typename TagType, typename... Args> + void callRemoteAsync(TagType tag, Args&&... args) const { + static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t"); + + // Verify that the arguments are compatible with the parameters + using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple; + static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value, + "Invalid argument type"); + + // Write the input arguments to the data Parcel + Parcel data; + data.writeInterfaceToken(this->getInterfaceDescriptor()); + status_t error = writeInputs(&data, std::forward<Args>(args)...); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged by writeInputs + return; + } + + // There will be no data in the reply Parcel since the call is one-way + Parcel reply; + error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply, + IBinder::FLAG_ONEWAY); + if (CC_UNLIKELY(error != NO_ERROR)) { + ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error); +#if SI_DUMP_CALLSTACKS + CallStack callStack(mLogTag); +#endif + } + } + +private: + const char* const mLogTag; + + // This struct provides information on whether the decayed types of the elements at Index in the + // tuple types T and U (that is, the types after stripping cv-qualifiers, removing references, + // and a few other less common operations) are the same + template <size_t Index, typename T, typename U> + struct DecayedElementsMatch { + private: + using FirstT = typename std::tuple_element<Index, T>::type; + using DecayedT = typename std::decay<FirstT>::type; + using FirstU = typename std::tuple_element<Index, U>::type; + using DecayedU = typename std::decay<FirstU>::type; + + public: + static constexpr bool value = std::is_same<DecayedT, DecayedU>::value; + }; + + // When comparing whether the argument types match the parameter types, we first decay them (see + // DecayedElementsMatch) to avoid falsely flagging, say, T&& against T even though they are + // equivalent enough for our purposes + template <typename T, typename U> + struct ArgsMatchParams {}; + template <typename... Args, typename... Params> + struct ArgsMatchParams<std::tuple<Args...>, std::tuple<Params...>> { + static_assert(sizeof...(Args) <= sizeof...(Params), "Too many arguments"); + static_assert(sizeof...(Args) >= sizeof...(Params), "Not enough arguments"); + + private: + template <size_t Index> + static constexpr typename std::enable_if<(Index < sizeof...(Args)), bool>::type + elementsMatch() { + if (!DecayedElementsMatch<Index, std::tuple<Args...>, std::tuple<Params...>>::value) { + return false; + } + return elementsMatch<Index + 1>(); + } + template <size_t Index> + static constexpr typename std::enable_if<(Index >= sizeof...(Args)), bool>::type + elementsMatch() { + return true; + } + + public: + static constexpr bool value = elementsMatch<0>(); + }; + + // Since we assume that pointer arguments are outputs, we can use this template struct to + // determine whether or not a given argument is fundamentally a pointer type and thus an output + template <typename T> + struct IsPointerIfDecayed { + private: + using Decayed = typename std::decay<T>::type; + + public: + static constexpr bool value = std::is_pointer<Decayed>::value; + }; + + template <typename T> + typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type writeIfInput( + Parcel* data, T&& t) const { + return SafeInterface::ParcelHandler{mLogTag}.write(data, std::forward<T>(t)); + } + template <typename T> + typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type writeIfInput( + Parcel* /*data*/, T&& /*t*/) const { + return NO_ERROR; + } + + // This method iterates through all of the arguments, writing them to the data Parcel if they + // are an input (i.e., if they are not a pointer type) + template <typename T, typename... Remaining> + status_t writeInputs(Parcel* data, T&& t, Remaining&&... remaining) const { + status_t error = writeIfInput(data, std::forward<T>(t)); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged by writeIfInput + return error; + } + return writeInputs(data, std::forward<Remaining>(remaining)...); + } + static status_t writeInputs(Parcel* /*data*/) { return NO_ERROR; } + + template <typename T> + typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type readIfOutput( + const Parcel& reply, T&& t) const { + return SafeInterface::ParcelHandler{mLogTag}.read(reply, std::forward<T>(t)); + } + template <typename T> + static typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type readIfOutput( + const Parcel& /*reply*/, T&& /*t*/) { + return NO_ERROR; + } + + // Similar to writeInputs except that it reads output arguments from the reply Parcel + template <typename T, typename... Remaining> + status_t readOutputs(const Parcel& reply, T&& t, Remaining&&... remaining) const { + status_t error = readIfOutput(reply, std::forward<T>(t)); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged by readIfOutput + return error; + } + return readOutputs(reply, std::forward<Remaining>(remaining)...); + } + static status_t readOutputs(const Parcel& /*data*/) { return NO_ERROR; } +}; + +template <typename Interface> +class SafeBnInterface : public BnInterface<Interface> { +public: + explicit SafeBnInterface(const char* logTag) : mLogTag(logTag) {} + +protected: + template <typename Method> + status_t callLocal(const Parcel& data, Parcel* reply, Method method) { + CHECK_INTERFACE(this, data, reply); + + // Since we need to both pass inputs into the call as well as retrieve outputs, we create a + // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the + // outputs. When we ultimately call into the method, we will pass the addresses of the + // output arguments instead of their tuple members directly, but the storage will live in + // the tuple. + using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple; + typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{}; + + // Read the inputs from the data Parcel into the argument tuple + status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged by read + return error; + } + + // Call the local method + status_t result = MethodCaller<ParamTuple>::call(this, method, &rawArgs); + + // Extract the outputs from the argument tuple and write them into the reply Parcel + error = OutputWriter<ParamTuple>{mLogTag}.writeOutputs(reply, &rawArgs); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged by write + return error; + } + + // Return the result code in the reply Parcel + error = reply->writeInt32(result); + if (CC_UNLIKELY(error != NO_ERROR)) { + ALOG(LOG_ERROR, mLogTag, "Failed to write result"); +#if SI_DUMP_CALLSTACKS + CallStack callStack(mLogTag); +#endif + return error; + } + return NO_ERROR; + } + + template <typename Method> + status_t callLocalAsync(const Parcel& data, Parcel* /*reply*/, Method method) { + // reply is not actually used by CHECK_INTERFACE + CHECK_INTERFACE(this, data, reply); + + // Since we need to both pass inputs into the call as well as retrieve outputs, we create a + // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the + // outputs. When we ultimately call into the method, we will pass the addresses of the + // output arguments instead of their tuple members directly, but the storage will live in + // the tuple. + using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple; + typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{}; + + // Read the inputs from the data Parcel into the argument tuple + status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged by read + return error; + } + + // Call the local method + MethodCaller<ParamTuple>::callVoid(this, method, &rawArgs); + + // After calling, there is nothing more to do since asynchronous calls do not return a value + // to the caller + return NO_ERROR; + } + +private: + const char* const mLogTag; + + // RemoveFirst strips the first element from a tuple. + // For example, given T = std::tuple<A, B, C>, RemoveFirst<T>::type = std::tuple<B, C> + template <typename T, typename... Args> + struct RemoveFirst; + template <typename T, typename... Args> + struct RemoveFirst<std::tuple<T, Args...>> { + using type = std::tuple<Args...>; + }; + + // RawConverter strips a tuple down to its fundamental types, discarding both pointers and + // references. This allows us to allocate storage for both input (non-pointer) arguments and + // output (pointer) arguments in one tuple. + // For example, given T = std::tuple<const A&, B*>, RawConverter<T>::type = std::tuple<A, B> + template <typename Unconverted, typename... Converted> + struct RawConverter; + template <typename Unconverted, typename... Converted> + struct RawConverter<std::tuple<Converted...>, Unconverted> { + private: + using ElementType = typename std::tuple_element<0, Unconverted>::type; + using Decayed = typename std::decay<ElementType>::type; + using WithoutPointer = typename std::remove_pointer<Decayed>::type; + + public: + using type = typename RawConverter<std::tuple<Converted..., WithoutPointer>, + typename RemoveFirst<Unconverted>::type>::type; + }; + template <typename... Converted> + struct RawConverter<std::tuple<Converted...>, std::tuple<>> { + using type = std::tuple<Converted...>; + }; + + // This provides a simple way to determine whether the indexed element of Args... is a pointer + template <size_t I, typename... Args> + struct ElementIsPointer { + private: + using ElementType = typename std::tuple_element<I, std::tuple<Args...>>::type; + + public: + static constexpr bool value = std::is_pointer<ElementType>::value; + }; + + // This class iterates over the parameter types, and if a given parameter is an input + // (i.e., is not a pointer), reads the corresponding argument tuple element from the data Parcel + template <typename... Params> + class InputReader; + template <typename... Params> + class InputReader<std::tuple<Params...>> { + public: + explicit InputReader(const char* logTag) : mLogTag(logTag) {} + + // Note that in this case (as opposed to in SafeBpInterface), we iterate using an explicit + // index (starting with 0 here) instead of using recursion and stripping the first element. + // This is because in SafeBpInterface we aren't actually operating on a real tuple, but are + // instead just using a tuple as a convenient container for variadic types, whereas here we + // can't modify the argument tuple without causing unnecessary copies or moves of the data + // contained therein. + template <typename RawTuple> + status_t readInputs(const Parcel& data, RawTuple* args) { + return dispatchArg<0>(data, args); + } + + private: + const char* const mLogTag; + + template <std::size_t I, typename RawTuple> + typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type readIfInput( + const Parcel& data, RawTuple* args) { + return SafeInterface::ParcelHandler{mLogTag}.read(data, &std::get<I>(*args)); + } + template <std::size_t I, typename RawTuple> + typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type readIfInput( + const Parcel& /*data*/, RawTuple* /*args*/) { + return NO_ERROR; + } + + // Recursively iterate through the arguments + template <std::size_t I, typename RawTuple> + typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg( + const Parcel& data, RawTuple* args) { + status_t error = readIfInput<I>(data, args); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged in read + return error; + } + return dispatchArg<I + 1>(data, args); + } + template <std::size_t I, typename RawTuple> + typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg( + const Parcel& /*data*/, RawTuple* /*args*/) { + return NO_ERROR; + } + }; + + // getForCall uses the types of the parameters to determine whether a given element of the + // argument tuple is an input, which should be passed directly into the call, or an output, for + // which its address should be passed into the call + template <size_t I, typename RawTuple, typename... Params> + static typename std::enable_if< + ElementIsPointer<I, Params...>::value, + typename std::tuple_element<I, std::tuple<Params...>>::type>::type + getForCall(RawTuple* args) { + return &std::get<I>(*args); + } + template <size_t I, typename RawTuple, typename... Params> + static typename std::enable_if< + !ElementIsPointer<I, Params...>::value, + typename std::tuple_element<I, std::tuple<Params...>>::type>::type& + getForCall(RawTuple* args) { + return std::get<I>(*args); + } + + // This template class uses std::index_sequence and parameter pack expansion to call the given + // method using the elements of the argument tuple (after those arguments are passed through + // getForCall to get addresses instead of values for output arguments) + template <typename... Params> + struct MethodCaller; + template <typename... Params> + struct MethodCaller<std::tuple<Params...>> { + public: + // The calls through these to the helper methods are necessary to generate the + // std::index_sequences used to unpack the argument tuple into the method call + template <typename Class, typename MemberFunction, typename RawTuple> + static status_t call(Class* instance, MemberFunction function, RawTuple* args) { + return callHelper(instance, function, args, std::index_sequence_for<Params...>{}); + } + template <typename Class, typename MemberFunction, typename RawTuple> + static void callVoid(Class* instance, MemberFunction function, RawTuple* args) { + callVoidHelper(instance, function, args, std::index_sequence_for<Params...>{}); + } + + private: + template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I> + static status_t callHelper(Class* instance, MemberFunction function, RawTuple* args, + std::index_sequence<I...> /*unused*/) { + return (instance->*function)(getForCall<I, RawTuple, Params...>(args)...); + } + template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I> + static void callVoidHelper(Class* instance, MemberFunction function, RawTuple* args, + std::index_sequence<I...> /*unused*/) { + (instance->*function)(getForCall<I, RawTuple, Params...>(args)...); + } + }; + + // This class iterates over the parameter types, and if a given parameter is an output + // (i.e., is a pointer), writes the corresponding argument tuple element into the reply Parcel + template <typename... Params> + struct OutputWriter; + template <typename... Params> + struct OutputWriter<std::tuple<Params...>> { + public: + explicit OutputWriter(const char* logTag) : mLogTag(logTag) {} + + // See the note on InputReader::readInputs for why this differs from the arguably simpler + // RemoveFirst approach in SafeBpInterface + template <typename RawTuple> + status_t writeOutputs(Parcel* reply, RawTuple* args) { + return dispatchArg<0>(reply, args); + } + + private: + const char* const mLogTag; + + template <std::size_t I, typename RawTuple> + typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type + writeIfOutput(Parcel* reply, RawTuple* args) { + return SafeInterface::ParcelHandler{mLogTag}.write(reply, std::get<I>(*args)); + } + template <std::size_t I, typename RawTuple> + typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type + writeIfOutput(Parcel* /*reply*/, RawTuple* /*args*/) { + return NO_ERROR; + } + + // Recursively iterate through the arguments + template <std::size_t I, typename RawTuple> + typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg( + Parcel* reply, RawTuple* args) { + status_t error = writeIfOutput<I>(reply, args); + if (CC_UNLIKELY(error != NO_ERROR)) { + // A message will have been logged in read + return error; + } + return dispatchArg<I + 1>(reply, args); + } + template <std::size_t I, typename RawTuple> + typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg( + Parcel* /*reply*/, RawTuple* /*args*/) { + return NO_ERROR; + } + }; +}; + +} // namespace android diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 327ecad0cd..1ee4b6f741 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -80,3 +80,27 @@ cc_test { "libbase", ], } + +cc_test { + name: "binderSafeInterfaceTest", + srcs: ["binderSafeInterfaceTest.cpp"], + + cppflags: [ + "-Werror", + "-Weverything", + "-Wno-c++98-compat", + "-Wno-c++98-compat-pedantic", + "-Wno-global-constructors", + "-Wno-padded", + "-Wno-weak-vtables", + ], + + cpp_std: "experimental", + gnu_extensions: false, + + shared_libs: [ + "libbinder", + "liblog", + "libutils", + ], +} diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp new file mode 100644 index 0000000000..ac2f4d5a59 --- /dev/null +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -0,0 +1,514 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/SafeInterface.h> + +#include <binder/IInterface.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/Parcelable.h> +#include <binder/ProcessState.h> + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +#include <gtest/gtest.h> +#pragma clang diagnostic pop + +#include <optional> + +using namespace std::chrono_literals; // NOLINT - google-build-using-namespace + +namespace android { +namespace tests { + +// This class serves two purposes: +// 1) It ensures that the implementation doesn't require copying or moving the data (for +// efficiency purposes) +// 2) It tests that Parcelables can be passed correctly +class NoCopyNoMove : public Parcelable { +public: + NoCopyNoMove() = default; + explicit NoCopyNoMove(int32_t value) : mValue(value) {} + ~NoCopyNoMove() override = default; + + // Not copyable + NoCopyNoMove(const NoCopyNoMove&) = delete; + NoCopyNoMove& operator=(const NoCopyNoMove&) = delete; + + // Not movable + NoCopyNoMove(NoCopyNoMove&&) = delete; + NoCopyNoMove& operator=(NoCopyNoMove&&) = delete; + + // Parcelable interface + status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); } + status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); } + + int32_t getValue() const { return mValue; } + void setValue(int32_t value) { mValue = value; } + +private: + int32_t mValue = 0; + uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded +}; + +struct TestLightFlattenable : LightFlattenablePod<TestLightFlattenable> { + TestLightFlattenable() = default; + explicit TestLightFlattenable(int32_t v) : value(v) {} + int32_t value = 0; +}; + +class ExitOnDeath : public IBinder::DeathRecipient { +public: + ~ExitOnDeath() override = default; + + void binderDied(const wp<IBinder>& /*who*/) override { + ALOG(LOG_INFO, "ExitOnDeath", "Exiting"); + exit(0); + } +}; + +// This callback class is used to test both one-way transactions and that sp<IInterface> can be +// passed correctly +class ICallback : public IInterface { +public: + DECLARE_META_INTERFACE(Callback) + + enum class Tag : uint32_t { + OnCallback = IBinder::FIRST_CALL_TRANSACTION, + Last, + }; + + virtual void onCallback(int32_t aPlusOne) = 0; +}; + +class BpCallback : public SafeBpInterface<ICallback> { +public: + explicit BpCallback(const sp<IBinder>& impl) : SafeBpInterface<ICallback>(impl, getLogTag()) {} + + void onCallback(int32_t aPlusOne) override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + return callRemoteAsync<decltype(&ICallback::onCallback)>(Tag::OnCallback, aPlusOne); + } + +private: + static constexpr const char* getLogTag() { return "BpCallback"; } +}; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wexit-time-destructors" +IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback"); +#pragma clang diagnostic pop + +class BnCallback : public SafeBnInterface<ICallback> { +public: + BnCallback() : SafeBnInterface("BnCallback") {} + + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t /*flags*/) override { + EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION); + EXPECT_LT(code, static_cast<uint32_t>(ICallback::Tag::Last)); + ICallback::Tag tag = static_cast<ICallback::Tag>(code); + switch (tag) { + case ICallback::Tag::OnCallback: { + return callLocalAsync(data, reply, &ICallback::onCallback); + } + case ICallback::Tag::Last: + // Should not be possible because of the asserts at the beginning of the method + [&]() { FAIL(); }(); + return UNKNOWN_ERROR; + } + } +}; + +class ISafeInterfaceTest : public IInterface { +public: + DECLARE_META_INTERFACE(SafeInterfaceTest) + + enum class Tag : uint32_t { + SetDeathToken = IBinder::FIRST_CALL_TRANSACTION, + ReturnsNoMemory, + LogicalNot, + IncrementLightFlattenable, + IncrementNoCopyNoMove, + ToUpper, + CallMeBack, + IncrementInt32, + IncrementUint32, + IncrementTwo, + Last, + }; + + // This is primarily so that the remote service dies when the test does, but it also serves to + // test the handling of sp<IBinder> and non-const methods + virtual status_t setDeathToken(const sp<IBinder>& token) = 0; + + // This is the most basic test since it doesn't require parceling any arguments + virtual status_t returnsNoMemory() const = 0; + + // These are ordered according to their corresponding methods in SafeInterface::ParcelHandler + virtual status_t logicalNot(bool a, bool* notA) const = 0; + virtual status_t increment(const TestLightFlattenable& a, + TestLightFlattenable* aPlusOne) const = 0; + virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0; + virtual status_t toUpper(const String8& str, String8* upperStr) const = 0; + // As mentioned above, sp<IBinder> is already tested by setDeathToken + virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0; + virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0; + virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0; + + // This tests that input/output parameter interleaving works correctly + virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, + int32_t* bPlusOne) const = 0; +}; + +class BpSafeInterfaceTest : public SafeBpInterface<ISafeInterfaceTest> { +public: + explicit BpSafeInterfaceTest(const sp<IBinder>& impl) + : SafeBpInterface<ISafeInterfaceTest>(impl, getLogTag()) {} + + status_t setDeathToken(const sp<IBinder>& token) override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + return callRemote<decltype(&ISafeInterfaceTest::setDeathToken)>(Tag::SetDeathToken, token); + } + status_t returnsNoMemory() const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + return callRemote<decltype(&ISafeInterfaceTest::returnsNoMemory)>(Tag::ReturnsNoMemory); + } + status_t logicalNot(bool a, bool* notA) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA); + } + status_t increment(const TestLightFlattenable& a, + TestLightFlattenable* aPlusOne) const override { + using Signature = status_t (ISafeInterfaceTest::*)(const TestLightFlattenable&, + TestLightFlattenable*) const; + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne); + } + status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a, + NoCopyNoMove* aPlusOne) const; + return callRemote<Signature>(Tag::IncrementNoCopyNoMove, a, aPlusOne); + } + status_t toUpper(const String8& str, String8* upperStr) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr); + } + void callMeBack(const sp<ICallback>& callback, int32_t a) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + return callRemoteAsync<decltype(&ISafeInterfaceTest::callMeBack)>(Tag::CallMeBack, callback, + a); + } + status_t increment(int32_t a, int32_t* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const; + return callRemote<Signature>(Tag::IncrementInt32, a, aPlusOne); + } + status_t increment(uint32_t a, uint32_t* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const; + return callRemote<Signature>(Tag::IncrementUint32, a, aPlusOne); + } + status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + using Signature = + status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t, int32_t*) const; + return callRemote<Signature>(Tag::IncrementTwo, a, aPlusOne, b, bPlusOne); + } + +private: + static constexpr const char* getLogTag() { return "BpSafeInterfaceTest"; } +}; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wexit-time-destructors" +IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest"); + +static sp<IBinder::DeathRecipient> getDeathRecipient() { + static sp<IBinder::DeathRecipient> recipient = new ExitOnDeath; + return recipient; +} +#pragma clang diagnostic pop + +class BnSafeInterfaceTest : public SafeBnInterface<ISafeInterfaceTest> { +public: + BnSafeInterfaceTest() : SafeBnInterface(getLogTag()) {} + + status_t setDeathToken(const sp<IBinder>& token) override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + token->linkToDeath(getDeathRecipient()); + return NO_ERROR; + } + status_t returnsNoMemory() const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + return NO_MEMORY; + } + status_t logicalNot(bool a, bool* notA) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + *notA = !a; + return NO_ERROR; + } + status_t increment(const TestLightFlattenable& a, + TestLightFlattenable* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + aPlusOne->value = a.value + 1; + return NO_ERROR; + } + status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + aPlusOne->setValue(a.getValue() + 1); + return NO_ERROR; + } + status_t toUpper(const String8& str, String8* upperStr) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + *upperStr = str; + upperStr->toUpper(); + return NO_ERROR; + } + void callMeBack(const sp<ICallback>& callback, int32_t a) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + callback->onCallback(a + 1); + } + status_t increment(int32_t a, int32_t* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + *aPlusOne = a + 1; + return NO_ERROR; + } + status_t increment(uint32_t a, uint32_t* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + *aPlusOne = a + 1; + return NO_ERROR; + } + status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + *aPlusOne = a + 1; + *bPlusOne = b + 1; + return NO_ERROR; + } + + // BnInterface + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t /*flags*/) override { + EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION); + EXPECT_LT(code, static_cast<uint32_t>(Tag::Last)); + ISafeInterfaceTest::Tag tag = static_cast<ISafeInterfaceTest::Tag>(code); + switch (tag) { + case ISafeInterfaceTest::Tag::SetDeathToken: { + return callLocal(data, reply, &ISafeInterfaceTest::setDeathToken); + } + case ISafeInterfaceTest::Tag::ReturnsNoMemory: { + return callLocal(data, reply, &ISafeInterfaceTest::returnsNoMemory); + } + case ISafeInterfaceTest::Tag::LogicalNot: { + return callLocal(data, reply, &ISafeInterfaceTest::logicalNot); + } + case ISafeInterfaceTest::Tag::IncrementLightFlattenable: { + using Signature = + status_t (ISafeInterfaceTest::*)(const TestLightFlattenable& a, + TestLightFlattenable* aPlusOne) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment); + } + case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: { + using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a, + NoCopyNoMove* aPlusOne) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment); + } + case ISafeInterfaceTest::Tag::ToUpper: { + return callLocal(data, reply, &ISafeInterfaceTest::toUpper); + } + case ISafeInterfaceTest::Tag::CallMeBack: { + return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack); + } + case ISafeInterfaceTest::Tag::IncrementInt32: { + using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment); + } + case ISafeInterfaceTest::Tag::IncrementUint32: { + using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment); + } + case ISafeInterfaceTest::Tag::IncrementTwo: { + using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t, + int32_t*) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment); + } + case ISafeInterfaceTest::Tag::Last: + // Should not be possible because of the asserts at the beginning of the method + [&]() { FAIL(); }(); + return UNKNOWN_ERROR; + } + } + +private: + static constexpr const char* getLogTag() { return "BnSafeInterfaceTest"; } +}; + +class SafeInterfaceTest : public ::testing::Test { +public: + SafeInterfaceTest() : mSafeInterfaceTest(getRemoteService()) { + ProcessState::self()->startThreadPool(); + } + ~SafeInterfaceTest() override = default; + +protected: + sp<ISafeInterfaceTest> mSafeInterfaceTest; + +private: + static constexpr const char* getLogTag() { return "SafeInterfaceTest"; } + + sp<ISafeInterfaceTest> getRemoteService() { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wexit-time-destructors" + static std::mutex sMutex; + static sp<ISafeInterfaceTest> sService; + static sp<IBinder> sDeathToken = new BBinder; +#pragma clang diagnostic pop + + std::unique_lock<decltype(sMutex)> lock; + if (sService == nullptr) { + ALOG(LOG_INFO, getLogTag(), "Forking remote process"); + pid_t forkPid = fork(); + EXPECT_NE(forkPid, -1); + + const String16 serviceName("SafeInterfaceTest"); + + if (forkPid == 0) { + ALOG(LOG_INFO, getLogTag(), "Remote process checking in"); + sp<ISafeInterfaceTest> nativeService = new BnSafeInterfaceTest; + defaultServiceManager()->addService(serviceName, + IInterface::asBinder(nativeService)); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + // We shouldn't get to this point + [&]() { FAIL(); }(); + } + + sp<IBinder> binder = defaultServiceManager()->getService(serviceName); + sService = interface_cast<ISafeInterfaceTest>(binder); + EXPECT_TRUE(sService != nullptr); + + sService->setDeathToken(sDeathToken); + } + + return sService; + } +}; + +TEST_F(SafeInterfaceTest, TestReturnsNoMemory) { + status_t result = mSafeInterfaceTest->returnsNoMemory(); + ASSERT_EQ(NO_MEMORY, result); +} + +TEST_F(SafeInterfaceTest, TestLogicalNot) { + const bool a = true; + bool notA = true; + status_t result = mSafeInterfaceTest->logicalNot(a, ¬A); + ASSERT_EQ(NO_ERROR, result); + ASSERT_EQ(!a, notA); + // Test both since we don't want to accidentally catch a default false somewhere + const bool b = false; + bool notB = false; + result = mSafeInterfaceTest->logicalNot(b, ¬B); + ASSERT_EQ(NO_ERROR, result); + ASSERT_EQ(!b, notB); +} + +TEST_F(SafeInterfaceTest, TestIncrementLightFlattenable) { + const TestLightFlattenable a{1}; + TestLightFlattenable aPlusOne{0}; + status_t result = mSafeInterfaceTest->increment(a, &aPlusOne); + ASSERT_EQ(NO_ERROR, result); + ASSERT_EQ(a.value + 1, aPlusOne.value); +} + +TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) { + const NoCopyNoMove a{1}; + NoCopyNoMove aPlusOne{0}; + status_t result = mSafeInterfaceTest->increment(a, &aPlusOne); + ASSERT_EQ(NO_ERROR, result); + ASSERT_EQ(a.getValue() + 1, aPlusOne.getValue()); +} + +TEST_F(SafeInterfaceTest, TestToUpper) { + const String8 str{"Hello, world!"}; + String8 upperStr; + status_t result = mSafeInterfaceTest->toUpper(str, &upperStr); + ASSERT_EQ(NO_ERROR, result); + ASSERT_TRUE(upperStr == String8{"HELLO, WORLD!"}); +} + +TEST_F(SafeInterfaceTest, TestCallMeBack) { + class CallbackReceiver : public BnCallback { + public: + void onCallback(int32_t aPlusOne) override { + ALOG(LOG_INFO, "CallbackReceiver", "%s", __PRETTY_FUNCTION__); + std::unique_lock<decltype(mMutex)> lock(mMutex); + mValue = aPlusOne; + mCondition.notify_one(); + } + + std::optional<int32_t> waitForCallback() { + std::unique_lock<decltype(mMutex)> lock(mMutex); + bool success = + mCondition.wait_for(lock, 100ms, [&]() { return static_cast<bool>(mValue); }); + return success ? mValue : std::nullopt; + } + + private: + std::mutex mMutex; + std::condition_variable mCondition; + std::optional<int32_t> mValue; + }; + + sp<CallbackReceiver> receiver = new CallbackReceiver; + const int32_t a = 1; + mSafeInterfaceTest->callMeBack(receiver, a); + auto result = receiver->waitForCallback(); + ASSERT_TRUE(result); + ASSERT_EQ(a + 1, *result); +} + +TEST_F(SafeInterfaceTest, TestIncrementInt32) { + const int32_t a = 1; + int32_t aPlusOne = 0; + status_t result = mSafeInterfaceTest->increment(a, &aPlusOne); + ASSERT_EQ(NO_ERROR, result); + ASSERT_EQ(a + 1, aPlusOne); +} + +TEST_F(SafeInterfaceTest, TestIncrementUint32) { + const uint32_t a = 1; + uint32_t aPlusOne = 0; + status_t result = mSafeInterfaceTest->increment(a, &aPlusOne); + ASSERT_EQ(NO_ERROR, result); + ASSERT_EQ(a + 1, aPlusOne); +} + +TEST_F(SafeInterfaceTest, TestIncrementTwo) { + const int32_t a = 1; + int32_t aPlusOne = 0; + const int32_t b = 2; + int32_t bPlusOne = 0; + status_t result = mSafeInterfaceTest->increment(1, &aPlusOne, 2, &bPlusOne); + ASSERT_EQ(NO_ERROR, result); + ASSERT_EQ(a + 1, aPlusOne); + ASSERT_EQ(b + 1, bPlusOne); +} + +} // namespace tests +} // namespace android diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 5fc6abe5b1..28c2a482c3 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -117,6 +117,7 @@ cc_library_shared { "android.hidl.token@1.0-utils", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.configstore@1.0", + "android.hardware.configstore-utils", ], export_shared_lib_headers: [ @@ -125,8 +126,6 @@ cc_library_shared { "android.hidl.token@1.0-utils", "android.hardware.graphics.bufferqueue@1.0", ], - - header_libs: ["android.hardware.configstore-utils"], } subdirs = ["tests"] diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 27ced6180b..aef231a252 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -951,7 +951,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, // Call back without the main BufferQueue lock held, but with the callback // lock held so we can ensure that callbacks occur in order - { + + int connectedApi; + sp<Fence> lastQueuedFence; + + { // scope for the lock Mutex::Autolock lock(mCallbackMutex); while (callbackTicket != mCurrentCallbackTicket) { mCallbackCondition.wait(mCallbackMutex); @@ -963,20 +967,24 @@ status_t BufferQueueProducer::queueBuffer(int slot, frameReplacedListener->onFrameReplaced(item); } + connectedApi = mCore->mConnectedApi; + lastQueuedFence = std::move(mLastQueueBufferFence); + + mLastQueueBufferFence = std::move(acquireFence); + mLastQueuedCrop = item.mCrop; + mLastQueuedTransform = item.mTransform; + ++mCurrentCallbackTicket; mCallbackCondition.broadcast(); } // Wait without lock held - if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) { + if (connectedApi == NATIVE_WINDOW_API_EGL) { // Waiting here allows for two full buffers to be queued but not a // third. In the event that frames take varying time, this makes a // small trade-off in favor of latency rather than throughput. - mLastQueueBufferFence->waitForever("Throttling EGL Production"); + lastQueuedFence->waitForever("Throttling EGL Production"); } - mLastQueueBufferFence = std::move(acquireFence); - mLastQueuedCrop = item.mCrop; - mLastQueuedTransform = item.mTransform; // Update and get FrameEventHistory. nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC); diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 8acdfed8f5..d4e4dc3616 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -287,6 +287,9 @@ status_t ConsumerBase::acquireBufferLocked(BufferItem *item, } if (item->mGraphicBuffer != NULL) { + if (mSlots[item->mSlot].mGraphicBuffer != NULL) { + freeBufferLocked(item->mSlot); + } mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer; } diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index db8a517d4d..2d2146b356 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -17,116 +17,56 @@ // tag as surfaceflinger #define LOG_TAG "SurfaceFlinger" -#include <stdio.h> #include <stdint.h> +#include <stdio.h> #include <sys/types.h> -#include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/SafeInterface.h> +#include <ui/FrameStats.h> #include <ui/Point.h> #include <ui/Rect.h> #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposerClient.h> -#include <private/gui/LayerState.h> - -// --------------------------------------------------------------------------- namespace android { -enum { - CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, - DESTROY_SURFACE, - CLEAR_LAYER_FRAME_STATS, - GET_LAYER_FRAME_STATS, - GET_TRANSFORM_TO_DISPLAY_INVERSE -}; - -class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient> -{ +class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> { public: explicit BpSurfaceComposerClient(const sp<IBinder>& impl) - : BpInterface<ISurfaceComposerClient>(impl) { - } - - virtual ~BpSurfaceComposerClient(); - - virtual status_t createSurface(const String8& name, uint32_t width, - uint32_t height, PixelFormat format, uint32_t flags, - const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid, - sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeString8(name); - data.writeUint32(width); - data.writeUint32(height); - data.writeInt32(static_cast<int32_t>(format)); - data.writeUint32(flags); - data.writeUint32(windowType); - data.writeUint32(ownerUid); - if (parent != nullptr) { - data.writeStrongBinder(parent); - } - remote()->transact(CREATE_SURFACE, data, &reply); - *handle = reply.readStrongBinder(); - *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder()); - return reply.readInt32(); + : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {} + + ~BpSurfaceComposerClient() override; + + status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format, + uint32_t flags, const sp<IBinder>& parent, uint32_t windowType, + uint32_t ownerUid, sp<IBinder>* handle, + sp<IGraphicBufferProducer>* gbp) override { + return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CreateSurface, + name, width, height, + format, flags, parent, + windowType, ownerUid, + handle, gbp); } - virtual status_t destroySurface(const sp<IBinder>& handle) { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeStrongBinder(handle); - remote()->transact(DESTROY_SURFACE, data, &reply); - return reply.readInt32(); + status_t destroySurface(const sp<IBinder>& handle) override { + return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DestroySurface, + handle); } - virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeStrongBinder(handle); - remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply); - return reply.readInt32(); + status_t clearLayerFrameStats(const sp<IBinder>& handle) const override { + return callRemote<decltype( + &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::ClearLayerFrameStats, handle); } - virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeStrongBinder(handle); - remote()->transact(GET_LAYER_FRAME_STATS, data, &reply); - reply.read(*outStats); - return reply.readInt32(); - } - - virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle, - bool* outTransformToDisplayInverse) const { - Parcel data, reply; - status_t result = - data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - if (result != NO_ERROR) { - return result; - } - result = data.writeStrongBinder(handle); - if (result != NO_ERROR) { - return result; - } - result = remote()->transact(GET_TRANSFORM_TO_DISPLAY_INVERSE, data, &reply); - if (result != NO_ERROR) { - return result; - } - int transformInverse; - result = reply.readInt32(&transformInverse); - if (result != NO_ERROR) { - return result; - } - *outTransformToDisplayInverse = transformInverse != 0 ? true : false; - status_t result2 = reply.readInt32(&result); - if (result2 != NO_ERROR) { - return result2; - } - return result; + status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override { + return callRemote<decltype( + &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GetLayerFrameStats, handle, + outStats); } }; @@ -138,75 +78,29 @@ IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClie // ---------------------------------------------------------------------- -status_t BnSurfaceComposerClient::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case CREATE_SURFACE: { - CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - String8 name = data.readString8(); - uint32_t width = data.readUint32(); - uint32_t height = data.readUint32(); - PixelFormat format = static_cast<PixelFormat>(data.readInt32()); - uint32_t createFlags = data.readUint32(); - uint32_t windowType = data.readUint32(); - uint32_t ownerUid = data.readUint32(); - sp<IBinder> parent = nullptr; - if (data.dataAvail() > 0) { - parent = data.readStrongBinder(); - } - sp<IBinder> handle; - sp<IGraphicBufferProducer> gbp; - status_t result = createSurface(name, width, height, format, - createFlags, parent, windowType, ownerUid, &handle, &gbp); - reply->writeStrongBinder(handle); - reply->writeStrongBinder(IInterface::asBinder(gbp)); - reply->writeInt32(result); - return NO_ERROR; - } - case DESTROY_SURFACE: { - CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - reply->writeInt32(destroySurface( data.readStrongBinder() ) ); - return NO_ERROR; +status_t BnSurfaceComposerClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + if (code < IBinder::FIRST_CALL_TRANSACTION || code >= static_cast<uint32_t>(Tag::Last)) { + return BBinder::onTransact(code, data, reply, flags); + } + auto tag = static_cast<Tag>(code); + switch (tag) { + case Tag::CreateSurface: { + return callLocal(data, reply, &ISurfaceComposerClient::createSurface); } - case CLEAR_LAYER_FRAME_STATS: { - CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - sp<IBinder> handle = data.readStrongBinder(); - status_t result = clearLayerFrameStats(handle); - reply->writeInt32(result); - return NO_ERROR; + case Tag::DestroySurface: { + return callLocal(data, reply, &ISurfaceComposerClient::destroySurface); } - case GET_LAYER_FRAME_STATS: { - CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - sp<IBinder> handle = data.readStrongBinder(); - FrameStats stats; - status_t result = getLayerFrameStats(handle, &stats); - reply->write(stats); - reply->writeInt32(result); - return NO_ERROR; + case Tag::ClearLayerFrameStats: { + return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats); } - case GET_TRANSFORM_TO_DISPLAY_INVERSE: { - CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - sp<IBinder> handle; - status_t result = data.readStrongBinder(&handle); - if (result != NO_ERROR) { - return result; - } - bool transformInverse = false; - result = getTransformToDisplayInverse(handle, &transformInverse); - if (result != NO_ERROR) { - return result; - } - result = reply->writeInt32(transformInverse ? 1 : 0); - if (result != NO_ERROR) { - return result; - } - result = reply->writeInt32(NO_ERROR); - return result; + case Tag::GetLayerFrameStats: { + return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats); } - default: + case Tag::Last: + // Should not be possible because of the check at the beginning of the method return BBinder::onTransact(code, data, reply, flags); } } -}; // namespace android +} // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 06fc31d16c..1149b8980b 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -505,7 +505,11 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { mFrameEventHistory->applyDelta(frameTimestamps); } - if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { + if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) { + if (mReportRemovedBuffers && (gbuf != nullptr)) { + mRemovedBuffers.clear(); + mRemovedBuffers.push_back(gbuf); + } result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); if (result != NO_ERROR) { ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); @@ -1075,10 +1079,16 @@ int Surface::connect(int api) { } int Surface::connect(int api, const sp<IProducerListener>& listener) { + return connect(api, listener, false); +} + +int Surface::connect( + int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) { ATRACE_CALL(); ALOGV("Surface::connect"); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; + mReportRemovedBuffers = reportBufferRemoval; int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); if (err == NO_ERROR) { mDefaultWidth = output.width; @@ -1109,6 +1119,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { ATRACE_CALL(); ALOGV("Surface::disconnect"); Mutex::Autolock lock(mMutex); + mRemovedBuffers.clear(); mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; mSharedBufferHasBeenQueued = false; freeAllBuffers(); @@ -1156,9 +1167,16 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, *outFence = Fence::NO_FENCE; } + if (mReportRemovedBuffers) { + mRemovedBuffers.clear(); + } + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { + if (mReportRemovedBuffers) { + mRemovedBuffers.push_back(mSlots[i].buffer); + } mSlots[i].buffer = NULL; } } @@ -1184,6 +1202,10 @@ int Surface::attachBuffer(ANativeWindowBuffer* buffer) graphicBuffer->mGenerationNumber = priorGeneration; return result; } + if (mReportRemovedBuffers && (mSlots[attachedSlot].buffer != nullptr)) { + mRemovedBuffers.clear(); + mRemovedBuffers.push_back(mSlots[attachedSlot].buffer); + } mSlots[attachedSlot].buffer = graphicBuffer; return NO_ERROR; @@ -1617,4 +1639,16 @@ status_t Surface::getUniqueId(uint64_t* outId) const { return mGraphicBufferProducer->getUniqueId(outId); } +status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) { + if (out == nullptr) { + ALOGE("%s: out must not be null!", __FUNCTION__); + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + *out = mRemovedBuffers; + mRemovedBuffers.clear(); + return OK; +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 088933afb6..56c7586041 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -711,14 +711,6 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token, return mClient->getLayerFrameStats(token, outStats); } -status_t SurfaceComposerClient::getTransformToDisplayInverse(const sp<IBinder>& token, - bool* outTransformToDisplayInverse) const { - if (mStatus != NO_ERROR) { - return mStatus; - } - return mClient->getTransformToDisplayInverse(token, outTransformToDisplayInverse); -} - inline Composer& SurfaceComposerClient::getComposer() { return mComposer; } diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 1e693796eb..7a68f1174a 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -209,13 +209,6 @@ status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const { return client->getLayerFrameStats(mHandle, outStats); } -status_t SurfaceControl::getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->getTransformToDisplayInverse(mHandle, outTransformToDisplayInverse); -} - status_t SurfaceControl::validate() const { if (mHandle==0 || mClient==0) { diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 3a99147a7a..192bfc8fac 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -27,6 +27,8 @@ cc_test { ], shared_libs: [ + "android.hardware.configstore@1.0", + "android.hardware.configstore-utils", "liblog", "libEGL", "libGLESv1_CM", @@ -34,6 +36,8 @@ cc_test { "libbinder", "libcutils", "libgui", + "libhidlbase", + "libhidltransport", "libui", "libutils", "libnativewindow" diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index 9c2e838b09..5848c74b8c 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -490,7 +490,7 @@ void produceOneFrame(const sp<ANativeWindow>& anw, ASSERT_TRUE(anb != NULL); - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); *stride = buf->getStride(); uint8_t* img = NULL; diff --git a/libs/gui/tests/FillBuffer.cpp b/libs/gui/tests/FillBuffer.cpp index 079962c8b9..ccd674fcb8 100644 --- a/libs/gui/tests/FillBuffer.cpp +++ b/libs/gui/tests/FillBuffer.cpp @@ -95,7 +95,7 @@ void produceOneRGBA8Frame(const sp<ANativeWindow>& anw) { &anb)); ASSERT_TRUE(anb != NULL); - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); uint8_t* img = NULL; ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp index 0606839506..0134273a07 100644 --- a/libs/gui/tests/SurfaceTextureFBO_test.cpp +++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp @@ -41,7 +41,7 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { &anb)); ASSERT_TRUE(anb != NULL); - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); // Fill the buffer with green uint8_t* img = NULL; @@ -65,7 +65,7 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { &anb)); ASSERT_TRUE(anb != NULL); - buf = new GraphicBuffer(anb, false); + buf = GraphicBuffer::from(anb); // Fill the buffer with red ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp index 308bd7d69c..c6745d034d 100644 --- a/libs/gui/tests/SurfaceTextureGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGL_test.cpp @@ -42,7 +42,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { &anb)); ASSERT_TRUE(anb != NULL); - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); // Fill the buffer with the a checkerboard pattern uint8_t* img = NULL; @@ -92,7 +92,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) { &anb)); ASSERT_TRUE(anb != NULL); - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); // Fill the buffer with the a checkerboard pattern uint8_t* img = NULL; @@ -157,7 +157,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { &anb)); ASSERT_TRUE(anb != NULL); - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); @@ -238,7 +238,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { return false; } - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); const int yuvTexOffsetY = 0; int stride = buf->getStride(); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 3932b92674..ce114864aa 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -18,7 +18,9 @@ #include <gtest/gtest.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <binder/ProcessState.h> +#include <configstore/Utils.h> #include <cutils/properties.h> #include <gui/BufferItemConsumer.h> #include <gui/IDisplayEventConnection.h> @@ -35,6 +37,12 @@ namespace android { using namespace std::chrono_literals; +// retrieve wide-color and hdr settings from configstore +using namespace android::hardware::configstore; +using namespace android::hardware::configstore::V1_0; + +static bool hasWideColorDisplay = + getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); class FakeSurfaceComposer; class FakeProducerFrameEventHistory; @@ -271,17 +279,19 @@ TEST_F(SurfaceTest, GetWideColorSupport) { bool supported; surface->getWideColorSupport(&supported); - // TODO(courtneygo): How can we know what device we are on to - // verify that this is correct? - char product[PROPERTY_VALUE_MAX] = "0"; - property_get("ro.build.product", product, "0"); - std::cerr << "[ ] product = " << product << std::endl; - - if (strcmp("marlin", product) == 0 || strcmp("sailfish", product) == 0) { - ASSERT_EQ(true, supported); - } else { - ASSERT_EQ(false, supported); - } + // NOTE: This test assumes that device that supports + // wide-color (as indicated by BoardConfig) must also + // have a wide-color primary display. + // That assumption allows this test to cover devices + // that advertised a wide-color color mode without + // actually supporting wide-color to pass this test + // as well as the case of a device that does support + // wide-color (via BoardConfig) and has a wide-color + // primary display. + // NOT covered at this time is a device that supports + // wide color in the BoardConfig but does not support + // a wide-color color mode on the primary display. + ASSERT_EQ(hasWideColorDisplay, supported); } TEST_F(SurfaceTest, DynamicSetBufferCount) { diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp index 03297cae8b..e35bfc9fea 100644 --- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp +++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp @@ -538,6 +538,12 @@ Error HWC2On1Adapter::Display::acceptChanges() { for (auto& change : mChanges->getTypeChanges()) { auto layerId = change.first; auto type = change.second; + if (mDevice.mLayers.count(layerId) == 0) { + // This should never happen but somehow does. + ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")", + layerId); + continue; + } auto layer = mDevice.mLayers[layerId]; layer->setCompositionType(type); } diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 1ed150b37b..a38b4dc61b 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -28,6 +28,7 @@ #include <ui/GraphicBuffer.h> #include <system/graphics.h> #include <hardware/gralloc1.h> +#include <grallocusage/GrallocUsageConversion.h> #include <private/android/AHardwareBufferHelpers.h> @@ -100,8 +101,12 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, outDesc->width = gbuffer->getWidth(); outDesc->height = gbuffer->getHeight(); outDesc->layers = gbuffer->getLayerCount(); + + uint64_t producerUsage = 0; + uint64_t consumerUsage = 0; + android_convertGralloc0To1Usage(gbuffer->getUsage(), &producerUsage, &consumerUsage); AHardwareBuffer_convertFromGrallocUsageBits(&outDesc->usage0, &outDesc->usage1, - gbuffer->getUsage(), gbuffer->getUsage()); + producerUsage, consumerUsage); outDesc->format = AHardwareBuffer_convertFromPixelFormat( static_cast<uint32_t>(gbuffer->getPixelFormat())); } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index c0c4ac0f04..6c67cf8dc6 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -25,6 +25,8 @@ #include <private/android/AHardwareBufferHelpers.h> +#include <ui/GraphicBuffer.h> + using namespace android; static int32_t query(ANativeWindow* window, int what) { @@ -105,6 +107,10 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo * vndk-stable **************************************************************************************************/ +AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(ANativeWindowBuffer* anwb) { + return AHardwareBuffer_from_GraphicBuffer(static_cast<GraphicBuffer*>(anwb)); +} + int ANativeWindow_OemStorageSet(ANativeWindow* window, uint32_t slot, intptr_t value) { if (slot < 4) { window->oem[slot] = value; diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h index 310e1e52a1..067046b8d3 100644 --- a/libs/nativewindow/include/vndk/window.h +++ b/libs/nativewindow/include/vndk/window.h @@ -99,8 +99,12 @@ typedef struct ANativeWindowBuffer typedef struct ANativeWindowBuffer ANativeWindowBuffer; -/*****************************************************************************/ +/* + * Convert this ANativeWindowBuffer into a AHardwareBuffer + */ +AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(ANativeWindowBuffer* anwb); +/*****************************************************************************/ /* * Stores a value into one of the 4 available slots diff --git a/libs/sensor/include/sensor/SensorEventQueue.h b/libs/sensor/include/sensor/SensorEventQueue.h index a03c7eeea3..baed2ee20d 100644 --- a/libs/sensor/include/sensor/SensorEventQueue.h +++ b/libs/sensor/include/sensor/SensorEventQueue.h @@ -83,7 +83,7 @@ public: status_t disableSensor(Sensor const* sensor) const; status_t setEventRate(Sensor const* sensor, nsecs_t ns) const; - // these are here only to support SensorManager.java + // these are here only to support SensorManager.java and HIDL Frameworks SensorManager. status_t enableSensor(int32_t handle, int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs, int reservedFlags) const; status_t disableSensor(int32_t handle) const; diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 6e8473018a..d21758d41e 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -39,6 +39,10 @@ static uint64_t getUniqueId() { return id; } +sp<GraphicBuffer> GraphicBuffer::from(ANativeWindowBuffer* anwb) { + return static_cast<GraphicBuffer *>(anwb); +} + GraphicBuffer::GraphicBuffer() : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) @@ -52,86 +56,42 @@ GraphicBuffer::GraphicBuffer() handle = NULL; } +// deprecated GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage, std::string requestorName) - : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) + : GraphicBuffer(inWidth, inHeight, inFormat, 1, inUsage, inUsage, + requestorName) { - width = - height = - stride = - format = - usage = 0; - layerCount = 0; - handle = NULL; - mInitCheck = initSize(inWidth, inHeight, inFormat, 1, inUsage, inUsage, - std::move(requestorName)); } GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t producerUsage, uint64_t consumerUsage, std::string requestorName) - : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) + : GraphicBuffer() { - width = - height = - stride = - format = - usage = 0; - layerCount = 0; - handle = NULL; - mInitCheck = initSize(inWidth, inHeight, inFormat, inLayerCount, + mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, producerUsage, consumerUsage, std::move(requestorName)); } +// deprecated GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle, bool keepOwnership) - : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), - mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) + : GraphicBuffer(inHandle, keepOwnership ? TAKE_HANDLE : WRAP_HANDLE, + inWidth, inHeight, inFormat, inLayerCount, inUsage, inUsage, + inStride) { - width = static_cast<int>(inWidth); - height = static_cast<int>(inHeight); - stride = static_cast<int>(inStride); - format = inFormat; - layerCount = inLayerCount; - usage = static_cast<int>(inUsage); - handle = inHandle; } -GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, - PixelFormat inFormat, uint32_t inLayerCount, uint32_t inProducerUsage, - uint32_t inConsumerUsage, uint32_t inStride, - native_handle_t* inHandle, bool keepOwnership) - : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), - mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) +GraphicBuffer::GraphicBuffer(const native_handle_t* handle, + HandleWrapMethod method, uint32_t width, uint32_t height, + PixelFormat format, uint32_t layerCount, + uint64_t producerUsage, uint64_t consumerUsage, + uint32_t stride) + : GraphicBuffer() { - width = static_cast<int>(inWidth); - height = static_cast<int>(inHeight); - stride = static_cast<int>(inStride); - format = inFormat; - layerCount = inLayerCount; - usage = android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage); - handle = inHandle; -} - - -GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership) - : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), - mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mWrappedBuffer(buffer), mId(getUniqueId()), - mGenerationNumber(0) -{ - width = buffer->width; - height = buffer->height; - stride = buffer->stride; - format = buffer->format; - layerCount = buffer->layerCount; - usage = buffer->usage; - handle = buffer->handle; + mInitCheck = initWithHandle(handle, method, width, height, format, + layerCount, producerUsage, consumerUsage, stride); } GraphicBuffer::~GraphicBuffer() @@ -154,7 +114,6 @@ void GraphicBuffer::free_handle() allocator.free(handle); } handle = NULL; - mWrappedBuffer = 0; } status_t GraphicBuffer::initCheck() const { @@ -192,8 +151,8 @@ status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight, allocator.free(handle); handle = 0; } - return initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, inUsage, - "[Reallocation]"); + return initWithSize(inWidth, inHeight, inFormat, inLayerCount, + inUsage, inUsage, "[Reallocation]"); } bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight, @@ -207,7 +166,7 @@ bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight, return false; } -status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight, +status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inProducerUsage, uint64_t inConsumerUsage, std::string requestorName) { @@ -227,6 +186,54 @@ status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight, return err; } +status_t GraphicBuffer::initWithHandle(const native_handle_t* handle, + HandleWrapMethod method, uint32_t width, uint32_t height, + PixelFormat format, uint32_t layerCount, + uint64_t producerUsage, uint64_t consumerUsage, + uint32_t stride) +{ + native_handle_t* clone = nullptr; + + if (method == CLONE_HANDLE) { + clone = native_handle_clone(handle); + if (!clone) { + return NO_MEMORY; + } + + handle = clone; + method = TAKE_UNREGISTERED_HANDLE; + } + + ANativeWindowBuffer::width = static_cast<int>(width); + ANativeWindowBuffer::height = static_cast<int>(height); + ANativeWindowBuffer::stride = static_cast<int>(stride); + ANativeWindowBuffer::format = format; + ANativeWindowBuffer::usage = + android_convertGralloc1To0Usage(producerUsage, consumerUsage); + + ANativeWindowBuffer::layerCount = layerCount; + ANativeWindowBuffer::handle = handle; + + mOwner = (method == WRAP_HANDLE) ? ownNone : ownHandle; + + if (method == TAKE_UNREGISTERED_HANDLE) { + status_t err = mBufferMapper.registerBuffer(this); + if (err != NO_ERROR) { + // clean up cloned handle + if (clone) { + native_handle_close(clone); + native_handle_delete(clone); + } + + initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0, 0); + + return err; + } + } + + return NO_ERROR; +} + status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr) { const Rect lockBounds(width, height); diff --git a/libs/vr/libbufferhub/ion_buffer.cpp b/libs/vr/libbufferhub/ion_buffer.cpp index 3fb3f3c6ff..e5a56c1a4b 100644 --- a/libs/vr/libbufferhub/ion_buffer.cpp +++ b/libs/vr/libbufferhub/ion_buffer.cpp @@ -1,5 +1,4 @@ #include <private/dvr/ion_buffer.h> -#include <ui/GraphicBufferMapper.h> #include <log/log.h> #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -70,10 +69,9 @@ int IonBuffer::Alloc(int width, int height, int format, int usage) { ALOGD_IF(TRACE, "IonBuffer::Alloc: width=%d height=%d format=%d usage=%d", width, height, format, usage); - GraphicBufferMapper& mapper = GraphicBufferMapper::get(); buffer_ = new GraphicBuffer(width, height, format, usage); - if (mapper.registerBuffer(buffer_.get()) != OK) { - ALOGE("IonBuffer::Aloc: Failed to register buffer"); + if (buffer_->initCheck() != OK) { + ALOGE("IonBuffer::Aloc: Failed to allocate buffer"); } return 0; } @@ -96,11 +94,10 @@ int IonBuffer::Import(buffer_handle_t handle, int width, int height, int stride, "usage=%d", handle, width, height, stride, format, usage); FreeHandle(); - GraphicBufferMapper& mapper = GraphicBufferMapper::get(); - buffer_ = new GraphicBuffer(width, height, format, 1, usage, - stride, (native_handle_t*)handle, true); - if (mapper.registerBuffer(buffer_.get()) != OK) { - ALOGE("IonBuffer::Import: Failed to register cloned buffer"); + buffer_ = new GraphicBuffer(handle, GraphicBuffer::TAKE_UNREGISTERED_HANDLE, + width, height, format, 1, usage, stride); + if (buffer_->initCheck() != OK) { + ALOGE("IonBuffer::Import: Failed to import buffer"); return -EINVAL; } return 0; diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp index 2d96638070..0fa1f01aad 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp @@ -42,7 +42,7 @@ sharedLibraries = [ cc_library { name: "libbufferhubqueue", - cflags = [ + cflags: [ "-DLOG_TAG=\"libbufferhubqueue\"", "-DTRACE=0", ], diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index bd6511de5a..031401a1b6 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp @@ -146,7 +146,7 @@ void BufferHubQueue::HandleBufferEvent(size_t slot, const epoll_event& event) { ALOGW( "Receives EPOLLHUP at slot: %zu, buffer event fd: %d, EPOLLHUP " "pending: %d", - slot, buffer->event_fd(), epollhup_pending_[slot]); + slot, buffer->event_fd(), int{epollhup_pending_[slot]}); if (epollhup_pending_[slot]) { epollhup_pending_[slot] = false; } else { diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp index a108042d01..a826a6958d 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp @@ -50,27 +50,7 @@ status_t BufferHubQueueCore::AllocateBuffer(uint32_t width, uint32_t height, LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu", slot); - // Allocating a new buffer, |buffers_[slot]| should be in initial state. - LOG_ALWAYS_FATAL_IF(buffers_[slot].mGraphicBuffer != nullptr, - "AllocateBuffer: slot %zu is not empty.", slot); - - // Create new GraphicBuffer based on the newly created |buffer_producer|. Here - // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because - // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle| - // is still type of |buffer_handle_t| and bears const property. - sp<GraphicBuffer> graphic_buffer(new GraphicBuffer( - buffer_producer->width(), buffer_producer->height(), - buffer_producer->format(), - 1, /* layer count */ - buffer_producer->usage(), - buffer_producer->stride(), - const_cast<native_handle_t*>(buffer_producer->buffer()->handle()), - false)); - - LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(), - "Failed to init GraphicBuffer."); buffers_[slot].mBufferProducer = buffer_producer; - buffers_[slot].mGraphicBuffer = graphic_buffer; return NO_ERROR; } diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp index ddf7fd2330..3fe76426fd 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp @@ -8,7 +8,7 @@ namespace dvr { BufferHubQueueProducer::BufferHubQueueProducer( const std::shared_ptr<BufferHubQueueCore>& core) - : core_(core), req_buffer_count_(kInvalidBufferCount) {} + : core_(core) {} status_t BufferHubQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { @@ -16,18 +16,48 @@ status_t BufferHubQueueProducer::requestBuffer(int slot, std::unique_lock<std::mutex> lock(core_->mutex_); - if (slot < 0 || slot >= req_buffer_count_) { + if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { + ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, - req_buffer_count_); + max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; + } else if (core_->buffers_[slot].mGraphicBuffer != nullptr) { + ALOGE("requestBuffer: slot %d is not empty.", slot); + return BAD_VALUE; + } else if (core_->buffers_[slot].mBufferProducer == nullptr) { + ALOGE("requestBuffer: slot %d is not dequeued.", slot); + return BAD_VALUE; } + const auto& buffer_producer = core_->buffers_[slot].mBufferProducer; + + // Create new GraphicBuffer based on the newly created |buffer_producer|. Here + // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because + // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle| + // is still type of |buffer_handle_t| and bears const property. + sp<GraphicBuffer> graphic_buffer(new GraphicBuffer( + buffer_producer->width(), buffer_producer->height(), + buffer_producer->format(), + 1, /* layer count */ + buffer_producer->usage(), + buffer_producer->stride(), + const_cast<native_handle_t*>(buffer_producer->buffer()->handle()), + false)); + + LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(), + "Failed to init GraphicBuffer."); + core_->buffers_[slot].mGraphicBuffer = graphic_buffer; core_->buffers_[slot].mRequestBufferCalled = true; - *buf = core_->buffers_[slot].mGraphicBuffer; + + *buf = graphic_buffer; return NO_ERROR; } @@ -46,30 +76,68 @@ status_t BufferHubQueueProducer::setMaxDequeuedBufferCount( return BAD_VALUE; } - req_buffer_count_ = max_dequeued_buffers; + // The new dequeued_buffers count should not be violated by the number + // of currently dequeued buffers. + int dequeued_count = 0; + for (const auto& buf : core_->buffers_) { + if (buf.mBufferState.isDequeued()) { + dequeued_count++; + } + } + if (dequeued_count > max_dequeued_buffers) { + ALOGE( + "setMaxDequeuedBufferCount: the requested dequeued_buffers" + "count (%d) exceeds the current dequeued buffer count (%d)", + max_dequeued_buffers, dequeued_count); + return BAD_VALUE; + } + + max_dequeued_buffer_count_ = max_dequeued_buffers; return NO_ERROR; } -status_t BufferHubQueueProducer::setAsyncMode(bool /* async */) { - ALOGE("BufferHubQueueProducer::setAsyncMode not implemented."); - return INVALID_OPERATION; +status_t BufferHubQueueProducer::setAsyncMode(bool async) { + if (async) { + // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer + // automatically and behaves differently from IGraphicBufferConsumer. Thus, + // android::BufferQueue's async mode (a.k.a. allocating an additional buffer + // to prevent dequeueBuffer from being blocking) technically does not apply + // here. + // + // In Daydream, non-blocking producer side dequeue is guaranteed by careful + // buffer consumer implementations. In another word, BufferHubQueue based + // dequeueBuffer should never block whether setAsyncMode(true) is set or + // not. + // + // See: IGraphicBufferProducer::setAsyncMode and + // BufferQueueProducer::setAsyncMode for more about original implementation. + ALOGW( + "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be " + "asynchronous. This call makes no effact."); + return NO_ERROR; + } + return NO_ERROR; } -status_t BufferHubQueueProducer::dequeueBuffer(int* out_slot, - sp<Fence>* out_fence, - uint32_t width, uint32_t height, - PixelFormat format, - uint32_t usage, - FrameEventHistoryDelta* /* outTimestamps */) { +status_t BufferHubQueueProducer::dequeueBuffer( + int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, + PixelFormat format, uint32_t usage, + FrameEventHistoryDelta* /* out_timestamps */) { ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width, height, format, usage); status_t ret; std::unique_lock<std::mutex> lock(core_->mutex_); - if (static_cast<int32_t>(core_->producer_->capacity()) < req_buffer_count_) { + if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { + ALOGE("dequeueBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + if (static_cast<int32_t>(core_->producer_->capacity()) < + max_dequeued_buffer_count_) { // Lazy allocation. When the capacity of |core_->producer_| has not reach - // |req_buffer_count_|, allocate new buffer. + // |max_dequeued_buffer_count_|, allocate new buffer. // TODO(jwcai) To save memory, the really reasonable thing to do is to go // over existing slots and find first existing one to dequeue. ret = core_->AllocateBuffer(width, height, format, usage, 1); @@ -126,8 +194,8 @@ status_t BufferHubQueueProducer::dequeueBuffer(int* out_slot, // BufferHubQueue). // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's // model. - LOG_ALWAYS_FATAL_IF(!core_->buffers_[slot].mBufferState.isFree() && - !core_->buffers_[slot].mBufferState.isQueued(), + LOG_ALWAYS_FATAL_IF((!core_->buffers_[slot].mBufferState.isFree() && + !core_->buffers_[slot].mBufferState.isQueued()), "dequeueBuffer: slot %zu is not free or queued.", slot); core_->buffers_[slot].mBufferState.freeQueued(); @@ -170,22 +238,39 @@ status_t BufferHubQueueProducer::attachBuffer( status_t BufferHubQueueProducer::queueBuffer(int slot, const QueueBufferInput& input, - QueueBufferOutput* /* output */) { + QueueBufferOutput* output) { ALOGD_IF(TRACE, "queueBuffer: slot %d", slot); + if (output == nullptr) { + return BAD_VALUE; + } + int64_t timestamp; + int scaling_mode; sp<Fence> fence; + Rect crop(Rect::EMPTY_RECT); // TODO(jwcai) The following attributes are ignored. bool is_auto_timestamp; android_dataspace data_space; - Rect crop(Rect::EMPTY_RECT); - int scaling_mode; uint32_t transform; input.deflate(×tamp, &is_auto_timestamp, &data_space, &crop, &scaling_mode, &transform, &fence); + // Check input scaling mode is valid. + switch (scaling_mode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: + case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: + break; + default: + ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode); + return BAD_VALUE; + } + + // Check input fence is valid. if (fence == nullptr) { ALOGE("queueBuffer: fence is NULL"); return BAD_VALUE; @@ -194,25 +279,61 @@ status_t BufferHubQueueProducer::queueBuffer(int slot, status_t ret; std::unique_lock<std::mutex> lock(core_->mutex_); - if (slot < 0 || slot >= req_buffer_count_) { + if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { + ALOGE("queueBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, - req_buffer_count_); + max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; + } else if ((!core_->buffers_[slot].mRequestBufferCalled || + core_->buffers_[slot].mGraphicBuffer == nullptr)) { + ALOGE( + "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, " + "mGraphicBuffer=%p)", + slot, core_->buffers_[slot].mRequestBufferCalled, + core_->buffers_[slot].mGraphicBuffer.get()); + return BAD_VALUE; } // Post the buffer producer with timestamp in the metadata. - auto buffer_producer = core_->buffers_[slot].mBufferProducer; + const auto& buffer_producer = core_->buffers_[slot].mBufferProducer; + + // Check input crop is not out of boundary of current buffer. + Rect buffer_rect(buffer_producer->width(), buffer_producer->height()); + Rect cropped_rect(Rect::EMPTY_RECT); + crop.intersect(buffer_rect, &cropped_rect); + if (cropped_rect != crop) { + ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot); + return BAD_VALUE; + } + LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); BufferHubQueueCore::BufferMetadata meta_data = {.timestamp = timestamp}; buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data)); core_->buffers_[slot].mBufferState.queue(); - // TODO(jwcai) check how to fill in output properly. + output->width = buffer_producer->width(); + output->height = buffer_producer->height(); + output->transformHint = 0; // default value, we don't use it yet. + + // |numPendingBuffers| counts of the number of buffers that has been enqueued + // by the producer but not yet acquired by the consumer. Due to the nature + // of BufferHubQueue design, this is hard to trace from the producer's client + // side, but it's safe to assume it's zero. + output->numPendingBuffers = 0; + + // Note that we are not setting nextFrameNumber here as it seems to be only + // used by surface flinger. See more at b/22802885, ag/791760. + output->nextFrameNumber = 0; + return NO_ERROR; } @@ -222,15 +343,20 @@ status_t BufferHubQueueProducer::cancelBuffer(int slot, std::unique_lock<std::mutex> lock(core_->mutex_); - if (slot < 0 || slot >= req_buffer_count_) { + if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { + ALOGE("cancelBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, - req_buffer_count_); + max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; - } else if (fence == NULL) { + } else if (fence == nullptr) { ALOGE("cancelBuffer: fence is NULL"); return BAD_VALUE; } @@ -249,7 +375,7 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { std::unique_lock<std::mutex> lock(core_->mutex_); - if (out_value == NULL) { + if (out_value == nullptr) { ALOGE("query: out_value was NULL"); return BAD_VALUE; } @@ -262,15 +388,30 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { case NATIVE_WINDOW_BUFFER_AGE: value = 0; break; - // The following queries are currently considered as unsupported. - // TODO(jwcai) Need to carefully check the whether they should be - // supported after all. case NATIVE_WINDOW_WIDTH: + value = core_->producer_->default_width(); + break; case NATIVE_WINDOW_HEIGHT: + value = core_->producer_->default_height(); + break; case NATIVE_WINDOW_FORMAT: - case NATIVE_WINDOW_STICKY_TRANSFORM: + value = core_->producer_->default_format(); + break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: + // BufferHubQueue is always operating in async mode, thus semantically + // consumer can never be running behind. See BufferQueueCore.cpp core + // for more information about the original meaning of this flag. + value = 0; + break; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: + // TODO(jwcai) This is currently not implement as we don't need + // IGraphicBufferConsumer parity. + value = 0; + break; + // The following queries are currently considered as unsupported. + // TODO(jwcai) Need to carefully check the whether they should be + // supported after all. + case NATIVE_WINDOW_STICKY_TRANSFORM: case NATIVE_WINDOW_DEFAULT_DATASPACE: default: return BAD_VALUE; @@ -282,24 +423,58 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { } status_t BufferHubQueueProducer::connect( - const sp<IProducerListener>& /* listener */, int /* api */, - bool /* producer_controlled_by_app */, QueueBufferOutput* /* output */) { + const sp<IProducerListener>& /* listener */, int api, + bool /* producer_controlled_by_app */, QueueBufferOutput* output) { // Consumer interaction are actually handled by buffer hub, and we need - // to maintain consumer operations here. Hence |connect| is a NO-OP. + // to maintain consumer operations here. We only need to perform basic input + // parameter checks here. ALOGD_IF(TRACE, __FUNCTION__); + + if (output == nullptr) { + return BAD_VALUE; + } + + std::unique_lock<std::mutex> lock(core_->mutex_); + + if (core_->connected_api_ != BufferHubQueueCore::kNoConnectedApi) { + return BAD_VALUE; + } + + switch (api) { + case NATIVE_WINDOW_API_EGL: + case NATIVE_WINDOW_API_CPU: + case NATIVE_WINDOW_API_MEDIA: + case NATIVE_WINDOW_API_CAMERA: + core_->connected_api_ = api; + // TODO(jwcai) Fill output. + break; + default: + ALOGE("BufferHubQueueProducer::connect: unknow API %d", api); + return BAD_VALUE; + } + return NO_ERROR; } -status_t BufferHubQueueProducer::disconnect(int /* api */, DisconnectMode /* mode */) { +status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode mode) { // Consumer interaction are actually handled by buffer hub, and we need - // to maintain consumer operations here. Hence |disconnect| is a NO-OP. + // to maintain consumer operations here. We only need to perform basic input + // parameter checks here. ALOGD_IF(TRACE, __FUNCTION__); + + std::unique_lock<std::mutex> lock(core_->mutex_); + + if (api != core_->connected_api_) { + return BAD_VALUE; + } + + core_->connected_api_ = BufferHubQueueCore::kNoConnectedApi; return NO_ERROR; } status_t BufferHubQueueProducer::setSidebandStream( const sp<NativeHandle>& stream) { - if (stream != NULL) { + if (stream != nullptr) { // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's // metadata. ALOGE("SidebandStream is not currently supported."); @@ -314,7 +489,7 @@ void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */, uint32_t /* usage */) { // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number // of buffers permitted by the current BufferQueue configuration (aka - // |req_buffer_count_|). + // |max_buffer_count_|). ALOGE("BufferHubQueueProducer::allocateBuffers not implemented."); } @@ -343,6 +518,7 @@ String8 BufferHubQueueProducer::getConsumerName() const { status_t BufferHubQueueProducer::setSharedBufferMode( bool /* shared_buffer_mode */) { ALOGE("BufferHubQueueProducer::setSharedBufferMode not implemented."); + // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow. return INVALID_OPERATION; } 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 f786356cce..a020dca7f9 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 @@ -32,6 +32,15 @@ class BufferHubQueue : public pdx::Client { // a new consumer queue client or nullptr on failure. std::unique_ptr<ConsumerQueue> CreateConsumerQueue(); + // Return the default buffer width of this buffer queue. + size_t default_width() const { return default_width_; } + + // Return the default buffer height of this buffer queue. + size_t default_height() const { return default_height_; } + + // Return the default buffer format of this buffer queue. + int32_t default_format() const { return default_format_; } + // Return the number of buffers avaiable for dequeue. size_t count() const { return available_buffers_.GetSize(); } @@ -169,6 +178,18 @@ class BufferHubQueue : public pdx::Client { void operator=(BufferInfo&) = delete; }; + // Default buffer width that can be set to override the buffer width when a + // width and height of 0 are specified in AllocateBuffer. + size_t default_width_{1}; + + // Default buffer height that can be set to override the buffer height when a + // width and height of 0 are specified in AllocateBuffer. + size_t default_height_{1}; + + // Default buffer format that can be set to override the buffer format when it + // isn't specified in AllocateBuffer. + int32_t default_format_{PIXEL_FORMAT_RGBA_8888}; + // Buffer queue: // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|. std::vector<std::shared_ptr<BufferHubBuffer>> buffers_; diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h index ba0c0c5f2e..e353187701 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h @@ -17,6 +17,8 @@ class BufferHubQueueCore { friend class BufferHubQueueProducer; public: + static constexpr int kNoConnectedApi = -1; + // Create a BufferHubQueueCore instance by creating a new producer queue. static std::shared_ptr<BufferHubQueueCore> Create(); @@ -87,6 +89,9 @@ class BufferHubQueueCore { // Mutex for thread safety. std::mutex mutex_; + // Connect client API, should be one of the NATIVE_WINDOW_API_* flags. + int connected_api_{kNoConnectedApi}; + // |buffers_| stores the buffers that have been dequeued from // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets // filled in with the result of |Dequeue|. 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 5b1a7e0c76..43e5ce30b8 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 @@ -103,13 +103,15 @@ class BufferHubQueueProducer : public IGraphicBufferProducer { private: using LocalHandle = pdx::LocalHandle; - static constexpr int kInvalidBufferCount = -1; - // |core_| holds the actually buffer slots. std::shared_ptr<BufferHubQueueCore> core_; - // |req_buffer_count_| sets the capacity of the underlying buffer queue. - int32_t req_buffer_count_; + // |max_buffer_count_| sets the capacity of the underlying buffer queue. + int32_t max_buffer_count_{BufferHubQueue::kMaxQueueCapacity}; + + // |max_dequeued_buffer_count_| set the maximum number of buffers that can + // be dequeued at the same momment. + int32_t max_dequeued_buffer_count_{1}; }; } // 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 5bb121aeb9..64034e8800 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp @@ -1,7 +1,9 @@ #include <private/dvr/buffer_hub_queue_producer.h> #include <base/logging.h> +#include <gui/IProducerListener.h> #include <gui/Surface.h> + #include <gtest/gtest.h> namespace android { @@ -9,12 +11,500 @@ namespace dvr { namespace { -class BufferHubQueueProducerTest : public ::testing::Test {}; +// Default dimensions before setDefaultBufferSize is called by the consumer. +constexpr uint32_t kDefaultWidth = 1; +constexpr uint32_t kDefaultHeight = 1; + +// Default format before setDefaultBufferFormat is called by the consumer. +constexpr PixelFormat kDefaultFormat = HAL_PIXEL_FORMAT_RGBA_8888; +constexpr int kDefaultConsumerUsageBits = 0; + +// Default transform hint before setTransformHint is called by the consumer. +constexpr uint32_t kDefaultTransformHint = 0; + +constexpr int kTestApi = NATIVE_WINDOW_API_CPU; +constexpr int kTestApiOther = NATIVE_WINDOW_API_EGL; +constexpr int kTestApiInvalid = 0xDEADBEEF; +constexpr int kTestProducerUsageBits = 0; +constexpr bool kTestControlledByApp = true; + +// Builder pattern to slightly vary *almost* correct input +// -- avoids copying and pasting +struct QueueBufferInputBuilder { + IGraphicBufferProducer::QueueBufferInput build() { + return IGraphicBufferProducer::QueueBufferInput( + mTimestamp, mIsAutoTimestamp, mDataSpace, mCrop, mScalingMode, + mTransform, mFence); + } + + QueueBufferInputBuilder& setTimestamp(int64_t timestamp) { + this->mTimestamp = timestamp; + return *this; + } + + QueueBufferInputBuilder& setIsAutoTimestamp(bool isAutoTimestamp) { + this->mIsAutoTimestamp = isAutoTimestamp; + return *this; + } + + QueueBufferInputBuilder& setDataSpace(android_dataspace dataSpace) { + this->mDataSpace = dataSpace; + return *this; + } + + QueueBufferInputBuilder& setCrop(Rect crop) { + this->mCrop = crop; + return *this; + } + + QueueBufferInputBuilder& setScalingMode(int scalingMode) { + this->mScalingMode = scalingMode; + return *this; + } + + QueueBufferInputBuilder& setTransform(uint32_t transform) { + this->mTransform = transform; + return *this; + } + + QueueBufferInputBuilder& setFence(sp<Fence> fence) { + this->mFence = fence; + return *this; + } + + private: + int64_t mTimestamp{1384888611}; + bool mIsAutoTimestamp{false}; + android_dataspace mDataSpace{HAL_DATASPACE_UNKNOWN}; + Rect mCrop{Rect(kDefaultWidth, kDefaultHeight)}; + int mScalingMode{0}; + uint32_t mTransform{0}; + sp<Fence> mFence{Fence::NO_FENCE}; +}; + +// This is a test that covers our implementation of bufferhubqueue-based +// IGraphicBufferProducer. +class BufferHubQueueProducerTest : public ::testing::Test { + protected: + virtual void SetUp() { + const ::testing::TestInfo* const testInfo = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(), + testInfo->name()); + + auto core = BufferHubQueueCore::Create(); + mProducer = new BufferHubQueueProducer(core); + ASSERT_TRUE(mProducer != nullptr); + mSurface = new Surface(mProducer, true); + ASSERT_TRUE(mSurface != nullptr); + } + + // Connect to a producer in a 'correct' fashion. + void ConnectProducer() { + IGraphicBufferProducer::QueueBufferOutput output; + // Can connect the first time. + ASSERT_EQ(NO_ERROR, mProducer->connect(kDummyListener, kTestApi, + kTestControlledByApp, &output)); + } + + // Dequeue a buffer in a 'correct' fashion. + // Precondition: Producer is connected. + void DequeueBuffer(int* outSlot) { + sp<Fence> fence; + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(outSlot, &fence)); + } + + void DequeueBuffer(int* outSlot, sp<Fence>* outFence) { + ASSERT_NE(nullptr, outSlot); + ASSERT_NE(nullptr, outFence); + + int ret = mProducer->dequeueBuffer(outSlot, outFence, kDefaultWidth, + kDefaultHeight, kDefaultFormat, + kTestProducerUsageBits, nullptr); + // BUFFER_NEEDS_REALLOCATION can be either on or off. + ASSERT_EQ(0, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & ret); + + // Slot number should be in boundary. + ASSERT_LE(0, *outSlot); + ASSERT_GT(BufferQueueDefs::NUM_BUFFER_SLOTS, *outSlot); + } + + // Create a generic "valid" input for queueBuffer + // -- uses the default buffer format, width, etc. + static IGraphicBufferProducer::QueueBufferInput CreateBufferInput() { + return QueueBufferInputBuilder().build(); + } + + const sp<IProducerListener> kDummyListener{new DummyProducerListener}; + + sp<BufferHubQueueProducer> mProducer; + sp<Surface> mSurface; +}; + +TEST_F(BufferHubQueueProducerTest, ConnectFirst_ReturnsError) { + IGraphicBufferProducer::QueueBufferOutput output; + + // NULL output returns BAD_VALUE + EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApi, + kTestControlledByApp, nullptr)); + + // Invalid API returns bad value + EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApiInvalid, + kTestControlledByApp, &output)); +} + +TEST_F(BufferHubQueueProducerTest, ConnectAgain_ReturnsError) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + // Can't connect when there is already a producer connected. + IGraphicBufferProducer::QueueBufferOutput output; + EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApi, + kTestControlledByApp, &output)); +} + +TEST_F(BufferHubQueueProducerTest, Disconnect_Succeeds) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); +} + +TEST_F(BufferHubQueueProducerTest, Disconnect_ReturnsError) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + // Must disconnect with same API number + EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiOther)); + // API must not be out of range + EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiInvalid)); +} + +TEST_F(BufferHubQueueProducerTest, Query_Succeeds) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + int32_t value = -1; + EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value)); + EXPECT_EQ(kDefaultWidth, static_cast<uint32_t>(value)); + + EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_HEIGHT, &value)); + EXPECT_EQ(kDefaultHeight, static_cast<uint32_t>(value)); + + EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); + EXPECT_EQ(kDefaultFormat, value); + + EXPECT_EQ(NO_ERROR, + mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value)); + EXPECT_LE(0, value); + EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, static_cast<size_t>(value)); + + EXPECT_EQ(NO_ERROR, + mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value)); + EXPECT_FALSE(value); // Can't run behind when we haven't touched the queue + + EXPECT_EQ(NO_ERROR, + mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &value)); + EXPECT_EQ(kDefaultConsumerUsageBits, value); +} + +TEST_F(BufferHubQueueProducerTest, Query_ReturnsError) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + // One past the end of the last 'query' enum value. Update this if we add more + // enums. + const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1; + + int value; + // What was out of range + EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ -1, &value)); + EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ 0xDEADBEEF, &value)); + EXPECT_EQ(BAD_VALUE, + mProducer->query(NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE, &value)); + + // Some enums from window.h are 'invalid' + EXPECT_EQ(BAD_VALUE, + mProducer->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &value)); + EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_CONCRETE_TYPE, &value)); + EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_WIDTH, &value)); + EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_HEIGHT, &value)); + EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_TRANSFORM_HINT, &value)); + + // Value was NULL + EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/ NULL)); +} + +TEST_F(BufferHubQueueProducerTest, Queue_Succeeds) { + int slot = -1; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + + // Request the buffer (pre-requisite for queueing) + sp<GraphicBuffer> buffer; + ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + + // A generic "valid" input + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + + // Queue the buffer back into the BQ + ASSERT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output)); + + EXPECT_EQ(kDefaultWidth, output.width); + EXPECT_EQ(kDefaultHeight, output.height); + EXPECT_EQ(kDefaultTransformHint, output.transformHint); + + // BufferHubQueue delivers buffers to consumer immediately. + EXPECT_EQ(0u, output.numPendingBuffers); + + // Note that BufferHubQueue doesn't support nextFrameNumber as it seems to + // be a SurfaceFlinger specific optimization. + EXPECT_EQ(0u, output.nextFrameNumber); + + // Buffer was not in the dequeued state + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); +} + +// Test invalid slot number +TEST_F(BufferHubQueueProducerTest, QueueInvalidSlot_ReturnsError) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + // A generic "valid" input + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ -1, input, &output)); + EXPECT_EQ(BAD_VALUE, + mProducer->queueBuffer(/*slot*/ 0xDEADBEEF, input, &output)); + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(BufferQueueDefs::NUM_BUFFER_SLOTS, + input, &output)); +} + +// Slot was not in the dequeued state (all slots start out in Free state) +TEST_F(BufferHubQueueProducerTest, QueueNotDequeued_ReturnsError) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ 0, input, &output)); +} + +// Slot was enqueued without requesting a buffer +TEST_F(BufferHubQueueProducerTest, QueueNotRequested_ReturnsError) { + int slot = -1; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); +} + +// Test when fence was NULL +TEST_F(BufferHubQueueProducerTest, QueueNoFence_ReturnsError) { + int slot = -1; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + + sp<GraphicBuffer> buffer; + ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + + sp<Fence> nullFence = NULL; + + IGraphicBufferProducer::QueueBufferInput input = + QueueBufferInputBuilder().setFence(nullFence).build(); + IGraphicBufferProducer::QueueBufferOutput output; + + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); +} + +// Test scaling mode was invalid +TEST_F(BufferHubQueueProducerTest, QueueTestInvalidScalingMode_ReturnsError) { + int slot = -1; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + + sp<GraphicBuffer> buffer; + ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + + IGraphicBufferProducer::QueueBufferInput input = + QueueBufferInputBuilder().setScalingMode(-1).build(); + IGraphicBufferProducer::QueueBufferOutput output; + + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); + + input = QueueBufferInputBuilder().setScalingMode(0xDEADBEEF).build(); + + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); +} + +// Test crop rect is out of bounds of the buffer dimensions +TEST_F(BufferHubQueueProducerTest, QueueCropOutOfBounds_ReturnsError) { + int slot = -1; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + + sp<GraphicBuffer> buffer; + ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + + IGraphicBufferProducer::QueueBufferInput input = + QueueBufferInputBuilder() + .setCrop(Rect(kDefaultWidth + 1, kDefaultHeight + 1)) + .build(); + IGraphicBufferProducer::QueueBufferOutput output; + + EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); +} + +TEST_F(BufferHubQueueProducerTest, CancelBuffer_Succeeds) { + int slot = -1; + sp<Fence> fence; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence)); + + // Should be able to cancel buffer after a dequeue. + EXPECT_EQ(NO_ERROR, mProducer->cancelBuffer(slot, fence)); +} + +TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Succeeds) { + return; + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + int minUndequeuedBuffers; + ASSERT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers)); + + const int minBuffers = 1; + const int maxBuffers = + BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers; + + ASSERT_EQ(NO_ERROR, mProducer->setAsyncMode(false)) + << "async mode: " << false; + ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(minBuffers)) + << "bufferCount: " << minBuffers; + + // Should now be able to dequeue up to minBuffers times + // Should now be able to dequeue up to maxBuffers times + int slot = -1; + for (int i = 0; i < minBuffers; ++i) { + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + } + + ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxBuffers)); + + // queue the first buffer to enable max dequeued buffer count checking + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + sp<GraphicBuffer> buffer; + ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + ASSERT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output)); + + sp<Fence> fence; + for (int i = 0; i < maxBuffers; ++i) { + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence)); + } + + // Cancel a buffer, so we can decrease the buffer count + ASSERT_EQ(NO_ERROR, mProducer->cancelBuffer(slot, fence)); + + // Should now be able to decrease the max dequeued count by 1 + ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxBuffers - 1)); +} + +TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Fails) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + int minUndequeuedBuffers; + ASSERT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers)); + + const int minBuffers = 1; + const int maxBuffers = + BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers; + + ASSERT_EQ(NO_ERROR, mProducer->setAsyncMode(false)) + << "async mode: " << false; + // Buffer count was out of range + EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0)) + << "bufferCount: " << 0; + EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1)) + << "bufferCount: " << maxBuffers + 1; + + // Set max dequeue count to 2 + ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(2)); + // Dequeue 2 buffers + int slot = -1; + sp<Fence> fence; + for (int i = 0; i < 2; i++) { + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer( + &slot, &fence, kDefaultWidth, kDefaultHeight, + kDefaultFormat, kTestProducerUsageBits, nullptr))) + << "slot: " << slot; + } + + // Client has too many buffers dequeued + EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(1)) + << "bufferCount: " << minBuffers; +} + +TEST_F(BufferHubQueueProducerTest, + DisconnectedProducerReturnsError_dequeueBuffer) { + int slot = -1; + sp<Fence> fence; + + ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth, + kDefaultHeight, kDefaultFormat, + kTestProducerUsageBits, nullptr)); +} + +TEST_F(BufferHubQueueProducerTest, + DisconnectedProducerReturnsError_requestBuffer) { + int slot = -1; + sp<GraphicBuffer> buffer; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + + // Shouldn't be able to request buffer after disconnect. + ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); + ASSERT_EQ(NO_INIT, mProducer->requestBuffer(slot, &buffer)); +} + +TEST_F(BufferHubQueueProducerTest, + DisconnectedProducerReturnsError_queueBuffer) { + int slot = -1; + sp<GraphicBuffer> buffer; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + + // A generic "valid" input + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + + // Shouldn't be able to queue buffer after disconnect. + ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); + ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output)); +} + +TEST_F(BufferHubQueueProducerTest, + DisconnectedProducerReturnsError_cancelBuffer) { + int slot = -1; + sp<GraphicBuffer> buffer; + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); -TEST_F(BufferHubQueueProducerTest, TempTestBufferHubQueueProducer) { - auto core = BufferHubQueueCore::Create(); - sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer(core); - sp<Surface> surface = new Surface(producer, true); + // Shouldn't be able to cancel buffer after disconnect. + ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); + ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE)); } } // namespace diff --git a/libs/vr/libdvr/Android.mk b/libs/vr/libdvr/Android.mk index 5449cb5866..3c6934bdcc 100644 --- a/libs/vr/libdvr/Android.mk +++ b/libs/vr/libdvr/Android.mk @@ -33,6 +33,7 @@ LOCAL_SRC_FILES := \ dvr_api.cpp \ dvr_buffer.cpp \ dvr_buffer_queue.cpp \ + dvr_hardware_composer_client.cpp \ dvr_surface.cpp \ vsync_client_api.cpp \ @@ -42,12 +43,15 @@ LOCAL_STATIC_LIBRARIES := \ libdisplay \ libvrsensor \ libvirtualtouchpadclient \ + libvr_hwc-impl \ + libvr_hwc-binder \ LOCAL_SHARED_LIBRARIES := \ android.hardware.graphics.bufferqueue@1.0 \ android.hidl.token@1.0-utils \ libandroid_runtime \ libbase \ + libnativewindow \ include $(BUILD_STATIC_LIBRARY) diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp index 5aa96527e7..f786c29e1d 100644 --- a/libs/vr/libdvr/dvr_api.cpp +++ b/libs/vr/libdvr/dvr_api.cpp @@ -11,6 +11,7 @@ // Headers not yet moved into libdvr. // TODO(jwcai) Move these once their callers are moved into Google3. +#include <dvr/dvr_hardware_composer_client.h> #include <dvr/pose_client.h> #include <dvr/virtual_touchpad_client.h> @@ -24,81 +25,101 @@ DVR_EXPORT int dvrGetApi(void* api, size_t struct_size, int version) { DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api); // display_manager_client.h - dvr_api->display_manager_client_create_ = dvrDisplayManagerClientCreate; - dvr_api->display_manager_client_destroy_ = dvrDisplayManagerClientDestroy; - dvr_api->display_manager_client_get_surface_list_ = + dvr_api->display_manager_client_create = dvrDisplayManagerClientCreate; + dvr_api->display_manager_client_destroy = dvrDisplayManagerClientDestroy; + dvr_api->display_manager_client_get_surface_list = dvrDisplayManagerClientGetSurfaceList; - dvr_api->display_manager_client_surface_list_destroy_ = + dvr_api->display_manager_client_surface_list_destroy = dvrDisplayManagerClientSurfaceListDestroy; - dvr_api->display_manager_setup_pose_buffer_ = + dvr_api->display_manager_setup_pose_buffer = dvrDisplayManagerSetupPoseBuffer; - dvr_api->display_manager_client_surface_list_get_size_ = + dvr_api->display_manager_client_surface_list_get_size = dvrDisplayManagerClientSurfaceListGetSize; - dvr_api->display_manager_client_surface_list_get_surface_id_ = + dvr_api->display_manager_client_surface_list_get_surface_id = dvrDisplayManagerClientSurfaceListGetSurfaceId; - dvr_api->display_manager_client_get_surface_buffer_list_ = + dvr_api->display_manager_client_get_surface_buffer_list = dvrDisplayManagerClientGetSurfaceBuffers; - dvr_api->display_manager_client_surface_buffer_list_destroy_ = + dvr_api->display_manager_client_surface_buffer_list_destroy = dvrDisplayManagerClientSurfaceBuffersDestroy; - dvr_api->display_manager_client_surface_buffer_list_get_size_ = + dvr_api->display_manager_client_surface_buffer_list_get_size = dvrDisplayManagerClientSurfaceBuffersGetSize; - dvr_api->display_manager_client_surface_buffer_list_get_fd_ = + dvr_api->display_manager_client_surface_buffer_list_get_fd = dvrDisplayManagerClientSurfaceBuffersGetFd; // dvr_buffer.h - dvr_api->write_buffer_destroy_ = dvrWriteBufferDestroy; - dvr_api->write_buffer_get_blob_fds_ = dvrWriteBufferGetBlobFds; - dvr_api->write_buffer_get_AHardwareBuffer_ = + dvr_api->write_buffer_destroy = dvrWriteBufferDestroy; + dvr_api->write_buffer_get_blob_fds = dvrWriteBufferGetBlobFds; + dvr_api->write_buffer_get_ahardwarebuffer = dvrWriteBufferGetAHardwareBuffer; - dvr_api->write_buffer_post_ = dvrWriteBufferPost; - dvr_api->write_buffer_gain_ = dvrWriteBufferGain; - dvr_api->write_buffer_gain_async_ = dvrWriteBufferGainAsync; + dvr_api->write_buffer_post = dvrWriteBufferPost; + dvr_api->write_buffer_gain = dvrWriteBufferGain; + dvr_api->write_buffer_gain_async = dvrWriteBufferGainAsync; - dvr_api->read_buffer_destroy_ = dvrReadBufferDestroy; - dvr_api->read_buffer_get_blob_fds_ = dvrReadBufferGetBlobFds; - dvr_api->read_buffer_get_AHardwareBuffer_ = dvrReadBufferGetAHardwareBuffer; - dvr_api->read_buffer_acquire_ = dvrReadBufferAcquire; - dvr_api->read_buffer_release_ = dvrReadBufferRelease; - dvr_api->read_buffer_release_async_ = dvrReadBufferReleaseAsync; + dvr_api->read_buffer_destroy = dvrReadBufferDestroy; + dvr_api->read_buffer_get_blob_fds = dvrReadBufferGetBlobFds; + dvr_api->read_buffer_get_ahardwarebuffer = dvrReadBufferGetAHardwareBuffer; + dvr_api->read_buffer_acquire = dvrReadBufferAcquire; + dvr_api->read_buffer_release = dvrReadBufferRelease; + dvr_api->read_buffer_release_async = dvrReadBufferReleaseAsync; // dvr_buffer_queue.h - dvr_api->write_buffer_queue_destroy_ = dvrWriteBufferQueueDestroy; - dvr_api->write_buffer_queue_get_capacity_ = dvrWriteBufferQueueGetCapacity; - dvr_api->write_buffer_queue_get_external_surface_ = + dvr_api->write_buffer_queue_destroy = dvrWriteBufferQueueDestroy; + dvr_api->write_buffer_queue_get_capacity = dvrWriteBufferQueueGetCapacity; + dvr_api->write_buffer_queue_get_external_surface = dvrWriteBufferQueueGetExternalSurface; - dvr_api->write_buffer_queue_create_read_queue_ = + dvr_api->write_buffer_queue_create_read_queue = dvrWriteBufferQueueCreateReadQueue; - dvr_api->write_buffer_queue_dequeue_ = dvrWriteBufferQueueDequeue; - dvr_api->read_buffer_queue_destroy_ = dvrReadBufferQueueDestroy; - dvr_api->read_buffer_queue_get_capacity_ = dvrReadBufferQueueGetCapacity; - dvr_api->read_buffer_queue_create_read_queue_ = + dvr_api->write_buffer_queue_dequeue = dvrWriteBufferQueueDequeue; + dvr_api->read_buffer_queue_destroy = dvrReadBufferQueueDestroy; + dvr_api->read_buffer_queue_get_capacity = dvrReadBufferQueueGetCapacity; + dvr_api->read_buffer_queue_create_read_queue = dvrReadBufferQueueCreateReadQueue; dvr_api->read_buffer_queue_dequeue = dvrReadBufferQueueDequeue; // dvr_surface.h - dvr_api->get_pose_buffer_ = dvrGetPoseBuffer; - dvr_api->surface_create_ = dvrSurfaceCreate; - dvr_api->surface_get_write_buffer_queue_ = dvrSurfaceGetWriteBufferQueue; + dvr_api->get_pose_buffer = dvrGetPoseBuffer; + dvr_api->surface_create = dvrSurfaceCreate; + dvr_api->surface_get_write_buffer_queue = dvrSurfaceGetWriteBufferQueue; // vsync_client_api.h - dvr_api->vsync_client_create_ = dvr_vsync_client_create; - dvr_api->vsync_client_destroy_ = dvr_vsync_client_destroy; - dvr_api->vsync_client_get_sched_info_ = dvr_vsync_client_get_sched_info; + dvr_api->vsync_client_create = dvr_vsync_client_create; + dvr_api->vsync_client_destroy = dvr_vsync_client_destroy; + dvr_api->vsync_client_get_sched_info = dvr_vsync_client_get_sched_info; // pose_client.h - dvr_api->pose_client_create_ = dvrPoseCreate; - dvr_api->pose_client_destroy_ = dvrPoseDestroy; - dvr_api->pose_get_ = dvrPoseGet; - dvr_api->pose_get_vsync_count_ = dvrPoseGetVsyncCount; - dvr_api->pose_get_controller_ = dvrPoseGetController; + dvr_api->pose_client_create = dvrPoseCreate; + dvr_api->pose_client_destroy = dvrPoseDestroy; + dvr_api->pose_get = dvrPoseGet; + dvr_api->pose_get_vsync_count = dvrPoseGetVsyncCount; + dvr_api->pose_get_controller = dvrPoseGetController; // virtual_touchpad_client.h - dvr_api->virtual_touchpad_create_ = dvrVirtualTouchpadCreate; - dvr_api->virtual_touchpad_destroy_ = dvrVirtualTouchpadDestroy; - dvr_api->virtual_touchpad_attach_ = dvrVirtualTouchpadAttach; - dvr_api->virtual_touchpad_detach_ = dvrVirtualTouchpadDetach; - dvr_api->virtual_touchpad_touch_ = dvrVirtualTouchpadTouch; - dvr_api->virtual_touchpad_button_state_ = dvrVirtualTouchpadButtonState; + dvr_api->virtual_touchpad_create = dvrVirtualTouchpadCreate; + dvr_api->virtual_touchpad_destroy = dvrVirtualTouchpadDestroy; + dvr_api->virtual_touchpad_attach = dvrVirtualTouchpadAttach; + dvr_api->virtual_touchpad_detach = dvrVirtualTouchpadDetach; + dvr_api->virtual_touchpad_touch = dvrVirtualTouchpadTouch; + dvr_api->virtual_touchpad_button_state = dvrVirtualTouchpadButtonState; + + // dvr_hardware_composer_client.h + dvr_api->hwc_client_create = dvrHwcClientCreate; + dvr_api->hwc_client_destroy = dvrHwcClientDestroy; + dvr_api->hwc_frame_destroy = dvrHwcFrameDestroy; + dvr_api->hwc_frame_get_display_id = dvrHwcFrameGetDisplayId; + dvr_api->hwc_frame_get_display_width = dvrHwcFrameGetDisplayWidth; + dvr_api->hwc_frame_get_display_height = dvrHwcFrameGetDisplayHeight; + dvr_api->hwc_frame_get_layer_count = dvrHwcFrameGetLayerCount; + dvr_api->hwc_frame_get_layer_id = dvrHwcFrameGetLayerId; + dvr_api->hwc_frame_get_layer_buffer = dvrHwcFrameGetLayerBuffer; + dvr_api->hwc_frame_get_layer_fence = dvrHwcFrameGetLayerFence; + dvr_api->hwc_frame_get_layer_display_frame = + dvrHwcFrameGetLayerDisplayFrame; + dvr_api->hwc_frame_get_layer_crop = dvrHwcFrameGetLayerCrop; + dvr_api->hwc_frame_get_layer_blend_mode = dvrHwcFrameGetLayerBlendMode; + dvr_api->hwc_frame_get_layer_alpha = dvrHwcFrameGetLayerAlpha; + dvr_api->hwc_frame_get_layer_type = dvrHwcFrameGetLayerType; + dvr_api->hwc_frame_get_layer_application_id = + dvrHwcFrameGetLayerApplicationId; return 0; } diff --git a/services/vr/hardware_composer/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp index 39fa9fc305..e5665e152f 100644 --- a/services/vr/hardware_composer/dvr_hardware_composer_client.cpp +++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp @@ -1,7 +1,8 @@ -#include "private/android/dvr_hardware_composer_client.h" +#include "include/dvr/dvr_hardware_composer_client.h" #include <android/dvr/IVrComposer.h> #include <android/dvr/BnVrComposerCallback.h> +#include <android/hardware_buffer.h> #include <binder/IServiceManager.h> #include <private/android/AHardwareBufferHelpers.h> @@ -15,7 +16,8 @@ namespace { class HwcCallback : public android::dvr::BnVrComposerCallback { public: - explicit HwcCallback(DvrHwcOnFrameCallback callback); + explicit HwcCallback(DvrHwcOnFrameCallback callback, + void* client_state); ~HwcCallback() override; std::unique_ptr<DvrHwcFrame> DequeueFrame(); @@ -27,13 +29,14 @@ class HwcCallback : public android::dvr::BnVrComposerCallback { android::dvr::ParcelableUniqueFd* fence) override; DvrHwcOnFrameCallback callback_; + void* client_state_; HwcCallback(const HwcCallback&) = delete; void operator=(const HwcCallback&) = delete; }; -HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback) - : callback_(callback) {} +HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback, void* client_state) + : callback_(callback), client_state_(client_state) {} HwcCallback::~HwcCallback() {} @@ -43,7 +46,8 @@ android::binder::Status HwcCallback::onNewFrame( std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame()); dvr_frame->frame = frame.frame(); - fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release()))); + fence->set_fence(android::base::unique_fd(callback_(client_state_, + dvr_frame.release()))); return android::binder::Status::ok(); } @@ -54,7 +58,7 @@ struct DvrHwcClient { android::sp<HwcCallback> callback; }; -DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback) { +DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) { std::unique_ptr<DvrHwcClient> client(new DvrHwcClient()); android::sp<android::IServiceManager> sm(android::defaultServiceManager()); @@ -63,7 +67,7 @@ DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback) { if (!client->composer.get()) return nullptr; - client->callback = new HwcCallback(callback); + client->callback = new HwcCallback(callback, data); android::binder::Status status = client->composer->registerObserver( client->callback); if (!status.isOk()) @@ -72,6 +76,10 @@ DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback) { return client.release(); } +void dvrHwcClientDestroy(DvrHwcClient* client) { + delete client; +} + void dvrHwcFrameDestroy(DvrHwcFrame* frame) { delete frame; } @@ -80,6 +88,18 @@ Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) { return frame->frame.display_id; } +int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame) { + return frame->frame.display_width; +} + +int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame) { + return frame->frame.display_height; +} + +bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame) { + return frame->frame.removed; +} + size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) { return frame->frame.layers.size(); } diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index bee4d66539..053382f28c 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -5,6 +5,7 @@ #include <stddef.h> #include <stdint.h> +#include <dvr/dvr_hardware_composer_defs.h> #include <jni.h> #ifdef __cplusplus @@ -144,82 +145,132 @@ typedef int (*DvrVirtualTouchpadTouchPtr)(DvrVirtualTouchpad* client, typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client, int touchpad, int buttons); +// dvr_hardware_composer_client.h +typedef struct DvrHwcClient DvrHwcClient; +typedef struct DvrHwcFrame DvrHwcFrame; +typedef int(*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame); +typedef DvrHwcClient* (*DvrHwcClientCreatePtr)(DvrHwcOnFrameCallback callback, + void* client_state); +typedef void (*DvrHwcClientDestroyPtr)(DvrHwcClient* client); +typedef void (*DvrHwcFrameDestroyPtr)(DvrHwcFrame* frame); +typedef Display (*DvrHwcFrameGetDisplayIdPtr)(DvrHwcFrame* frame); +typedef int32_t (*DvrHwcFrameGetDisplayWidthPtr)(DvrHwcFrame* frame); +typedef int32_t (*DvrHwcFrameGetDisplayHeightPtr)(DvrHwcFrame* frame); +typedef bool (*DvrHwcFrameGetDisplayRemovedPtr)(DvrHwcFrame* frame); +typedef size_t (*DvrHwcFrameGetLayerCountPtr)(DvrHwcFrame* frame); +typedef Layer (*DvrHwcFrameGetLayerIdPtr)(DvrHwcFrame* frame, size_t layer_index); +typedef AHardwareBuffer* (*DvrHwcFrameGetLayerBufferPtr)(DvrHwcFrame* frame, + size_t layer_index); +typedef int (*DvrHwcFrameGetLayerFencePtr)(DvrHwcFrame* frame, + size_t layer_index); +typedef Recti (*DvrHwcFrameGetLayerDisplayFramePtr)(DvrHwcFrame* frame, + size_t layer_index); +typedef Rectf (*DvrHwcFrameGetLayerCropPtr)(DvrHwcFrame* frame, + size_t layer_index); +typedef BlendMode (*DvrHwcFrameGetLayerBlendModePtr)(DvrHwcFrame* frame, + size_t layer_index); +typedef float (*DvrHwcFrameGetLayerAlphaPtr)(DvrHwcFrame* frame, + size_t layer_index); +typedef uint32_t (*DvrHwcFrameGetLayerTypePtr)(DvrHwcFrame* frame, + size_t layer_index); +typedef uint32_t (*DvrHwcFrameGetLayerApplicationIdPtr)(DvrHwcFrame* frame, + size_t layer_index); + struct DvrApi_v1 { // Display manager client - DvrDisplayManagerClientCreatePtr display_manager_client_create_; - DvrDisplayManagerClientDestroyPtr display_manager_client_destroy_; + DvrDisplayManagerClientCreatePtr display_manager_client_create; + DvrDisplayManagerClientDestroyPtr display_manager_client_destroy; DvrDisplayManagerClientGetSurfaceListPtr - display_manager_client_get_surface_list_; + display_manager_client_get_surface_list; DvrDisplayManagerClientSurfaceListDestroyPtr - display_manager_client_surface_list_destroy_; - DvrDisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer_; + display_manager_client_surface_list_destroy; + DvrDisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer; DvrDisplayManagerClientSurfaceListGetSizePtr - display_manager_client_surface_list_get_size_; + display_manager_client_surface_list_get_size; DvrDisplayManagerClientSurfaceListGetSurfaceIdPtr - display_manager_client_surface_list_get_surface_id_; + display_manager_client_surface_list_get_surface_id; DvrDisplayManagerClientGetSurfaceBufferListPtr - display_manager_client_get_surface_buffer_list_; + display_manager_client_get_surface_buffer_list; DvrDisplayManagerClientSurfaceBufferListDestroyPtr - display_manager_client_surface_buffer_list_destroy_; + display_manager_client_surface_buffer_list_destroy; DvrDisplayManagerClientSurfaceBufferListGetSizePtr - display_manager_client_surface_buffer_list_get_size_; + display_manager_client_surface_buffer_list_get_size; DvrDisplayManagerClientSurfaceBufferListGetFdPtr - display_manager_client_surface_buffer_list_get_fd_; + display_manager_client_surface_buffer_list_get_fd; // Write buffer - DvrWriteBufferDestroyPtr write_buffer_destroy_; - DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds_; - DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_AHardwareBuffer_; - DvrWriteBufferPostPtr write_buffer_post_; - DvrWriteBufferGainPtr write_buffer_gain_; - DvrWriteBufferGainAsyncPtr write_buffer_gain_async_; + DvrWriteBufferDestroyPtr write_buffer_destroy; + DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds; + DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_ahardwarebuffer; + DvrWriteBufferPostPtr write_buffer_post; + DvrWriteBufferGainPtr write_buffer_gain; + DvrWriteBufferGainAsyncPtr write_buffer_gain_async; // Read buffer - DvrReadBufferDestroyPtr read_buffer_destroy_; - DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds_; - DvrReadBufferGetAHardwareBufferPtr read_buffer_get_AHardwareBuffer_; - DvrReadBufferAcquirePtr read_buffer_acquire_; - DvrReadBufferReleasePtr read_buffer_release_; - DvrReadBufferReleaseAsyncPtr read_buffer_release_async_; + DvrReadBufferDestroyPtr read_buffer_destroy; + DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds; + DvrReadBufferGetAHardwareBufferPtr read_buffer_get_ahardwarebuffer; + DvrReadBufferAcquirePtr read_buffer_acquire; + DvrReadBufferReleasePtr read_buffer_release; + DvrReadBufferReleaseAsyncPtr read_buffer_release_async; // Write buffer queue - DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy_; - DvrWriteBufferQueueGetCapacityPtr write_buffer_queue_get_capacity_; + DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy; + DvrWriteBufferQueueGetCapacityPtr write_buffer_queue_get_capacity; DvrWriteBufferQueueGetExternalSurfacePtr - write_buffer_queue_get_external_surface_; - DvrWriteBufferQueueCreateReadQueuePtr write_buffer_queue_create_read_queue_; - DvrWriteBufferQueueDequeuePtr write_buffer_queue_dequeue_; + write_buffer_queue_get_external_surface; + DvrWriteBufferQueueCreateReadQueuePtr write_buffer_queue_create_read_queue; + DvrWriteBufferQueueDequeuePtr write_buffer_queue_dequeue; // Read buffer queue - DvrReadBufferQueueDestroyPtr read_buffer_queue_destroy_; - DvrReadBufferQueueGetCapacityPtr read_buffer_queue_get_capacity_; - DvrReadBufferQueueCreateReadQueuePtr read_buffer_queue_create_read_queue_; + DvrReadBufferQueueDestroyPtr read_buffer_queue_destroy; + DvrReadBufferQueueGetCapacityPtr read_buffer_queue_get_capacity; + DvrReadBufferQueueCreateReadQueuePtr read_buffer_queue_create_read_queue; DvrReadBufferQueueDequeuePtr read_buffer_queue_dequeue; // V-Sync client - DvrVSyncClientCreatePtr vsync_client_create_; - DvrVSyncClientDestroyPtr vsync_client_destroy_; - DvrVSyncClientGetSchedInfoPtr vsync_client_get_sched_info_; + DvrVSyncClientCreatePtr vsync_client_create; + DvrVSyncClientDestroyPtr vsync_client_destroy; + DvrVSyncClientGetSchedInfoPtr vsync_client_get_sched_info; // Display surface - DvrGetPoseBufferPtr get_pose_buffer_; - DvrSurfaceCreatePtr surface_create_; - DvrSurfaceGetWriteBufferQueuePtr surface_get_write_buffer_queue_; + DvrGetPoseBufferPtr get_pose_buffer; + DvrSurfaceCreatePtr surface_create; + DvrSurfaceGetWriteBufferQueuePtr surface_get_write_buffer_queue; // Pose client - DvrPoseClientCreatePtr pose_client_create_; - DvrPoseClientDestroyPtr pose_client_destroy_; - DvrPoseGetPtr pose_get_; - DvrPoseGetVsyncCountPtr pose_get_vsync_count_; - DvrPoseGetControllerPtr pose_get_controller_; + DvrPoseClientCreatePtr pose_client_create; + DvrPoseClientDestroyPtr pose_client_destroy; + DvrPoseGetPtr pose_get; + DvrPoseGetVsyncCountPtr pose_get_vsync_count; + DvrPoseGetControllerPtr pose_get_controller; // Virtual touchpad client - DvrVirtualTouchpadCreatePtr virtual_touchpad_create_; - DvrVirtualTouchpadDestroyPtr virtual_touchpad_destroy_; - DvrVirtualTouchpadAttachPtr virtual_touchpad_attach_; - DvrVirtualTouchpadDetachPtr virtual_touchpad_detach_; - DvrVirtualTouchpadTouchPtr virtual_touchpad_touch_; - DvrVirtualTouchpadButtonStatePtr virtual_touchpad_button_state_; + DvrVirtualTouchpadCreatePtr virtual_touchpad_create; + DvrVirtualTouchpadDestroyPtr virtual_touchpad_destroy; + DvrVirtualTouchpadAttachPtr virtual_touchpad_attach; + DvrVirtualTouchpadDetachPtr virtual_touchpad_detach; + DvrVirtualTouchpadTouchPtr virtual_touchpad_touch; + DvrVirtualTouchpadButtonStatePtr virtual_touchpad_button_state; + + // VR HWComposer client + DvrHwcClientCreatePtr hwc_client_create; + DvrHwcClientDestroyPtr hwc_client_destroy; + DvrHwcFrameDestroyPtr hwc_frame_destroy; + DvrHwcFrameGetDisplayIdPtr hwc_frame_get_display_id; + DvrHwcFrameGetDisplayWidthPtr hwc_frame_get_display_width; + DvrHwcFrameGetDisplayHeightPtr hwc_frame_get_display_height; + DvrHwcFrameGetDisplayRemovedPtr hwc_frame_get_display_removed; + DvrHwcFrameGetLayerCountPtr hwc_frame_get_layer_count; + DvrHwcFrameGetLayerIdPtr hwc_frame_get_layer_id; + DvrHwcFrameGetLayerBufferPtr hwc_frame_get_layer_buffer; + DvrHwcFrameGetLayerFencePtr hwc_frame_get_layer_fence; + DvrHwcFrameGetLayerDisplayFramePtr hwc_frame_get_layer_display_frame; + DvrHwcFrameGetLayerCropPtr hwc_frame_get_layer_crop; + DvrHwcFrameGetLayerBlendModePtr hwc_frame_get_layer_blend_mode; + DvrHwcFrameGetLayerAlphaPtr hwc_frame_get_layer_alpha; + DvrHwcFrameGetLayerTypePtr hwc_frame_get_layer_type; + DvrHwcFrameGetLayerApplicationIdPtr hwc_frame_get_layer_application_id; }; int dvrGetApi(void* api, size_t struct_size, int version); diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h index 063c16d484..692864da4c 100644 --- a/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h +++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h @@ -1,29 +1,45 @@ -#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H -#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H +#ifndef ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H +#define ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H -#include <android/dvr_hardware_composer_defs.h> -#include <android/hardware_buffer.h> +#include <dvr/dvr_hardware_composer_defs.h> +#include <stdbool.h> #ifdef __cplusplus extern "C" { #endif +typedef struct AHardwareBuffer AHardwareBuffer; typedef struct DvrHwcClient DvrHwcClient; typedef struct DvrHwcFrame DvrHwcFrame; // Called when a new frame has arrived. // +// @param client_state Pointer to client state passed in |dvrHwcCreateClient()|. // @param frame New frame. Owned by the client. // @return fence FD for the release of the last frame. -typedef int(*DvrHwcOnFrameCallback)(DvrHwcFrame* frame); +typedef int(*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame); -DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback); +// @param callback Called when a new frame is available. +// @param client_state Pointer to client state passed back in the callback. +DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, + void* client_state); + +void dvrHwcClientDestroy(DvrHwcClient* client); // Called to free the frame information. void dvrHwcFrameDestroy(DvrHwcFrame* frame); Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame); +int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame); + +int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame); + +// @return True if the display has been removed. In this case the current frame +// does not contain any valid layers to display. It is a signal to clean up any +// display related state. +bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame); + // @return Number of layers in the frame. size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame); @@ -59,4 +75,4 @@ uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame, } // extern "C" #endif -#endif // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H +#endif // ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h index 3186f821a6..546ed7b040 100644 --- a/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h +++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h @@ -1,5 +1,5 @@ -#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H -#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H +#ifndef ANDROID_VR_HARDWARE_COMPOSER_DEFS_H +#define ANDROID_VR_HARDWARE_COMPOSER_DEFS_H #include <inttypes.h> @@ -47,4 +47,4 @@ struct Rectf { } // extern "C" #endif -#endif // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_DEFS_H +#endif // ANDROID_DVR_HARDWARE_COMPOSER_DEFS_H diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp index c31862896a..bfa2d879b5 100644 --- a/libs/vr/libpdx/client.cpp +++ b/libs/vr/libpdx/client.cpp @@ -4,7 +4,6 @@ #include <log/log.h> #include <pdx/trace.h> -#include "errno_guard.h" namespace android { namespace pdx { @@ -84,7 +83,6 @@ int Client::error() const { return error_; } Status<void> Client::SendImpulse(int opcode) { PDX_TRACE_NAME("Client::SendImpulse"); - ErrnoGuard errno_guard; auto status = CheckReconnect(); if (!status) @@ -98,7 +96,6 @@ Status<void> Client::SendImpulse(int opcode) { Status<void> Client::SendImpulse(int opcode, const void* buffer, size_t length) { PDX_TRACE_NAME("Client::SendImpulse"); - ErrnoGuard errno_guard; auto status = CheckReconnect(); if (!status) @@ -110,7 +107,6 @@ Status<void> Client::SendImpulse(int opcode, const void* buffer, } void Client::Close(int error) { - ErrnoGuard errno_guard; channel_.reset(); // Normalize error codes to negative integer space. error_ = error <= 0 ? error : -error; @@ -228,37 +224,38 @@ void Transaction::SendTransaction(int opcode, Status<LocalChannelHandle>* ret, CheckDisconnect(*ret); } -FileReference Transaction::PushFileHandle(const LocalHandle& handle) { - return client_.CheckReconnect() && EnsureStateAllocated() - ? client_.GetChannel()->PushFileHandle(state_, handle) - : -1; +Status<FileReference> Transaction::PushFileHandle(const LocalHandle& handle) { + if (client_.CheckReconnect() && EnsureStateAllocated()) + return client_.GetChannel()->PushFileHandle(state_, handle); + return ErrorStatus{ESHUTDOWN}; } -FileReference Transaction::PushFileHandle(const BorrowedHandle& handle) { - return client_.CheckReconnect() && EnsureStateAllocated() - ? client_.GetChannel()->PushFileHandle(state_, handle) - : -1; +Status<FileReference> Transaction::PushFileHandle( + const BorrowedHandle& handle) { + if (client_.CheckReconnect() && EnsureStateAllocated()) + return client_.GetChannel()->PushFileHandle(state_, handle); + return ErrorStatus{ESHUTDOWN}; } -FileReference Transaction::PushFileHandle(const RemoteHandle& handle) { +Status<FileReference> Transaction::PushFileHandle(const RemoteHandle& handle) { return handle.Get(); } -ChannelReference Transaction::PushChannelHandle( +Status<ChannelReference> Transaction::PushChannelHandle( const LocalChannelHandle& handle) { - return client_.CheckReconnect() && EnsureStateAllocated() - ? client_.GetChannel()->PushChannelHandle(state_, handle) - : -1; + if (client_.CheckReconnect() && EnsureStateAllocated()) + return client_.GetChannel()->PushChannelHandle(state_, handle); + return ErrorStatus{ESHUTDOWN}; } -ChannelReference Transaction::PushChannelHandle( +Status<ChannelReference> Transaction::PushChannelHandle( const BorrowedChannelHandle& handle) { - return client_.CheckReconnect() && EnsureStateAllocated() - ? client_.GetChannel()->PushChannelHandle(state_, handle) - : -1; + if (client_.CheckReconnect() && EnsureStateAllocated()) + return client_.GetChannel()->PushChannelHandle(state_, handle); + return ErrorStatus{ESHUTDOWN}; } -ChannelReference Transaction::PushChannelHandle( +Status<ChannelReference> Transaction::PushChannelHandle( const RemoteChannelHandle& handle) { return handle.value(); } diff --git a/libs/vr/libpdx/client_tests.cpp b/libs/vr/libpdx/client_tests.cpp index f1fb6d1143..99ccc698c4 100644 --- a/libs/vr/libpdx/client_tests.cpp +++ b/libs/vr/libpdx/client_tests.cpp @@ -518,28 +518,29 @@ TEST_F(ClientTransactionTest, PushHandle) { EXPECT_CALL(*mock_channel(), PushFileHandle(kTransactionState, A<const LocalHandle&>())) .WillOnce(Return(1)); - EXPECT_EQ(1, transaction_.PushFileHandle(LocalHandle{-1})); + EXPECT_EQ(1, transaction_.PushFileHandle(LocalHandle{-1}).get()); EXPECT_CALL(*mock_channel(), PushFileHandle(kTransactionState, A<const BorrowedHandle&>())) .WillOnce(Return(2)); - EXPECT_EQ(2, transaction_.PushFileHandle(BorrowedHandle{-1})); + EXPECT_EQ(2, transaction_.PushFileHandle(BorrowedHandle{-1}).get()); - EXPECT_EQ(3, transaction_.PushFileHandle(RemoteHandle{3})); + EXPECT_EQ(3, transaction_.PushFileHandle(RemoteHandle{3}).get()); EXPECT_CALL( *mock_channel(), PushChannelHandle(kTransactionState, A<const LocalChannelHandle&>())) .WillOnce(Return(11)); - EXPECT_EQ(11, transaction_.PushChannelHandle(LocalChannelHandle{nullptr, 1})); + EXPECT_EQ( + 11, transaction_.PushChannelHandle(LocalChannelHandle{nullptr, 1}).get()); EXPECT_CALL( *mock_channel(), PushChannelHandle(kTransactionState, A<const BorrowedChannelHandle&>())) .WillOnce(Return(12)); - EXPECT_EQ(12, transaction_.PushChannelHandle(BorrowedChannelHandle{2})); + EXPECT_EQ(12, transaction_.PushChannelHandle(BorrowedChannelHandle{2}).get()); - EXPECT_EQ(13, transaction_.PushChannelHandle(RemoteChannelHandle{13})); + EXPECT_EQ(13, transaction_.PushChannelHandle(RemoteChannelHandle{13}).get()); } TEST_F(ClientTransactionTest, GetHandle) { diff --git a/libs/vr/libpdx/errno_guard.h b/libs/vr/libpdx/errno_guard.h deleted file mode 100644 index fc7dfdf4fd..0000000000 --- a/libs/vr/libpdx/errno_guard.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef ANDROID_PDX_ERRNO_GUARD_H_ -#define ANDROID_PDX_ERRNO_GUARD_H_ - -#include <errno.h> - -namespace android { -namespace pdx { - -// Automatically saves and restores the system errno for API implementations to -// prevent internal use errno from affecting API callers. -class ErrnoGuard { - public: - ErrnoGuard() : saved_errno_(errno) {} - ~ErrnoGuard() { errno = saved_errno_; } - - int saved_errno() const { return saved_errno_; } - - private: - int saved_errno_; - - ErrnoGuard(const ErrnoGuard&) = delete; - void operator=(const ErrnoGuard&) = delete; -}; - -// Checks |return_code| and returns either it or the negated system errno based -// on the return code value. -inline int ReturnCodeOrError(int return_code) { - return return_code < 0 ? -errno : return_code; -} - -} // namespace pdx -} // namespace android - -#endif // ANDROID_PDX_ERRNO_GUARD_H_ diff --git a/libs/vr/libpdx/private/pdx/client.h b/libs/vr/libpdx/private/pdx/client.h index a590087497..656de7e2ca 100644 --- a/libs/vr/libpdx/private/pdx/client.h +++ b/libs/vr/libpdx/private/pdx/client.h @@ -253,13 +253,14 @@ class Transaction final : public OutputResourceMapper, } // OutputResourceMapper - FileReference PushFileHandle(const LocalHandle& handle) override; - FileReference PushFileHandle(const BorrowedHandle& handle) override; - FileReference PushFileHandle(const RemoteHandle& handle) override; - ChannelReference PushChannelHandle(const LocalChannelHandle& handle) override; - ChannelReference PushChannelHandle( + Status<FileReference> PushFileHandle(const LocalHandle& handle) override; + Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override; + Status<FileReference> PushFileHandle(const RemoteHandle& handle) override; + Status<ChannelReference> PushChannelHandle( + const LocalChannelHandle& handle) override; + Status<ChannelReference> PushChannelHandle( const BorrowedChannelHandle& handle) override; - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const RemoteChannelHandle& handle) override; // InputResourceMapper diff --git a/libs/vr/libpdx/private/pdx/message_writer.h b/libs/vr/libpdx/private/pdx/message_writer.h index 0cb6e4064f..4a101d6806 100644 --- a/libs/vr/libpdx/private/pdx/message_writer.h +++ b/libs/vr/libpdx/private/pdx/message_writer.h @@ -3,20 +3,22 @@ #include <pdx/channel_handle.h> #include <pdx/file_handle.h> +#include <pdx/status.h> namespace android { namespace pdx { class OutputResourceMapper { public: - virtual FileReference PushFileHandle(const LocalHandle& handle) = 0; - virtual FileReference PushFileHandle(const BorrowedHandle& handle) = 0; - virtual FileReference PushFileHandle(const RemoteHandle& handle) = 0; - virtual ChannelReference PushChannelHandle( + virtual Status<FileReference> PushFileHandle(const LocalHandle& handle) = 0; + virtual Status<FileReference> PushFileHandle( + const BorrowedHandle& handle) = 0; + virtual Status<FileReference> PushFileHandle(const RemoteHandle& handle) = 0; + virtual Status<ChannelReference> PushChannelHandle( const LocalChannelHandle& handle) = 0; - virtual ChannelReference PushChannelHandle( + virtual Status<ChannelReference> PushChannelHandle( const BorrowedChannelHandle& handle) = 0; - virtual ChannelReference PushChannelHandle( + virtual Status<ChannelReference> PushChannelHandle( const RemoteChannelHandle& handle) = 0; protected: diff --git a/libs/vr/libpdx/private/pdx/mock_message_writer.h b/libs/vr/libpdx/private/pdx/mock_message_writer.h index 3c513d7e5a..e06e5bbc2b 100644 --- a/libs/vr/libpdx/private/pdx/mock_message_writer.h +++ b/libs/vr/libpdx/private/pdx/mock_message_writer.h @@ -9,15 +9,18 @@ namespace pdx { class MockOutputResourceMapper : public OutputResourceMapper { public: - MOCK_METHOD1(PushFileHandle, FileReference(const LocalHandle& handle)); - MOCK_METHOD1(PushFileHandle, FileReference(const BorrowedHandle& handle)); - MOCK_METHOD1(PushFileHandle, FileReference(const RemoteHandle& handle)); + MOCK_METHOD1(PushFileHandle, + Status<FileReference>(const LocalHandle& handle)); + MOCK_METHOD1(PushFileHandle, + Status<FileReference>(const BorrowedHandle& handle)); + MOCK_METHOD1(PushFileHandle, + Status<FileReference>(const RemoteHandle& handle)); MOCK_METHOD1(PushChannelHandle, - ChannelReference(const LocalChannelHandle& handle)); + Status<ChannelReference>(const LocalChannelHandle& handle)); MOCK_METHOD1(PushChannelHandle, - ChannelReference(const BorrowedChannelHandle& handle)); + Status<ChannelReference>(const BorrowedChannelHandle& handle)); MOCK_METHOD1(PushChannelHandle, - ChannelReference(const RemoteChannelHandle& handle)); + Status<ChannelReference>(const RemoteChannelHandle& handle)); }; class MockMessageWriter : public MessageWriter { diff --git a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h index ead74d561f..e741d4a46b 100644 --- a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h +++ b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h @@ -10,46 +10,54 @@ namespace pdx { class MockEndpoint : public Endpoint { public: MOCK_CONST_METHOD0(GetIpcTag, uint32_t()); - MOCK_METHOD1(SetService, int(Service* service)); - MOCK_METHOD2(SetChannel, int(int channel_id, Channel* channel)); - MOCK_METHOD1(CloseChannel, int(int channel_id)); + MOCK_METHOD1(SetService, Status<void>(Service* service)); + MOCK_METHOD2(SetChannel, Status<void>(int channel_id, Channel* channel)); + MOCK_METHOD1(CloseChannel, Status<void>(int channel_id)); MOCK_METHOD3(ModifyChannelEvents, - int(int channel_id, int clear_mask, int set_mask)); + Status<void>(int channel_id, int clear_mask, int set_mask)); MOCK_METHOD4(PushChannel, Status<RemoteChannelHandle>(Message* message, int flags, Channel* channel, int* channel_id)); MOCK_METHOD3(CheckChannel, Status<int>(const Message* message, ChannelReference ref, Channel** channel)); - MOCK_METHOD1(DefaultHandleMessage, int(const MessageInfo& info)); - MOCK_METHOD1(MessageReceive, int(Message* message)); - MOCK_METHOD2(MessageReply, int(Message* message, int return_code)); - MOCK_METHOD2(MessageReplyFd, int(Message* message, unsigned int push_fd)); + MOCK_METHOD1(MessageReceive, Status<void>(Message* message)); + MOCK_METHOD2(MessageReply, Status<void>(Message* message, int return_code)); + MOCK_METHOD2(MessageReplyFd, + Status<void>(Message* message, unsigned int push_fd)); MOCK_METHOD2(MessageReplyChannelHandle, - int(Message* message, const LocalChannelHandle& handle)); + Status<void>(Message* message, + const LocalChannelHandle& handle)); MOCK_METHOD2(MessageReplyChannelHandle, - int(Message* message, const BorrowedChannelHandle& handle)); + Status<void>(Message* message, + const BorrowedChannelHandle& handle)); MOCK_METHOD2(MessageReplyChannelHandle, - int(Message* message, const RemoteChannelHandle& handle)); - MOCK_METHOD3(ReadMessageData, ssize_t(Message* message, const iovec* vector, - size_t vector_length)); - MOCK_METHOD3(WriteMessageData, ssize_t(Message* message, const iovec* vector, - size_t vector_length)); + Status<void>(Message* message, + const RemoteChannelHandle& handle)); + MOCK_METHOD3(ReadMessageData, + Status<size_t>(Message* message, const iovec* vector, + size_t vector_length)); + MOCK_METHOD3(WriteMessageData, + Status<size_t>(Message* message, const iovec* vector, + size_t vector_length)); MOCK_METHOD2(PushFileHandle, - FileReference(Message* message, const LocalHandle& handle)); + Status<FileReference>(Message* message, + const LocalHandle& handle)); MOCK_METHOD2(PushFileHandle, - FileReference(Message* message, const BorrowedHandle& handle)); + Status<FileReference>(Message* message, + const BorrowedHandle& handle)); MOCK_METHOD2(PushFileHandle, - FileReference(Message* message, const RemoteHandle& handle)); + Status<FileReference>(Message* message, + const RemoteHandle& handle)); MOCK_METHOD2(PushChannelHandle, - ChannelReference(Message* message, - const LocalChannelHandle& handle)); + Status<ChannelReference>(Message* message, + const LocalChannelHandle& handle)); MOCK_METHOD2(PushChannelHandle, - ChannelReference(Message* message, - const BorrowedChannelHandle& handle)); + Status<ChannelReference>(Message* message, + const BorrowedChannelHandle& handle)); MOCK_METHOD2(PushChannelHandle, - ChannelReference(Message* message, - const RemoteChannelHandle& handle)); + Status<ChannelReference>(Message* message, + const RemoteChannelHandle& handle)); MOCK_CONST_METHOD2(GetFileHandle, LocalHandle(Message* message, FileReference ref)); MOCK_CONST_METHOD2(GetChannelHandle, @@ -57,7 +65,7 @@ class MockEndpoint : public Endpoint { ChannelReference ref)); MOCK_METHOD0(AllocateMessageState, void*()); MOCK_METHOD1(FreeMessageState, void(void* state)); - MOCK_METHOD0(Cancel, int()); + MOCK_METHOD0(Cancel, Status<void>()); }; } // namespace pdx diff --git a/libs/vr/libpdx/private/pdx/rpc/remote_method.h b/libs/vr/libpdx/private/pdx/rpc/remote_method.h index 3eca9e5f10..505c63b1bf 100644 --- a/libs/vr/libpdx/private/pdx/rpc/remote_method.h +++ b/libs/vr/libpdx/private/pdx/rpc/remote_method.h @@ -121,9 +121,9 @@ class UnpackArguments<Class, Return(Args...)> { // either during dispatch of the remote method handler or at a later time if the // message is moved for delayed response. inline void RemoteMethodError(Message& message, int error_code) { - const int ret = message.ReplyError(error_code); - ALOGE_IF(ret < 0, "RemoteMethodError: Failed to reply to message: %s", - strerror(-ret)); + const auto status = message.ReplyError(error_code); + ALOGE_IF(!status, "RemoteMethodError: Failed to reply to message: %s", + status.GetErrorMessage().c_str()); } // Returns a value from a remote method to the client. The usual method to @@ -135,9 +135,9 @@ inline void RemoteMethodError(Message& message, int error_code) { template <typename RemoteMethodType, typename Return> EnableIfDirectReturn<typename RemoteMethodType::Return> RemoteMethodReturn( Message& message, const Return& return_value) { - const int ret = message.Reply(return_value); - ALOGE_IF(ret < 0, "RemoteMethodReturn: Failed to reply to message: %s", - strerror(-ret)); + const auto status = message.Reply(return_value); + ALOGE_IF(!status, "RemoteMethodReturn: Failed to reply to message: %s", + status.GetErrorMessage().c_str()); } // Overload for non-direct return types. @@ -148,14 +148,10 @@ EnableIfNotDirectReturn<typename RemoteMethodType::Return> RemoteMethodReturn( rpc::ServicePayload<ReplyBuffer> payload(message); MakeArgumentEncoder<Signature>(&payload).EncodeReturn(return_value); - int ret; - auto size = message.Write(payload.Data(), payload.Size()); - if (size < static_cast<decltype(size)>(payload.Size())) - ret = message.ReplyError(EIO); - else - ret = message.Reply(0); - ALOGE_IF(ret < 0, "RemoteMethodReturn: Failed to reply to message: %s", - strerror(-ret)); + auto ret = message.WriteAll(payload.Data(), payload.Size()); + auto status = message.Reply(ret); + ALOGE_IF(!status, "RemoteMethodReturn: Failed to reply to message: %s", + status.GetErrorMessage().c_str()); } // Overload for Status<void> return types. @@ -189,13 +185,13 @@ void DispatchRemoteMethod(Class& instance, rpc::ServicePayload<ReceiveBuffer> payload(message); payload.Resize(max_capacity); - auto size = message.Read(payload.Data(), payload.Size()); - if (size < 0) { - RemoteMethodError(message, -size); + Status<size_t> read_status = message.Read(payload.Data(), payload.Size()); + if (!read_status) { + RemoteMethodError(message, read_status.error()); return; } - payload.Resize(size); + payload.Resize(read_status.get()); ErrorType error; auto decoder = MakeArgumentDecoder<Signature>(&payload); @@ -225,13 +221,13 @@ void DispatchRemoteMethod(Class& instance, rpc::ServicePayload<ReceiveBuffer> payload(message); payload.Resize(max_capacity); - auto size = message.Read(payload.Data(), payload.Size()); - if (size < 0) { - RemoteMethodError(message, -size); + Status<size_t> read_status = message.Read(payload.Data(), payload.Size()); + if (!read_status) { + RemoteMethodError(message, read_status.error()); return; } - payload.Resize(size); + payload.Resize(read_status.get()); ErrorType error; auto decoder = MakeArgumentDecoder<Signature>(&payload); @@ -265,13 +261,13 @@ void DispatchRemoteMethod(Class& instance, rpc::ServicePayload<ReceiveBuffer> payload(message); payload.Resize(max_capacity); - auto size = message.Read(payload.Data(), payload.Size()); - if (size < 0) { - RemoteMethodError(message, -size); + Status<size_t> read_status = message.Read(payload.Data(), payload.Size()); + if (!read_status) { + RemoteMethodError(message, read_status.error()); return; } - payload.Resize(size); + payload.Resize(read_status.get()); ErrorType error; auto decoder = MakeArgumentDecoder<Signature>(&payload); diff --git a/libs/vr/libpdx/private/pdx/rpc/serialization.h b/libs/vr/libpdx/private/pdx/rpc/serialization.h index fccd028336..9a012ede7d 100644 --- a/libs/vr/libpdx/private/pdx/rpc/serialization.h +++ b/libs/vr/libpdx/private/pdx/rpc/serialization.h @@ -905,8 +905,9 @@ template <FileHandleMode Mode> inline void SerializeObject(const FileHandle<Mode>& fd, MessageWriter* writer, void*& buffer) { SerializeType(fd, buffer); - const FileReference value = + const Status<FileReference> status = writer->GetOutputResourceMapper()->PushFileHandle(fd); + FileReference value = status ? status.get() : -status.error(); SerializeRaw(value, buffer); } @@ -915,8 +916,9 @@ template <ChannelHandleMode Mode> inline void SerializeObject(const ChannelHandle<Mode>& handle, MessageWriter* writer, void*& buffer) { SerializeType(handle, buffer); - const ChannelReference value = + const Status<ChannelReference> status = writer->GetOutputResourceMapper()->PushChannelHandle(handle); + ChannelReference value = status ? status.get() : -status.error(); SerializeRaw(value, buffer); } diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h index 175cedfb16..0d30614562 100644 --- a/libs/vr/libpdx/private/pdx/service.h +++ b/libs/vr/libpdx/private/pdx/service.h @@ -98,29 +98,62 @@ class Message : public OutputResourceMapper, public InputResourceMapper { /* * Read/write payload, in either single buffer or iovec form. */ - ssize_t ReadVector(const iovec* vector, size_t vector_length); - ssize_t Read(void* buffer, size_t length); - ssize_t WriteVector(const iovec* vector, size_t vector_length); - ssize_t Write(const void* buffer, size_t length); + Status<size_t> ReadVector(const iovec* vector, size_t vector_length); + Status<size_t> Read(void* buffer, size_t length); + Status<size_t> WriteVector(const iovec* vector, size_t vector_length); + Status<size_t> Write(const void* buffer, size_t length); template <size_t N> - inline ssize_t ReadVector(const iovec (&vector)[N]) { + inline Status<size_t> ReadVector(const iovec (&vector)[N]) { return ReadVector(vector, N); } template <size_t N> - inline ssize_t WriteVector(const iovec (&vector)[N]) { + inline Status<size_t> WriteVector(const iovec (&vector)[N]) { return WriteVector(vector, N); } + // Helper functions to read/write all requested bytes, and return EIO if not + // all were read/written. + Status<void> ReadVectorAll(const iovec* vector, size_t vector_length); + Status<void> WriteVectorAll(const iovec* vector, size_t vector_length); + + inline Status<void> ReadAll(void* buffer, size_t length) { + Status<size_t> status = Read(buffer, length); + if (status && status.get() < length) + status.SetError(EIO); + Status<void> ret; + ret.PropagateError(status); + return ret; + } + inline Status<void> WriteAll(const void* buffer, size_t length) { + Status<size_t> status = Write(buffer, length); + if (status && status.get() < length) + status.SetError(EIO); + Status<void> ret; + ret.PropagateError(status); + return ret; + } + + template <size_t N> + inline Status<void> ReadVectorAll(const iovec (&vector)[N]) { + return ReadVectorAll(vector, N); + } + + template <size_t N> + inline Status<void> WriteVectorAll(const iovec (&vector)[N]) { + return WriteVectorAll(vector, N); + } + // OutputResourceMapper - FileReference PushFileHandle(const LocalHandle& handle) override; - FileReference PushFileHandle(const BorrowedHandle& handle) override; - FileReference PushFileHandle(const RemoteHandle& handle) override; - ChannelReference PushChannelHandle(const LocalChannelHandle& handle) override; - ChannelReference PushChannelHandle( + Status<FileReference> PushFileHandle(const LocalHandle& handle) override; + Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override; + Status<FileReference> PushFileHandle(const RemoteHandle& handle) override; + Status<ChannelReference> PushChannelHandle( + const LocalChannelHandle& handle) override; + Status<ChannelReference> PushChannelHandle( const BorrowedChannelHandle& handle) override; - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const RemoteChannelHandle& handle) override; // InputResourceMapper @@ -131,25 +164,29 @@ class Message : public OutputResourceMapper, public InputResourceMapper { /* * Various ways to reply to a message. */ - int Reply(int return_code); - int ReplyError(unsigned error); - int ReplyFileDescriptor(unsigned int fd); - int Reply(const LocalHandle& handle); - int Reply(const BorrowedHandle& handle); - int Reply(const RemoteHandle& handle); - int Reply(const LocalChannelHandle& handle); - int Reply(const BorrowedChannelHandle& handle); - int Reply(const RemoteChannelHandle& handle); + Status<void> Reply(int return_code); + Status<void> ReplyError(unsigned int error); + Status<void> ReplyFileDescriptor(unsigned int fd); + Status<void> Reply(const LocalHandle& handle); + Status<void> Reply(const BorrowedHandle& handle); + Status<void> Reply(const RemoteHandle& handle); + Status<void> Reply(const LocalChannelHandle& handle); + Status<void> Reply(const BorrowedChannelHandle& handle); + Status<void> Reply(const RemoteChannelHandle& handle); template <typename T> - inline int Reply(const Status<T>& status) { + inline Status<void> Reply(const Status<T>& status) { return status ? Reply(status.get()) : ReplyError(status.error()); } + inline Status<void> Reply(const Status<void>& status) { + return status ? Reply(0) : ReplyError(status.error()); + } + /* * Update the channel event bits with the given clear and set masks. */ - int ModifyChannelEvents(int clear_mask, int set_mask); + Status<void> ModifyChannelEvents(int clear_mask, int set_mask); /* * Create a new channel and push it as a file descriptor to the client. See @@ -264,7 +301,7 @@ class Message : public OutputResourceMapper, public InputResourceMapper { * these in multi-threaded services. */ std::shared_ptr<Channel> GetChannel() const; - void SetChannel(const std::shared_ptr<Channel>& channnel); + Status<void> SetChannel(const std::shared_ptr<Channel>& channnel); /* * Get the Channel object for the channel associated with this message, @@ -355,7 +392,8 @@ class Service : public std::enable_shared_from_this<Service> { * the Channel object until the channel is closed or another call replaces * the current value. */ - int SetChannel(int channel_id, const std::shared_ptr<Channel>& channel); + Status<void> SetChannel(int channel_id, + const std::shared_ptr<Channel>& channel); /* * Get the channel context for the given channel id. This method should be @@ -404,7 +442,7 @@ class Service : public std::enable_shared_from_this<Service> { * * OnChannelClosed is not called in response to this method call. */ - int CloseChannel(int channel_id); + Status<void> CloseChannel(int channel_id); /* * Update the event bits for the given channel (given by id), using the @@ -413,7 +451,8 @@ class Service : public std::enable_shared_from_this<Service> { * This is useful for asynchronously signaling events that clients may be * waiting for using select/poll/epoll. */ - int ModifyChannelEvents(int channel_id, int clear_mask, int set_mask); + Status<void> ModifyChannelEvents(int channel_id, int clear_mask, + int set_mask); /* * Create a new channel and push it as a file descriptor to the process @@ -478,7 +517,7 @@ class Service : public std::enable_shared_from_this<Service> { * The default implementation simply calls defaultHandleMessage(). * Subclasses should call the same for any unrecognized message opcodes. */ - virtual int HandleMessage(Message& message); + virtual Status<void> HandleMessage(Message& message); /* * Handle an asynchronous message. Subclasses override this to receive @@ -496,9 +535,9 @@ class Service : public std::enable_shared_from_this<Service> { * Provides default handling of CHANNEL_OPEN and CHANNEL_CLOSE, calling * OnChannelOpen() and OnChannelClose(), respectively. * - * For all other message opcodes, this method replies with -ENOTSUP. + * For all other message opcodes, this method replies with ENOTSUP. */ - int DefaultHandleMessage(Message& message); + Status<void> DefaultHandleMessage(Message& message); /* * Called when system properties have changed. Subclasses should implement @@ -515,7 +554,7 @@ class Service : public std::enable_shared_from_this<Service> { * Cancels the endpoint, unblocking any receiver threads waiting in * ReceiveAndDispatch(). */ - int Cancel(); + Status<void> Cancel(); /* * Iterator type for Channel map iterators. @@ -564,14 +603,14 @@ class Service : public std::enable_shared_from_this<Service> { * If the endpoint is in blocking mode this call blocks until a message is * received, a signal is delivered to this thread, or the service is canceled. * If the endpoint is in non-blocking mode and a message is not pending this - * call returns immediately with -ETIMEDOUT. + * call returns immediately with ETIMEDOUT. */ - int ReceiveAndDispatch(); + Status<void> ReceiveAndDispatch(); private: friend class Message; - bool HandleSystemMessage(Message& message); + Status<void> HandleSystemMessage(Message& message); Service(const Service&); void operator=(const Service&) = delete; @@ -639,28 +678,28 @@ class ServiceBase : public Service { #define REPLY_ERROR(message, error, error_label) \ do { \ - int __ret = message.ReplyError(error); \ - CHECK_ERROR(__ret < 0, error_label, \ + auto __status = message.ReplyError(error); \ + CHECK_ERROR(!__status, error_label, \ PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \ - strerror(-__ret)); \ + __status.GetErrorMessage().c_str()); \ goto error_label; \ } while (0) #define REPLY_ERROR_RETURN(message, error, ...) \ do { \ - int __ret = message.ReplyError(error); \ - ALOGE_IF(__ret < 0, \ + auto __status = message.ReplyError(error); \ + ALOGE_IF(!__status, \ PDX_ERROR_PREFIX " Failed to reply to message because: %s", \ - strerror(-__ret)); \ + __status.GetErrorMessage().c_str()); \ return __VA_ARGS__; \ } while (0) #define REPLY_MESSAGE(message, message_return_code, error_label) \ do { \ - int __ret = message.Reply(message_return_code); \ - CHECK_ERROR(__ret < 0, error_label, \ + auto __status = message.Reply(message_return_code); \ + CHECK_ERROR(!__status, error_label, \ PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \ - strerror(-__ret)); \ + __status.GetErrorMessage().c_str()); \ goto error_label; \ } while (0) @@ -669,10 +708,10 @@ class ServiceBase : public Service { #define REPLY_MESSAGE_RETURN(message, message_return_code, ...) \ do { \ - int __ret = message.Reply(message_return_code); \ - ALOGE_IF(__ret < 0, \ + auto __status = message.Reply(message_return_code); \ + ALOGE_IF(!__status, \ PDX_ERROR_PREFIX " Failed to reply to message because: %s", \ - strerror(-__ret)); \ + __status.GetErrorMessage().c_str()); \ return __VA_ARGS__; \ } while (0) @@ -681,19 +720,19 @@ class ServiceBase : public Service { #define REPLY_FD(message, push_fd, error_label) \ do { \ - int __ret = message.ReplyFileDescriptor(push_fd); \ - CHECK_ERROR(__ret < 0, error_label, \ + auto __status = message.ReplyFileDescriptor(push_fd); \ + CHECK_ERROR(!__status, error_label, \ PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \ - strerror(-__ret)); \ + __status.GetErrorMessage().c_str()); \ goto error_label; \ } while (0) #define REPLY_FD_RETURN(message, push_fd, ...) \ do { \ - int __ret = message.ReplyFileDescriptor(push_fd); \ - ALOGE_IF(__ret < 0, \ + auto __status = message.ReplyFileDescriptor(push_fd); \ + ALOGE_IF(__status < 0, \ PDX_ERROR_PREFIX " Failed to reply to message because: %s", \ - strerror(-__ret)); \ + __status.GetErrorMessage().c_str()); \ return __VA_ARGS__; \ } while (0) diff --git a/libs/vr/libpdx/private/pdx/service_endpoint.h b/libs/vr/libpdx/private/pdx/service_endpoint.h index 613be7c9fa..28bd6bc454 100644 --- a/libs/vr/libpdx/private/pdx/service_endpoint.h +++ b/libs/vr/libpdx/private/pdx/service_endpoint.h @@ -44,20 +44,20 @@ class Endpoint { // Associates a Service instance with an endpoint by setting the service // context pointer to the address of the Service. Only one Service may be // associated with a given endpoint. - virtual int SetService(Service* service) = 0; + virtual Status<void> SetService(Service* service) = 0; // Set the channel context for the given channel. - virtual int SetChannel(int channel_id, Channel* channel) = 0; + virtual Status<void> SetChannel(int channel_id, Channel* channel) = 0; // Close a channel, signaling the client file object and freeing the channel // id. Once closed, the client side of the channel always returns the error // ESHUTDOWN and signals the poll/epoll events POLLHUP and POLLFREE. - virtual int CloseChannel(int channel_id) = 0; + virtual Status<void> CloseChannel(int channel_id) = 0; // Update the event bits for the given channel (given by id), using the // given clear and set masks. - virtual int ModifyChannelEvents(int channel_id, int clear_mask, - int set_mask) = 0; + virtual Status<void> ModifyChannelEvents(int channel_id, int clear_mask, + int set_mask) = 0; // Create a new channel and push it as a file descriptor to the process // sending the |message|. |flags| may be set to O_NONBLOCK and/or @@ -77,54 +77,49 @@ class Endpoint { virtual Status<int> CheckChannel(const Message* message, ChannelReference ref, Channel** channel) = 0; - // The default message handler. It is important that all messages - // (eventually) get a reply. This method should be called for any unrecognized - // opcodes or otherwise unhandled messages to prevent erroneous requests from - // blocking indefinitely. - virtual int DefaultHandleMessage(const MessageInfo& info) = 0; - // Receives a message on the given endpoint file descriptor. - virtual int MessageReceive(Message* message) = 0; + virtual Status<void> MessageReceive(Message* message) = 0; // Replies to the message with a return code. - virtual int MessageReply(Message* message, int return_code) = 0; + virtual Status<void> MessageReply(Message* message, int return_code) = 0; // Replies to the message with a file descriptor. - virtual int MessageReplyFd(Message* message, unsigned int push_fd) = 0; + virtual Status<void> MessageReplyFd(Message* message, + unsigned int push_fd) = 0; // Replies to the message with a local channel handle. - virtual int MessageReplyChannelHandle(Message* message, - const LocalChannelHandle& handle) = 0; + virtual Status<void> MessageReplyChannelHandle( + Message* message, const LocalChannelHandle& handle) = 0; // Replies to the message with a borrowed local channel handle. - virtual int MessageReplyChannelHandle( + virtual Status<void> MessageReplyChannelHandle( Message* message, const BorrowedChannelHandle& handle) = 0; // Replies to the message with a remote channel handle. - virtual int MessageReplyChannelHandle(Message* message, - const RemoteChannelHandle& handle) = 0; + virtual Status<void> MessageReplyChannelHandle( + Message* message, const RemoteChannelHandle& handle) = 0; // Reads message data into an array of memory buffers. - virtual ssize_t ReadMessageData(Message* message, const iovec* vector, - size_t vector_length) = 0; + virtual Status<size_t> ReadMessageData(Message* message, const iovec* vector, + size_t vector_length) = 0; // Sends reply data for message. - virtual ssize_t WriteMessageData(Message* message, const iovec* vector, - size_t vector_length) = 0; + virtual Status<size_t> WriteMessageData(Message* message, const iovec* vector, + size_t vector_length) = 0; // Records a file descriptor into the message buffer and returns the remapped // reference to be sent to the remote process. - virtual FileReference PushFileHandle(Message* message, - const LocalHandle& handle) = 0; - virtual FileReference PushFileHandle(Message* message, - const BorrowedHandle& handle) = 0; - virtual FileReference PushFileHandle(Message* message, - const RemoteHandle& handle) = 0; - virtual ChannelReference PushChannelHandle( + virtual Status<FileReference> PushFileHandle(Message* message, + const LocalHandle& handle) = 0; + virtual Status<FileReference> PushFileHandle( + Message* message, const BorrowedHandle& handle) = 0; + virtual Status<FileReference> PushFileHandle(Message* message, + const RemoteHandle& handle) = 0; + virtual Status<ChannelReference> PushChannelHandle( Message* message, const LocalChannelHandle& handle) = 0; - virtual ChannelReference PushChannelHandle( + virtual Status<ChannelReference> PushChannelHandle( Message* message, const BorrowedChannelHandle& handle) = 0; - virtual ChannelReference PushChannelHandle( + virtual Status<ChannelReference> PushChannelHandle( Message* message, const RemoteChannelHandle& handle) = 0; // Obtains a file descriptor/channel handle from a message for the given @@ -140,7 +135,7 @@ class Endpoint { // Cancels the endpoint, unblocking any receiver threads waiting for a // message. - virtual int Cancel() = 0; + virtual Status<void> Cancel() = 0; }; } // namespace pdx diff --git a/libs/vr/libpdx/private/pdx/status.h b/libs/vr/libpdx/private/pdx/status.h index ca2832c2a5..067fe25e9c 100644 --- a/libs/vr/libpdx/private/pdx/status.h +++ b/libs/vr/libpdx/private/pdx/status.h @@ -103,6 +103,17 @@ class Status { // is not empty nor containing a valid value). int error() const { return std::max(error_, 0); } + // Returns the error code as ErrorStatus object. This is a helper method + // to aid in propagation of error codes between Status<T> of different types + // as in the following example: + // Status<int> foo() { + // Status<void> status = bar(); + // if(!status) + // return status.error_status(); + // return 12; + // } + inline ErrorStatus error_status() const { return ErrorStatus{error()}; } + // Returns the error message associated with error code stored in the object. // The message is the same as the string returned by strerror(status.error()). // Can be called only when an error is actually stored (that is, the object @@ -142,6 +153,7 @@ class Status<void> { bool empty() const { return false; } explicit operator bool() const { return ok(); } int error() const { return std::max(error_, 0); } + inline ErrorStatus error_status() const { return ErrorStatus{error()}; } std::string GetErrorMessage() const { std::string message; if (error_ > 0) diff --git a/libs/vr/libpdx/private/pdx/utility.h b/libs/vr/libpdx/private/pdx/utility.h index c8c717cb65..305c3b87a4 100644 --- a/libs/vr/libpdx/private/pdx/utility.h +++ b/libs/vr/libpdx/private/pdx/utility.h @@ -150,29 +150,29 @@ inline R GetNTuple(T value) { class NoOpOutputResourceMapper : public OutputResourceMapper { public: - FileReference PushFileHandle(const LocalHandle& handle) override { + Status<FileReference> PushFileHandle(const LocalHandle& handle) override { return handle.Get(); } - FileReference PushFileHandle(const BorrowedHandle& handle) override { + Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override { return handle.Get(); } - FileReference PushFileHandle(const RemoteHandle& handle) override { + Status<FileReference> PushFileHandle(const RemoteHandle& handle) override { return handle.Get(); } - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const LocalChannelHandle& handle) override { return handle.value(); } - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const BorrowedChannelHandle& handle) override { return handle.value(); } - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const RemoteChannelHandle& handle) override { return handle.value(); } @@ -278,7 +278,7 @@ class Payload : public MessageWriter, OutputResourceMapper* GetOutputResourceMapper() override { return this; } // OutputResourceMapper - FileReference PushFileHandle(const LocalHandle& handle) override { + Status<FileReference> PushFileHandle(const LocalHandle& handle) override { if (handle) { const int ref = file_handles_.size(); file_handles_.push_back(handle.Get()); @@ -288,7 +288,7 @@ class Payload : public MessageWriter, } } - FileReference PushFileHandle(const BorrowedHandle& handle) override { + Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override { if (handle) { const int ref = file_handles_.size(); file_handles_.push_back(handle.Get()); @@ -298,11 +298,11 @@ class Payload : public MessageWriter, } } - FileReference PushFileHandle(const RemoteHandle& handle) override { + Status<FileReference> PushFileHandle(const RemoteHandle& handle) override { return handle.Get(); } - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const LocalChannelHandle& handle) override { if (handle) { const int ref = file_handles_.size(); @@ -313,7 +313,7 @@ class Payload : public MessageWriter, } } - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const BorrowedChannelHandle& handle) override { if (handle) { const int ref = file_handles_.size(); @@ -324,7 +324,7 @@ class Payload : public MessageWriter, } } - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const RemoteChannelHandle& handle) override { return handle.value(); } diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp index daf9af89ed..fab4770b7f 100644 --- a/libs/vr/libpdx/service.cpp +++ b/libs/vr/libpdx/service.cpp @@ -9,7 +9,6 @@ #include <cstdint> #include <pdx/trace.h> -#include "errno_guard.h" #define TRACE 0 @@ -60,7 +59,7 @@ void Message::Destroy() { "ERROR: Service \"%s\" failed to reply to message: op=%d pid=%d " "cid=%d\n", svc->name_.c_str(), info_.op, info_.pid, info_.cid); - svc->endpoint()->DefaultHandleMessage(info_); + svc->DefaultHandleMessage(*this); } svc->endpoint()->FreeMessageState(state_); } @@ -77,112 +76,138 @@ const std::uint8_t* Message::ImpulseEnd() const { return ImpulseBegin() + (IsImpulse() ? GetSendLength() : 0); } -ssize_t Message::ReadVector(const struct iovec* vector, size_t vector_length) { +Status<size_t> Message::ReadVector(const struct iovec* vector, + size_t vector_length) { PDX_TRACE_NAME("Message::ReadVector"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - const ssize_t ret = + return svc->endpoint()->ReadMessageData(this, vector, vector_length); + } else { + return ErrorStatus{ESHUTDOWN}; + } +} + +Status<void> Message::ReadVectorAll(const struct iovec* vector, + size_t vector_length) { + PDX_TRACE_NAME("Message::ReadVectorAll"); + if (auto svc = service_.lock()) { + const auto status = svc->endpoint()->ReadMessageData(this, vector, vector_length); - return ReturnCodeOrError(ret); + if (!status) + return status.error_status(); + size_t size_to_read = 0; + for (size_t i = 0; i < vector_length; i++) + size_to_read += vector[i].iov_len; + if (status.get() < size_to_read) + return ErrorStatus{EIO}; + return {}; } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -ssize_t Message::Read(void* buffer, size_t length) { +Status<size_t> Message::Read(void* buffer, size_t length) { PDX_TRACE_NAME("Message::Read"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; const struct iovec vector = {buffer, length}; - const ssize_t ret = svc->endpoint()->ReadMessageData(this, &vector, 1); - return ReturnCodeOrError(ret); + return svc->endpoint()->ReadMessageData(this, &vector, 1); + } else { + return ErrorStatus{ESHUTDOWN}; + } +} + +Status<size_t> Message::WriteVector(const struct iovec* vector, + size_t vector_length) { + PDX_TRACE_NAME("Message::WriteVector"); + if (auto svc = service_.lock()) { + return svc->endpoint()->WriteMessageData(this, vector, vector_length); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -ssize_t Message::WriteVector(const struct iovec* vector, size_t vector_length) { +Status<void> Message::WriteVectorAll(const struct iovec* vector, + size_t vector_length) { PDX_TRACE_NAME("Message::WriteVector"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - const ssize_t ret = + const auto status = svc->endpoint()->WriteMessageData(this, vector, vector_length); - return ReturnCodeOrError(ret); + if (!status) + return status.error_status(); + size_t size_to_write = 0; + for (size_t i = 0; i < vector_length; i++) + size_to_write += vector[i].iov_len; + if (status.get() < size_to_write) + return ErrorStatus{EIO}; + return {}; } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -ssize_t Message::Write(const void* buffer, size_t length) { +Status<size_t> Message::Write(const void* buffer, size_t length) { PDX_TRACE_NAME("Message::Write"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; const struct iovec vector = {const_cast<void*>(buffer), length}; - const ssize_t ret = svc->endpoint()->WriteMessageData(this, &vector, 1); - return ReturnCodeOrError(ret); + return svc->endpoint()->WriteMessageData(this, &vector, 1); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -FileReference Message::PushFileHandle(const LocalHandle& handle) { +Status<FileReference> Message::PushFileHandle(const LocalHandle& handle) { PDX_TRACE_NAME("Message::PushFileHandle"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle)); + return svc->endpoint()->PushFileHandle(this, handle); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -FileReference Message::PushFileHandle(const BorrowedHandle& handle) { +Status<FileReference> Message::PushFileHandle(const BorrowedHandle& handle) { PDX_TRACE_NAME("Message::PushFileHandle"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle)); + return svc->endpoint()->PushFileHandle(this, handle); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -FileReference Message::PushFileHandle(const RemoteHandle& handle) { +Status<FileReference> Message::PushFileHandle(const RemoteHandle& handle) { PDX_TRACE_NAME("Message::PushFileHandle"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle)); + return svc->endpoint()->PushFileHandle(this, handle); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -ChannelReference Message::PushChannelHandle(const LocalChannelHandle& handle) { +Status<ChannelReference> Message::PushChannelHandle( + const LocalChannelHandle& handle) { PDX_TRACE_NAME("Message::PushChannelHandle"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle)); + return svc->endpoint()->PushChannelHandle(this, handle); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -ChannelReference Message::PushChannelHandle( +Status<ChannelReference> Message::PushChannelHandle( const BorrowedChannelHandle& handle) { PDX_TRACE_NAME("Message::PushChannelHandle"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle)); + return svc->endpoint()->PushChannelHandle(this, handle); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } -ChannelReference Message::PushChannelHandle(const RemoteChannelHandle& handle) { +Status<ChannelReference> Message::PushChannelHandle( + const RemoteChannelHandle& handle) { PDX_TRACE_NAME("Message::PushChannelHandle"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle)); + return svc->endpoint()->PushChannelHandle(this, handle); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } @@ -193,7 +218,6 @@ bool Message::GetFileHandle(FileReference ref, LocalHandle* handle) { return false; if (ref >= 0) { - ErrnoGuard errno_guard; *handle = svc->endpoint()->GetFileHandle(this, ref); if (!handle->IsValid()) return false; @@ -211,7 +235,6 @@ bool Message::GetChannelHandle(ChannelReference ref, return false; if (ref >= 0) { - ErrnoGuard errno_guard; *handle = svc->endpoint()->GetChannelHandle(this, ref); if (!handle->valid()) return false; @@ -221,141 +244,137 @@ bool Message::GetChannelHandle(ChannelReference ref, return true; } -int Message::Reply(int return_code) { +Status<void> Message::Reply(int return_code) { PDX_TRACE_NAME("Message::Reply"); auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - const int ret = svc->endpoint()->MessageReply(this, return_code); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + const auto ret = svc->endpoint()->MessageReply(this, return_code); + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::ReplyFileDescriptor(unsigned int fd) { +Status<void> Message::ReplyFileDescriptor(unsigned int fd) { PDX_TRACE_NAME("Message::ReplyFileDescriptor"); auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - const int ret = svc->endpoint()->MessageReplyFd(this, fd); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + const auto ret = svc->endpoint()->MessageReplyFd(this, fd); + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::ReplyError(unsigned error) { +Status<void> Message::ReplyError(unsigned int error) { PDX_TRACE_NAME("Message::ReplyError"); auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - const int ret = svc->endpoint()->MessageReply(this, -error); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + const auto ret = + svc->endpoint()->MessageReply(this, -static_cast<int>(error)); + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::Reply(const LocalHandle& handle) { +Status<void> Message::Reply(const LocalHandle& handle) { PDX_TRACE_NAME("Message::ReplyFileHandle"); auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - int ret; + Status<void> ret; if (handle) ret = svc->endpoint()->MessageReplyFd(this, handle.Get()); else ret = svc->endpoint()->MessageReply(this, handle.Get()); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::Reply(const BorrowedHandle& handle) { +Status<void> Message::Reply(const BorrowedHandle& handle) { PDX_TRACE_NAME("Message::ReplyFileHandle"); auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - int ret; + Status<void> ret; if (handle) ret = svc->endpoint()->MessageReplyFd(this, handle.Get()); else ret = svc->endpoint()->MessageReply(this, handle.Get()); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::Reply(const RemoteHandle& handle) { +Status<void> Message::Reply(const RemoteHandle& handle) { PDX_TRACE_NAME("Message::ReplyFileHandle"); auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - const int ret = svc->endpoint()->MessageReply(this, handle.Get()); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + Status<void> ret; + + if (handle) + ret = svc->endpoint()->MessageReply(this, handle.Get()); + else + ret = svc->endpoint()->MessageReply(this, handle.Get()); + + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::Reply(const LocalChannelHandle& handle) { +Status<void> Message::Reply(const LocalChannelHandle& handle) { auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - const int ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::Reply(const BorrowedChannelHandle& handle) { +Status<void> Message::Reply(const BorrowedChannelHandle& handle) { auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - const int ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::Reply(const RemoteChannelHandle& handle) { +Status<void> Message::Reply(const RemoteChannelHandle& handle) { auto svc = service_.lock(); if (!replied_ && svc) { - ErrnoGuard errno_guard; - const int ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); - replied_ = ret == 0; - return ReturnCodeOrError(ret); + const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle); + replied_ = ret.ok(); + return ret; } else { - return -EINVAL; + return ErrorStatus{EINVAL}; } } -int Message::ModifyChannelEvents(int clear_mask, int set_mask) { +Status<void> Message::ModifyChannelEvents(int clear_mask, int set_mask) { PDX_TRACE_NAME("Message::ModifyChannelEvents"); if (auto svc = service_.lock()) { - ErrnoGuard errno_guard; - const int ret = - svc->endpoint()->ModifyChannelEvents(info_.cid, clear_mask, set_mask); - return ReturnCodeOrError(ret); + return svc->endpoint()->ModifyChannelEvents(info_.cid, clear_mask, + set_mask); } else { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } } @@ -416,11 +435,12 @@ size_t Message::GetFileDescriptorCount() const { return info_.fd_count; } std::shared_ptr<Channel> Message::GetChannel() const { return channel_.lock(); } -void Message::SetChannel(const std::shared_ptr<Channel>& chan) { +Status<void> Message::SetChannel(const std::shared_ptr<Channel>& chan) { channel_ = chan; - + Status<void> status; if (auto svc = service_.lock()) - svc->SetChannel(info_.cid, chan); + status = svc->SetChannel(info_.cid, chan); + return status; } std::shared_ptr<Service> Message::GetService() const { return service_.lock(); } @@ -432,16 +452,16 @@ Service::Service(const std::string& name, std::unique_ptr<Endpoint> endpoint) if (!endpoint_) return; - const int ret = endpoint_->SetService(this); - ALOGE_IF(ret < 0, "Failed to set service context because: %s", - strerror(-ret)); + const auto status = endpoint_->SetService(this); + ALOGE_IF(!status, "Failed to set service context because: %s", + status.GetErrorMessage().c_str()); } Service::~Service() { if (endpoint_) { - const int ret = endpoint_->SetService(nullptr); - ALOGE_IF(ret < 0, "Failed to clear service context because: %s", - strerror(-ret)); + const auto status = endpoint_->SetService(nullptr); + ALOGE_IF(!status, "Failed to clear service context because: %s", + status.GetErrorMessage().c_str()); } } @@ -459,32 +479,28 @@ std::shared_ptr<Channel> Service::OnChannelOpen(Message& /*message*/) { void Service::OnChannelClose(Message& /*message*/, const std::shared_ptr<Channel>& /*channel*/) {} -int Service::SetChannel(int channel_id, - const std::shared_ptr<Channel>& channel) { +Status<void> Service::SetChannel(int channel_id, + const std::shared_ptr<Channel>& channel) { PDX_TRACE_NAME("Service::SetChannel"); - ErrnoGuard errno_guard; std::lock_guard<std::mutex> autolock(channels_mutex_); - const int ret = endpoint_->SetChannel(channel_id, channel.get()); - if (ret == -1) { + const auto status = endpoint_->SetChannel(channel_id, channel.get()); + if (!status) { ALOGE("%s::SetChannel: Failed to set channel context: %s\n", name_.c_str(), - strerror(errno)); + status.GetErrorMessage().c_str()); // It's possible someone mucked with things behind our back by calling the C // API directly. Since we know the channel id isn't valid, make sure we // don't have it in the channels map. - if (errno == ENOENT) + if (status.error() == ENOENT) + channels_.erase(channel_id); + } else { + if (channel != nullptr) + channels_[channel_id] = channel; + else channels_.erase(channel_id); - - return ReturnCodeOrError(ret); } - - if (channel != nullptr) - channels_[channel_id] = channel; - else - channels_.erase(channel_id); - - return ret; + return status; } std::shared_ptr<Channel> Service::GetChannel(int channel_id) const { @@ -498,21 +514,21 @@ std::shared_ptr<Channel> Service::GetChannel(int channel_id) const { return nullptr; } -int Service::CloseChannel(int channel_id) { +Status<void> Service::CloseChannel(int channel_id) { PDX_TRACE_NAME("Service::CloseChannel"); - ErrnoGuard errno_guard; std::lock_guard<std::mutex> autolock(channels_mutex_); - const int ret = endpoint_->CloseChannel(channel_id); + const auto status = endpoint_->CloseChannel(channel_id); // Always erase the map entry, in case someone mucked with things behind our // back using the C API directly. channels_.erase(channel_id); - return ReturnCodeOrError(ret); + return status; } -int Service::ModifyChannelEvents(int channel_id, int clear_mask, int set_mask) { +Status<void> Service::ModifyChannelEvents(int channel_id, int clear_mask, + int set_mask) { PDX_TRACE_NAME("Service::ModifyChannelEvents"); return endpoint_->ModifyChannelEvents(channel_id, clear_mask, set_mask); } @@ -521,7 +537,6 @@ Status<RemoteChannelHandle> Service::PushChannel( Message* message, int flags, const std::shared_ptr<Channel>& channel, int* channel_id) { PDX_TRACE_NAME("Service::PushChannel"); - ErrnoGuard errno_guard; std::lock_guard<std::mutex> autolock(channels_mutex_); @@ -542,7 +557,6 @@ Status<RemoteChannelHandle> Service::PushChannel( Status<int> Service::CheckChannel(const Message* message, ChannelReference ref, std::shared_ptr<Channel>* channel) const { PDX_TRACE_NAME("Service::CheckChannel"); - ErrnoGuard errno_guard; // Synchronization to maintain consistency between the kernel's channel // context pointer and the userspace channels_ map. Other threads may attempt @@ -565,13 +579,13 @@ Status<int> Service::CheckChannel(const Message* message, ChannelReference ref, std::string Service::DumpState(size_t /*max_length*/) { return ""; } -int Service::HandleMessage(Message& message) { +Status<void> Service::HandleMessage(Message& message) { return DefaultHandleMessage(message); } void Service::HandleImpulse(Message& /*impulse*/) {} -bool Service::HandleSystemMessage(Message& message) { +Status<void> Service::HandleSystemMessage(Message& message) { const MessageInfo& info = message.GetInfo(); switch (info.op) { @@ -579,8 +593,7 @@ bool Service::HandleSystemMessage(Message& message) { ALOGD("%s::OnChannelOpen: pid=%d cid=%d\n", name_.c_str(), info.pid, info.cid); message.SetChannel(OnChannelOpen(message)); - message.Reply(0); - return true; + return message.Reply(0); } case opcodes::CHANNEL_CLOSE: { @@ -588,8 +601,7 @@ bool Service::HandleSystemMessage(Message& message) { info.cid); OnChannelClose(message, Channel::GetFromMessageInfo(info)); message.SetChannel(nullptr); - message.Reply(0); - return true; + return message.Reply(0); } case opcodes::REPORT_SYSPROP_CHANGE: @@ -597,8 +609,7 @@ bool Service::HandleSystemMessage(Message& message) { info.pid, info.cid); OnSysPropChange(); android::report_sysprop_change(); - message.Reply(0); - return true; + return message.Reply(0); case opcodes::DUMP_STATE: { ALOGD("%s:DUMP_STATE: pid=%d cid=%d\n", name_.c_str(), info.pid, @@ -607,21 +618,20 @@ bool Service::HandleSystemMessage(Message& message) { const size_t response_size = response.size() < message.GetReceiveLength() ? response.size() : message.GetReceiveLength(); - const ssize_t bytes_written = + const Status<size_t> status = message.Write(response.data(), response_size); - if (bytes_written < static_cast<ssize_t>(response_size)) - message.ReplyError(EIO); + if (status && status.get() < response_size) + return message.ReplyError(EIO); else - message.Reply(bytes_written); - return true; + return message.Reply(status); } default: - return false; + return ErrorStatus{EOPNOTSUPP}; } } -int Service::DefaultHandleMessage(Message& message) { +Status<void> Service::DefaultHandleMessage(Message& message) { const MessageInfo& info = message.GetInfo(); ALOGD_IF(TRACE, "Service::DefaultHandleMessage: pid=%d cid=%d op=%d\n", @@ -632,23 +642,21 @@ int Service::DefaultHandleMessage(Message& message) { case opcodes::CHANNEL_CLOSE: case opcodes::REPORT_SYSPROP_CHANGE: case opcodes::DUMP_STATE: - HandleSystemMessage(message); - return 0; + return HandleSystemMessage(message); default: - return message.ReplyError(ENOTSUP); + return message.ReplyError(EOPNOTSUPP); } } void Service::OnSysPropChange() {} -int Service::ReceiveAndDispatch() { - ErrnoGuard errno_guard; +Status<void> Service::ReceiveAndDispatch() { Message message; - const int ret = endpoint_->MessageReceive(&message); - if (ret < 0) { - ALOGE("Failed to receive message: %s\n", strerror(errno)); - return ReturnCodeOrError(ret); + const auto status = endpoint_->MessageReceive(&message); + if (!status) { + ALOGE("Failed to receive message: %s\n", status.GetErrorMessage().c_str()); + return status; } std::shared_ptr<Service> service = message.GetService(); @@ -657,24 +665,20 @@ int Service::ReceiveAndDispatch() { ALOGE("Service::ReceiveAndDispatch: service context is NULL!!!\n"); // Don't block the sender indefinitely in this error case. endpoint_->MessageReply(&message, -EINVAL); - return -EINVAL; + return ErrorStatus{EINVAL}; } if (message.IsImpulse()) { service->HandleImpulse(message); - return 0; + return {}; } else if (service->HandleSystemMessage(message)) { - return 0; + return {}; } else { return service->HandleMessage(message); } } -int Service::Cancel() { - ErrnoGuard errno_guard; - const int ret = endpoint_->Cancel(); - return ReturnCodeOrError(ret); -} +Status<void> Service::Cancel() { return endpoint_->Cancel(); } } // namespace pdx } // namespace android diff --git a/libs/vr/libpdx/service_tests.cpp b/libs/vr/libpdx/service_tests.cpp index fc0c8dbbf9..c7412b7aae 100644 --- a/libs/vr/libpdx/service_tests.cpp +++ b/libs/vr/libpdx/service_tests.cpp @@ -30,7 +30,6 @@ using testing::Matcher; using testing::Ref; using testing::Return; using testing::SetArgPointee; -using testing::SetErrnoAndReturn; using testing::WithArg; using testing::WithoutArgs; using testing::_; @@ -91,7 +90,7 @@ class MockService : public Service { MOCK_METHOD1(OnChannelOpen, std::shared_ptr<Channel>(Message& message)); MOCK_METHOD2(OnChannelClose, void(Message& message, const std::shared_ptr<Channel>& channel)); - MOCK_METHOD1(HandleMessage, int(Message& message)); + MOCK_METHOD1(HandleMessage, Status<void>(Message& message)); MOCK_METHOD1(HandleImpulse, void(Message& impulse)); MOCK_METHOD0(OnSysPropChange, void()); MOCK_METHOD1(DumpState, std::string(size_t max_length)); @@ -101,7 +100,9 @@ class ServiceTest : public testing::Test { public: ServiceTest() { auto endpoint = std::make_unique<testing::StrictMock<MockEndpoint>>(); - EXPECT_CALL(*endpoint, SetService(_)).Times(2).WillRepeatedly(Return(0)); + EXPECT_CALL(*endpoint, SetService(_)) + .Times(2) + .WillRepeatedly(Return(Status<void>{})); service_ = std::make_shared<MockService>("MockSvc", std::move(endpoint)); } @@ -134,7 +135,8 @@ class ServiceTest : public testing::Test { } void ExpectDefaultHandleMessage() { - EXPECT_CALL(*endpoint(), DefaultHandleMessage(_)); + EXPECT_CALL(*endpoint(), MessageReply(_, -EOPNOTSUPP)) + .WillOnce(Return(Status<void>{})); } std::shared_ptr<MockService> service_; @@ -222,10 +224,11 @@ TEST_F(ServiceTest, HandleMessageChannelOpen) { auto channel = std::make_shared<Channel>(); EXPECT_CALL(*service_, OnChannelOpen(Ref(message))).WillOnce(Return(channel)); EXPECT_CALL(*endpoint(), SetChannel(kTestCid, channel.get())) - .WillOnce(Return(0)); - EXPECT_CALL(*endpoint(), MessageReply(&message, 0)).WillOnce(Return(0)); + .WillOnce(Return(Status<void>{})); + EXPECT_CALL(*endpoint(), MessageReply(&message, 0)) + .WillOnce(Return(Status<void>{})); - EXPECT_EQ(0, service_->Service::HandleMessage(message)); + EXPECT_TRUE(service_->Service::HandleMessage(message)); } TEST_F(ServiceTest, HandleMessageChannelClose) { @@ -237,10 +240,12 @@ TEST_F(ServiceTest, HandleMessageChannelClose) { Message message{info}; EXPECT_CALL(*service_, OnChannelClose(Ref(message), channel)); - EXPECT_CALL(*endpoint(), SetChannel(kTestCid, nullptr)).WillOnce(Return(0)); - EXPECT_CALL(*endpoint(), MessageReply(&message, 0)).WillOnce(Return(0)); + EXPECT_CALL(*endpoint(), SetChannel(kTestCid, nullptr)) + .WillOnce(Return(Status<void>{})); + EXPECT_CALL(*endpoint(), MessageReply(&message, 0)) + .WillOnce(Return(Status<void>{})); - EXPECT_EQ(0, service_->Service::HandleMessage(message)); + EXPECT_TRUE(service_->Service::HandleMessage(message)); } TEST_F(ServiceTest, HandleMessageOnSysPropChange) { @@ -250,9 +255,10 @@ TEST_F(ServiceTest, HandleMessageOnSysPropChange) { Message message{info}; EXPECT_CALL(*service_, OnSysPropChange()); - EXPECT_CALL(*endpoint(), MessageReply(&message, 0)).WillOnce(Return(0)); + EXPECT_CALL(*endpoint(), MessageReply(&message, 0)) + .WillOnce(Return(Status<void>{})); - EXPECT_EQ(0, service_->Service::HandleMessage(message)); + EXPECT_TRUE(service_->Service::HandleMessage(message)); } TEST_F(ServiceTest, HandleMessageOnDumpState) { @@ -270,9 +276,9 @@ TEST_F(ServiceTest, HandleMessageOnDumpState) { WriteMessageData(&message, IoVecDataMatcher(IoVecData{kReply}), 1)) .WillOnce(Return(kReply.size())); EXPECT_CALL(*endpoint(), MessageReply(&message, kReply.size())) - .WillOnce(Return(0)); + .WillOnce(Return(Status<void>{})); - EXPECT_EQ(0, service_->Service::HandleMessage(message)); + EXPECT_TRUE(service_->Service::HandleMessage(message)); } TEST_F(ServiceTest, HandleMessageOnDumpStateTooLarge) { @@ -291,9 +297,9 @@ TEST_F(ServiceTest, HandleMessageOnDumpStateTooLarge) { WriteMessageData(&message, IoVecDataMatcher(IoVecData{kActualReply}), 1)) .WillOnce(Return(kActualReply.size())); EXPECT_CALL(*endpoint(), MessageReply(&message, kActualReply.size())) - .WillOnce(Return(0)); + .WillOnce(Return(Status<void>{})); - EXPECT_EQ(0, service_->Service::HandleMessage(message)); + EXPECT_TRUE(service_->Service::HandleMessage(message)); } TEST_F(ServiceTest, HandleMessageOnDumpStateFail) { @@ -310,9 +316,10 @@ TEST_F(ServiceTest, HandleMessageOnDumpStateFail) { *endpoint(), WriteMessageData(&message, IoVecDataMatcher(IoVecData{kReply}), 1)) .WillOnce(Return(1)); - EXPECT_CALL(*endpoint(), MessageReply(&message, -EIO)).WillOnce(Return(0)); + EXPECT_CALL(*endpoint(), MessageReply(&message, -EIO)) + .WillOnce(Return(Status<void>{})); - EXPECT_EQ(0, service_->Service::HandleMessage(message)); + EXPECT_TRUE(service_->Service::HandleMessage(message)); } TEST_F(ServiceTest, HandleMessageCustom) { @@ -320,10 +327,10 @@ TEST_F(ServiceTest, HandleMessageCustom) { SetupMessageInfoAndDefaultExpectations(&info, kTestOp); Message message{info}; - EXPECT_CALL(*endpoint(), MessageReply(&message, -ENOTSUP)) - .WillOnce(Return(0)); + EXPECT_CALL(*endpoint(), MessageReply(&message, -EOPNOTSUPP)) + .WillOnce(Return(Status<void>{})); - EXPECT_EQ(0, service_->Service::HandleMessage(message)); + EXPECT_TRUE(service_->Service::HandleMessage(message)); } TEST_F(ServiceTest, ReplyMessageWithoutService) { @@ -337,7 +344,7 @@ TEST_F(ServiceTest, ReplyMessageWithoutService) { service_.reset(); EXPECT_TRUE(message.IsServiceExpired()); - EXPECT_EQ(-EINVAL, message.Reply(12)); + EXPECT_EQ(EINVAL, message.Reply(12).error()); } TEST_F(ServiceTest, ReceiveAndDispatchMessage) { @@ -345,33 +352,33 @@ TEST_F(ServiceTest, ReceiveAndDispatchMessage) { SetupMessageInfoAndDefaultExpectations(&info, kTestOp); ExpectDefaultHandleMessage(); - auto on_receive = [&info](Message* message) { + auto on_receive = [&info](Message* message) -> Status<void> { *message = Message{info}; - return 0; + return {}; }; EXPECT_CALL(*endpoint(), MessageReceive(_)).WillOnce(Invoke(on_receive)); - EXPECT_CALL(*service_, HandleMessage(_)).WillOnce(Return(0)); + EXPECT_CALL(*service_, HandleMessage(_)).WillOnce(Return(Status<void>{})); - EXPECT_EQ(0, service_->ReceiveAndDispatch()); + EXPECT_TRUE(service_->ReceiveAndDispatch()); } TEST_F(ServiceTest, ReceiveAndDispatchImpulse) { MessageInfo info; SetupMessageInfoAndDefaultExpectations(&info, kTestOp, true); - auto on_receive = [&info](Message* message) { + auto on_receive = [&info](Message* message) -> Status<void> { *message = Message{info}; - return 0; + return {}; }; EXPECT_CALL(*endpoint(), MessageReceive(_)).WillOnce(Invoke(on_receive)); EXPECT_CALL(*service_, HandleImpulse(_)); - EXPECT_EQ(0, service_->ReceiveAndDispatch()); + EXPECT_TRUE(service_->ReceiveAndDispatch()); } TEST_F(ServiceTest, Cancel) { - EXPECT_CALL(*endpoint(), Cancel()).WillOnce(Return(0)); - EXPECT_EQ(0, service_->Cancel()); + EXPECT_CALL(*endpoint(), Cancel()).WillOnce(Return(Status<void>{})); + EXPECT_TRUE(service_->Cancel()); } /////////////////////////////////////////////////////////////////////////////// @@ -380,85 +387,85 @@ TEST_F(ServiceTest, Cancel) { TEST_F(ServiceMessageTest, Reply) { EXPECT_CALL(*endpoint(), MessageReply(message_.get(), 12)) - .WillOnce(Return(0)); + .WillOnce(Return(Status<void>{})); EXPECT_FALSE(message_->replied()); - EXPECT_EQ(0, message_->Reply(12)); + EXPECT_TRUE(message_->Reply(12)); EXPECT_TRUE(message_->replied()); - EXPECT_EQ(-EINVAL, message_->Reply(12)); // Already replied. + EXPECT_EQ(EINVAL, message_->Reply(12).error()); // Already replied. } TEST_F(ServiceMessageTest, ReplyFail) { EXPECT_CALL(*endpoint(), MessageReply(message_.get(), 12)) - .WillOnce(SetErrnoAndReturn(EIO, -1)); - EXPECT_EQ(-EIO, message_->Reply(12)); + .WillOnce(Return(ErrorStatus{EIO})); + EXPECT_EQ(EIO, message_->Reply(12).error()); ExpectDefaultHandleMessage(); } TEST_F(ServiceMessageTest, ReplyError) { EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -12)) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->ReplyError(12)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->ReplyError(12)); } TEST_F(ServiceMessageTest, ReplyFileDescriptor) { EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), 5)) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->ReplyFileDescriptor(5)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->ReplyFileDescriptor(5)); } TEST_F(ServiceMessageTest, ReplyLocalFileHandle) { const int kFakeFd = 12345; LocalHandle handle{kFakeFd}; EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), kFakeFd)) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); handle.Release(); // Make sure we do not close the fake file descriptor. } TEST_F(ServiceMessageTest, ReplyLocalFileHandleError) { LocalHandle handle{-EINVAL}; EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EINVAL)) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); } TEST_F(ServiceMessageTest, ReplyBorrowedFileHandle) { const int kFakeFd = 12345; BorrowedHandle handle{kFakeFd}; EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), kFakeFd)) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); } TEST_F(ServiceMessageTest, ReplyBorrowedFileHandleError) { BorrowedHandle handle{-EACCES}; EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EACCES)) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); } TEST_F(ServiceMessageTest, ReplyRemoteFileHandle) { RemoteHandle handle{123}; EXPECT_CALL(*endpoint(), MessageReply(message_.get(), handle.Get())) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); } TEST_F(ServiceMessageTest, ReplyRemoteFileHandleError) { RemoteHandle handle{-EIO}; EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EIO)) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); } TEST_F(ServiceMessageTest, ReplyLocalChannelHandle) { LocalChannelHandle handle{nullptr, 12345}; EXPECT_CALL(*endpoint(), MessageReplyChannelHandle( message_.get(), A<const LocalChannelHandle&>())) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); } TEST_F(ServiceMessageTest, ReplyBorrowedChannelHandle) { @@ -466,30 +473,30 @@ TEST_F(ServiceMessageTest, ReplyBorrowedChannelHandle) { EXPECT_CALL(*endpoint(), MessageReplyChannelHandle(message_.get(), A<const BorrowedChannelHandle&>())) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); } TEST_F(ServiceMessageTest, ReplyRemoteChannelHandle) { RemoteChannelHandle handle{12345}; EXPECT_CALL(*endpoint(), MessageReplyChannelHandle( message_.get(), A<const RemoteChannelHandle&>())) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(handle)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(handle)); } TEST_F(ServiceMessageTest, ReplyStatusInt) { Status<int> status{123}; EXPECT_CALL(*endpoint(), MessageReply(message_.get(), status.get())) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(status)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(status)); } TEST_F(ServiceMessageTest, ReplyStatusError) { Status<int> status{ErrorStatus{EIO}}; EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -status.error())) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->Reply(status)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->Reply(status)); } TEST_F(ServiceMessageTest, Read) { @@ -500,9 +507,9 @@ TEST_F(ServiceMessageTest, Read) { *endpoint(), ReadMessageData(message_.get(), IoVecMatcher(kDataBuffer, kDataSize), 1)) .WillOnce(Return(50)) - .WillOnce(SetErrnoAndReturn(EACCES, -1)); - EXPECT_EQ(50, message_->Read(kDataBuffer, kDataSize)); - EXPECT_EQ(-EACCES, message_->Read(kDataBuffer, kDataSize)); + .WillOnce(Return(ErrorStatus{EACCES})); + EXPECT_EQ(50u, message_->Read(kDataBuffer, kDataSize).get()); + EXPECT_EQ(EACCES, message_->Read(kDataBuffer, kDataSize).error()); } TEST_F(ServiceMessageTest, ReadVector) { @@ -516,10 +523,10 @@ TEST_F(ServiceMessageTest, ReadVector) { IoVecMatcher(IoVecArray{std::begin(vec), std::end(vec)}), 2)) .WillOnce(Return(30)) .WillOnce(Return(15)) - .WillOnce(SetErrnoAndReturn(EBADF, -1)); - EXPECT_EQ(30, message_->ReadVector(vec, 2)); - EXPECT_EQ(15, message_->ReadVector(vec)); - EXPECT_EQ(-EBADF, message_->ReadVector(vec)); + .WillOnce(Return(ErrorStatus{EBADF})); + EXPECT_EQ(30u, message_->ReadVector(vec, 2).get()); + EXPECT_EQ(15u, message_->ReadVector(vec).get()); + EXPECT_EQ(EBADF, message_->ReadVector(vec).error()); } TEST_F(ServiceMessageTest, Write) { @@ -530,9 +537,9 @@ TEST_F(ServiceMessageTest, Write) { *endpoint(), WriteMessageData(message_.get(), IoVecMatcher(kDataBuffer, kDataSize), 1)) .WillOnce(Return(50)) - .WillOnce(SetErrnoAndReturn(EBADMSG, -1)); - EXPECT_EQ(50, message_->Write(kDataBuffer, kDataSize)); - EXPECT_EQ(-EBADMSG, message_->Write(kDataBuffer, kDataSize)); + .WillOnce(Return(ErrorStatus{EBADMSG})); + EXPECT_EQ(50u, message_->Write(kDataBuffer, kDataSize).get()); + EXPECT_EQ(EBADMSG, message_->Write(kDataBuffer, kDataSize).error()); } TEST_F(ServiceMessageTest, WriteVector) { @@ -546,10 +553,10 @@ TEST_F(ServiceMessageTest, WriteVector) { IoVecMatcher(IoVecArray{std::begin(vec), std::end(vec)}), 2)) .WillOnce(Return(30)) .WillOnce(Return(15)) - .WillOnce(SetErrnoAndReturn(EIO, -1)); - EXPECT_EQ(30, message_->WriteVector(vec, 2)); - EXPECT_EQ(15, message_->WriteVector(vec)); - EXPECT_EQ(-EIO, message_->WriteVector(vec, 2)); + .WillOnce(Return(ErrorStatus{EIO})); + EXPECT_EQ(30u, message_->WriteVector(vec, 2).get()); + EXPECT_EQ(15u, message_->WriteVector(vec).get()); + EXPECT_EQ(EIO, message_->WriteVector(vec, 2).error()); } TEST_F(ServiceMessageTest, PushLocalFileHandle) { @@ -560,9 +567,9 @@ TEST_F(ServiceMessageTest, PushLocalFileHandle) { PushFileHandle(message_.get(), Matcher<const LocalHandle&>( FileHandleMatcher(kFakeFd)))) .WillOnce(Return(12)) - .WillOnce(SetErrnoAndReturn(EIO, -1)); - EXPECT_EQ(12, message_->PushFileHandle(handle)); - EXPECT_EQ(-EIO, message_->PushFileHandle(handle)); + .WillOnce(Return(ErrorStatus{EIO})); + EXPECT_EQ(12, message_->PushFileHandle(handle).get()); + EXPECT_EQ(EIO, message_->PushFileHandle(handle).error()); handle.Release(); // Make sure we do not close the fake file descriptor. } @@ -574,9 +581,9 @@ TEST_F(ServiceMessageTest, PushBorrowedFileHandle) { PushFileHandle(message_.get(), Matcher<const BorrowedHandle&>( FileHandleMatcher(kFakeFd)))) .WillOnce(Return(13)) - .WillOnce(SetErrnoAndReturn(EACCES, -1)); - EXPECT_EQ(13, message_->PushFileHandle(handle)); - EXPECT_EQ(-EACCES, message_->PushFileHandle(handle)); + .WillOnce(Return(ErrorStatus{EACCES})); + EXPECT_EQ(13, message_->PushFileHandle(handle).get()); + EXPECT_EQ(EACCES, message_->PushFileHandle(handle).error()); } TEST_F(ServiceMessageTest, PushRemoteFileHandle) { @@ -587,9 +594,9 @@ TEST_F(ServiceMessageTest, PushRemoteFileHandle) { PushFileHandle(message_.get(), Matcher<const RemoteHandle&>( FileHandleMatcher(kFakeFd)))) .WillOnce(Return(kFakeFd)) - .WillOnce(SetErrnoAndReturn(EIO, -1)); - EXPECT_EQ(kFakeFd, message_->PushFileHandle(handle)); - EXPECT_EQ(-EIO, message_->PushFileHandle(handle)); + .WillOnce(Return(ErrorStatus{EIO})); + EXPECT_EQ(kFakeFd, message_->PushFileHandle(handle).get()); + EXPECT_EQ(EIO, message_->PushFileHandle(handle).error()); } TEST_F(ServiceMessageTest, PushLocalChannelHandle) { @@ -600,9 +607,9 @@ TEST_F(ServiceMessageTest, PushLocalChannelHandle) { Matcher<const LocalChannelHandle&>( ChannelHandleMatcher(kValue)))) .WillOnce(Return(7)) - .WillOnce(SetErrnoAndReturn(EIO, -1)); - EXPECT_EQ(7, message_->PushChannelHandle(handle)); - EXPECT_EQ(-EIO, message_->PushChannelHandle(handle)); + .WillOnce(Return(ErrorStatus{EIO})); + EXPECT_EQ(7, message_->PushChannelHandle(handle).get()); + EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error()); } TEST_F(ServiceMessageTest, PushBorrowedChannelHandle) { @@ -614,9 +621,9 @@ TEST_F(ServiceMessageTest, PushBorrowedChannelHandle) { PushChannelHandle(message_.get(), Matcher<const BorrowedChannelHandle&>( ChannelHandleMatcher(kValue)))) .WillOnce(Return(8)) - .WillOnce(SetErrnoAndReturn(EIO, -1)); - EXPECT_EQ(8, message_->PushChannelHandle(handle)); - EXPECT_EQ(-EIO, message_->PushChannelHandle(handle)); + .WillOnce(Return(ErrorStatus{EIO})); + EXPECT_EQ(8, message_->PushChannelHandle(handle).get()); + EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error()); } TEST_F(ServiceMessageTest, PushRemoteChannelHandle) { @@ -628,9 +635,9 @@ TEST_F(ServiceMessageTest, PushRemoteChannelHandle) { PushChannelHandle(message_.get(), Matcher<const RemoteChannelHandle&>( ChannelHandleMatcher(kValue)))) .WillOnce(Return(kValue)) - .WillOnce(SetErrnoAndReturn(EIO, -1)); - EXPECT_EQ(kValue, message_->PushChannelHandle(handle)); - EXPECT_EQ(-EIO, message_->PushChannelHandle(handle)); + .WillOnce(Return(ErrorStatus{EIO})); + EXPECT_EQ(kValue, message_->PushChannelHandle(handle).get()); + EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error()); } TEST_F(ServiceMessageTest, GetFileHandle) { @@ -701,8 +708,8 @@ TEST_F(ServiceMessageTest, ModifyChannelEvents) { int kClearMask = 1; int kSetMask = 2; EXPECT_CALL(*endpoint(), ModifyChannelEvents(kTestCid, kClearMask, kSetMask)) - .WillOnce(Return(0)); - EXPECT_EQ(0, message_->ModifyChannelEvents(kClearMask, kSetMask)); + .WillOnce(Return(Status<void>{})); + EXPECT_TRUE(message_->ModifyChannelEvents(kClearMask, kSetMask)); } TEST_F(ServiceMessageTest, PushChannelSameService) { @@ -733,7 +740,9 @@ TEST_F(ServiceMessageTest, PushChannelFailure) { TEST_F(ServiceMessageTest, PushChannelDifferentService) { ExpectDefaultHandleMessage(); auto endpoint2 = std::make_unique<testing::StrictMock<MockEndpoint>>(); - EXPECT_CALL(*endpoint2, SetService(_)).Times(2).WillRepeatedly(Return(0)); + EXPECT_CALL(*endpoint2, SetService(_)) + .Times(2) + .WillRepeatedly(Return(Status<void>{})); auto service2 = std::make_shared<MockService>("MockSvc2", std::move(endpoint2)); @@ -779,7 +788,9 @@ TEST_F(ServiceMessageTest, CheckChannelFailure) { TEST_F(ServiceMessageTest, CheckChannelDifferentService) { ExpectDefaultHandleMessage(); auto endpoint2 = std::make_unique<testing::StrictMock<MockEndpoint>>(); - EXPECT_CALL(*endpoint2, SetService(_)).Times(2).WillRepeatedly(Return(0)); + EXPECT_CALL(*endpoint2, SetService(_)) + .Times(2) + .WillRepeatedly(Return(Status<void>{})); auto service2 = std::make_shared<MockService>("MockSvc2", std::move(endpoint2)); diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp index 655adb8ddc..8cfa86fa44 100644 --- a/libs/vr/libpdx_default_transport/Android.bp +++ b/libs/vr/libpdx_default_transport/Android.bp @@ -57,6 +57,7 @@ cc_binary { "pdx_benchmarks.cpp", ], shared_libs: [ + "libbase", "libchrome", "libcutils", "liblog", diff --git a/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp b/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp index de0240189b..0b658fbc70 100644 --- a/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp +++ b/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp @@ -38,6 +38,7 @@ using android::pdx::Channel; using android::pdx::ClientBase; using android::pdx::Endpoint; +using android::pdx::ErrorStatus; using android::pdx::Message; using android::pdx::Service; using android::pdx::ServiceBase; @@ -246,7 +247,7 @@ class BenchmarkService : public ServiceBase<BenchmarkService> { << message.GetChannelId(); } - int HandleMessage(Message& message) override { + Status<void> HandleMessage(Message& message) override { ATRACE_NAME("BenchmarkService::HandleMessage"); switch (message.GetOp()) { @@ -254,30 +255,27 @@ class BenchmarkService : public ServiceBase<BenchmarkService> { VLOG(1) << "BenchmarkService::HandleMessage: op=nop"; { ATRACE_NAME("Reply"); - CHECK(message.Reply(0) == 0); + CHECK(message.Reply(0)); } - return 0; + return {}; case BenchmarkOps::Write: { VLOG(1) << "BenchmarkService::HandleMessage: op=write send_length=" << message.GetSendLength() << " receive_length=" << message.GetReceiveLength(); - const ssize_t expected_length = - static_cast<ssize_t>(message.GetSendLength()); - const ssize_t actual_length = - expected_length > 0 - ? message.Read(send_buffer.data(), message.GetSendLength()) - : 0; + Status<void> status; + if (message.GetSendLength()) + status = message.ReadAll(send_buffer.data(), message.GetSendLength()); { ATRACE_NAME("Reply"); - if (actual_length < expected_length) - CHECK(message.ReplyError(EIO) == 0); + if (!status) + CHECK(message.ReplyError(status.error())); else - CHECK(message.Reply(actual_length) == 0); + CHECK(message.Reply(message.GetSendLength())); } - return 0; + return {}; } case BenchmarkOps::Read: { @@ -285,22 +283,20 @@ class BenchmarkService : public ServiceBase<BenchmarkService> { << message.GetSendLength() << " receive_length=" << message.GetReceiveLength(); - const ssize_t expected_length = - static_cast<ssize_t>(message.GetReceiveLength()); - const ssize_t actual_length = - expected_length > 0 - ? message.Write(receive_buffer.data(), - message.GetReceiveLength()) - : 0; + Status<void> status; + if (message.GetReceiveLength()) { + status = message.WriteAll(receive_buffer.data(), + message.GetReceiveLength()); + } { ATRACE_NAME("Reply"); - if (actual_length < expected_length) - CHECK(message.ReplyError(EIO) == 0); + if (!status) + CHECK(message.ReplyError(status.error())); else - CHECK(message.Reply(actual_length) == 0); + CHECK(message.Reply(message.GetReceiveLength())); } - return 0; + return {}; } case BenchmarkOps::Echo: { @@ -308,31 +304,28 @@ class BenchmarkService : public ServiceBase<BenchmarkService> { << message.GetSendLength() << " receive_length=" << message.GetReceiveLength(); - const ssize_t expected_length = - static_cast<ssize_t>(message.GetSendLength()); - ssize_t actual_length = - expected_length > 0 - ? message.Read(send_buffer.data(), message.GetSendLength()) - : 0; + Status<void> status; + if (message.GetSendLength()) + status = message.ReadAll(send_buffer.data(), message.GetSendLength()); - if (actual_length < expected_length) { - CHECK(message.ReplyError(EIO) == 0); - return 0; + if (!status) { + CHECK(message.ReplyError(status.error())); + return {}; } - actual_length = - expected_length > 0 - ? message.Write(send_buffer.data(), message.GetSendLength()) - : 0; + if (message.GetSendLength()) { + status = + message.WriteAll(send_buffer.data(), message.GetSendLength()); + } { ATRACE_NAME("Reply"); - if (actual_length < expected_length) - CHECK(message.ReplyError(EIO) == 0); + if (!status) + CHECK(message.ReplyError(status.error())); else - CHECK(message.Reply(actual_length) == 0); + CHECK(message.Reply(message.GetSendLength())); } - return 0; + return {}; } case BenchmarkOps::Stats: { @@ -348,7 +341,7 @@ class BenchmarkService : public ServiceBase<BenchmarkService> { RemoteMethodReturn<BenchmarkRPC::Stats>( message, BenchmarkRPC::Stats::Return{receive_time_ns, GetClockNs(), sched_stats_}); - return 0; + return {}; } case BenchmarkOps::WriteVector: @@ -358,7 +351,7 @@ class BenchmarkService : public ServiceBase<BenchmarkService> { DispatchRemoteMethod<BenchmarkRPC::WriteVector>( *this, &BenchmarkService::OnWriteVector, message, kMaxMessageSize); - return 0; + return {}; case BenchmarkOps::EchoVector: VLOG(1) << "BenchmarkService::HandleMessage: op=echovec send_length=" @@ -367,11 +360,11 @@ class BenchmarkService : public ServiceBase<BenchmarkService> { DispatchRemoteMethod<BenchmarkRPC::EchoVector>( *this, &BenchmarkService::OnEchoVector, message, kMaxMessageSize); - return 0; + return {}; case BenchmarkOps::Quit: Cancel(); - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; default: VLOG(1) << "BenchmarkService::HandleMessage: default case; op=" @@ -543,17 +536,17 @@ int ServiceCommand(const std::string& path) { const std::shared_ptr<BenchmarkService>& local_service) { SetThreadName("service" + std::to_string(service_id)); - // Read the inital schedstats for this thread from procfs. + // Read the initial schedstats for this thread from procfs. local_service->UpdateSchedStats(); ATRACE_NAME("BenchmarkService::Dispatch"); while (!done) { - const int ret = local_service->ReceiveAndDispatch(); - if (ret < 0) { - if (ret != -ESHUTDOWN) { + auto ret = local_service->ReceiveAndDispatch(); + if (!ret) { + if (ret.error() != ESHUTDOWN) { std::cerr << "Error while dispatching message on thread " << thread_id << " service " << service_id << ": " - << strerror(-ret) << std::endl; + << ret.GetErrorMessage() << std::endl; } else { std::cerr << "Quitting thread " << thread_id << " service " << service_id << std::endl; diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp index 09eeaa04d0..a73ba34177 100644 --- a/libs/vr/libpdx_uds/Android.bp +++ b/libs/vr/libpdx_uds/Android.bp @@ -20,6 +20,8 @@ cc_library_static { "service_endpoint.cpp", ], static_libs: [ + "libcutils", + "libbase", "libpdx", ], } @@ -41,6 +43,8 @@ cc_test { "libpdx", ], shared_libs: [ + "libbase", + "libcutils", "liblog", "libutils", ], diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp index f8baeabe88..ac4dea993b 100644 --- a/libs/vr/libpdx_uds/channel_event_set.cpp +++ b/libs/vr/libpdx_uds/channel_event_set.cpp @@ -12,7 +12,7 @@ ChannelEventSet::ChannelEventSet() { const int flags = EFD_CLOEXEC | EFD_NONBLOCK; LocalHandle epoll_fd, event_fd; - if (!SetupHandle(epoll_create(1), &epoll_fd, "epoll") || + if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll") || !SetupHandle(eventfd(0, flags), &event_fd, "event")) { return; } diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp index 18791276a1..f059453ce0 100644 --- a/libs/vr/libpdx_uds/client_channel_factory.cpp +++ b/libs/vr/libpdx_uds/client_channel_factory.cpp @@ -6,10 +6,16 @@ #include <sys/un.h> #include <unistd.h> +#include <chrono> +#include <thread> + #include <uds/channel_manager.h> #include <uds/client_channel.h> #include <uds/ipc_helper.h> +using std::chrono::duration_cast; +using std::chrono::steady_clock; + namespace android { namespace pdx { namespace uds { @@ -41,13 +47,11 @@ std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create( Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect( int64_t timeout_ms) const { - auto status = WaitForEndpoint(endpoint_path_, timeout_ms); - if (!status) - return ErrorStatus(status.error()); + Status<void> status; LocalHandle socket_fd{socket(AF_UNIX, SOCK_STREAM, 0)}; if (!socket_fd) { - ALOGE("ClientChannelFactory::Connect: socket error %s", strerror(errno)); + ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno)); return ErrorStatus(errno); } @@ -56,16 +60,55 @@ Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect( strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path)); remote.sun_path[sizeof(remote.sun_path) - 1] = '\0'; - int ret = RETRY_EINTR(connect( - socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote))); - if (ret == -1) { - ALOGE( - "ClientChannelFactory::Connect: Failed to initialize connection when " - "connecting %s", - strerror(errno)); - return ErrorStatus(errno); - } + bool use_timeout = (timeout_ms >= 0); + auto now = steady_clock::now(); + auto time_end = now + std::chrono::milliseconds{timeout_ms}; + + bool connected = false; + while (!connected) { + int64_t timeout = -1; + if (use_timeout) { + auto remaining = time_end - now; + timeout = duration_cast<std::chrono::milliseconds>(remaining).count(); + if (timeout < 0) + return ErrorStatus(ETIMEDOUT); + } + ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path); + status = WaitForEndpoint(endpoint_path_, timeout); + if (!status) + return ErrorStatus(status.error()); + + ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path); + int ret = RETRY_EINTR(connect( + socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote))); + if (ret == -1) { + ALOGD("ClientChannelFactory: Connect error %d: %s", errno, + strerror(errno)); + if (errno == ECONNREFUSED) { + // Connection refused can be the result of connecting too early (the + // service socket is created but not being listened to yet). + ALOGD("ClientChannelFactory: Connection refused, waiting..."); + using namespace std::literals::chrono_literals; + std::this_thread::sleep_for(100ms); + } else if (errno != ENOENT && errno != ENOTDIR) { + // ENOENT/ENOTDIR might mean that the socket file/directory containing + // it has been just deleted. Try to wait for its creation and do not + // return an error immediately. + ALOGE( + "ClientChannelFactory::Connect: Failed to initialize connection " + "when connecting: %s", + strerror(errno)); + return ErrorStatus(errno); + } + } else { + connected = true; + } + if (use_timeout) + now = steady_clock::now(); + } // while (!connected) + ALOGD("ClientChannelFactory: Connected successfully to %s...", + remote.sun_path); RequestHeader<BorrowedHandle> request; InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false); status = SendData(socket_fd.Get(), request); diff --git a/libs/vr/libpdx_uds/ipc_helper.cpp b/libs/vr/libpdx_uds/ipc_helper.cpp index ee7299e1a9..fe5c98631e 100644 --- a/libs/vr/libpdx_uds/ipc_helper.cpp +++ b/libs/vr/libpdx_uds/ipc_helper.cpp @@ -87,7 +87,7 @@ void* SendPayload::GetNextWriteBufferSection(size_t size) { OutputResourceMapper* SendPayload::GetOutputResourceMapper() { return this; } // OutputResourceMapper -FileReference SendPayload::PushFileHandle(const LocalHandle& handle) { +Status<FileReference> SendPayload::PushFileHandle(const LocalHandle& handle) { if (handle) { const int ref = file_handles_.size(); file_handles_.push_back(handle.Get()); @@ -97,7 +97,8 @@ FileReference SendPayload::PushFileHandle(const LocalHandle& handle) { } } -FileReference SendPayload::PushFileHandle(const BorrowedHandle& handle) { +Status<FileReference> SendPayload::PushFileHandle( + const BorrowedHandle& handle) { if (handle) { const int ref = file_handles_.size(); file_handles_.push_back(handle.Get()); @@ -107,21 +108,21 @@ FileReference SendPayload::PushFileHandle(const BorrowedHandle& handle) { } } -FileReference SendPayload::PushFileHandle(const RemoteHandle& handle) { +Status<FileReference> SendPayload::PushFileHandle(const RemoteHandle& handle) { return handle.Get(); } -ChannelReference SendPayload::PushChannelHandle( +Status<ChannelReference> SendPayload::PushChannelHandle( const LocalChannelHandle& /*handle*/) { - return -1; + return ErrorStatus{EOPNOTSUPP}; } -ChannelReference SendPayload::PushChannelHandle( +Status<ChannelReference> SendPayload::PushChannelHandle( const BorrowedChannelHandle& /*handle*/) { - return -1; + return ErrorStatus{EOPNOTSUPP}; } -ChannelReference SendPayload::PushChannelHandle( +Status<ChannelReference> SendPayload::PushChannelHandle( const RemoteChannelHandle& /*handle*/) { - return -1; + return ErrorStatus{EOPNOTSUPP}; } Status<void> ReceivePayload::Receive(int socket_fd) { diff --git a/libs/vr/libpdx_uds/private/uds/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h index 00f3490fe7..80530bf2ff 100644 --- a/libs/vr/libpdx_uds/private/uds/ipc_helper.h +++ b/libs/vr/libpdx_uds/private/uds/ipc_helper.h @@ -33,13 +33,14 @@ class SendPayload : public MessageWriter, public OutputResourceMapper { OutputResourceMapper* GetOutputResourceMapper() override; // OutputResourceMapper - FileReference PushFileHandle(const LocalHandle& handle) override; - FileReference PushFileHandle(const BorrowedHandle& handle) override; - FileReference PushFileHandle(const RemoteHandle& handle) override; - ChannelReference PushChannelHandle(const LocalChannelHandle& handle) override; - ChannelReference PushChannelHandle( + Status<FileReference> PushFileHandle(const LocalHandle& handle) override; + Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override; + Status<FileReference> PushFileHandle(const RemoteHandle& handle) override; + Status<ChannelReference> PushChannelHandle( + const LocalChannelHandle& handle) override; + Status<ChannelReference> PushChannelHandle( const BorrowedChannelHandle& handle) override; - ChannelReference PushChannelHandle( + Status<ChannelReference> PushChannelHandle( const RemoteChannelHandle& handle) override; private: diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h index 3ec851909b..2b24f62b84 100644 --- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h +++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h @@ -39,41 +39,40 @@ class Endpoint : public pdx::Endpoint { ~Endpoint() override = default; uint32_t GetIpcTag() const override { return kIpcTag; } - int SetService(Service* service) override; - int SetChannel(int channel_id, Channel* channel) override; - int CloseChannel(int channel_id) override; - int ModifyChannelEvents(int channel_id, int clear_mask, - int set_mask) override; + Status<void> SetService(Service* service) override; + Status<void> SetChannel(int channel_id, Channel* channel) override; + Status<void> CloseChannel(int channel_id) override; + Status<void> ModifyChannelEvents(int channel_id, int clear_mask, + int set_mask) override; Status<RemoteChannelHandle> PushChannel(Message* message, int flags, Channel* channel, int* channel_id) override; Status<int> CheckChannel(const Message* message, ChannelReference ref, Channel** channel) override; - int DefaultHandleMessage(const MessageInfo& info) override; - int MessageReceive(Message* message) override; - int MessageReply(Message* message, int return_code) override; - int MessageReplyFd(Message* message, unsigned int push_fd) override; - int MessageReplyChannelHandle(Message* message, - const LocalChannelHandle& handle) override; - int MessageReplyChannelHandle(Message* message, - const BorrowedChannelHandle& handle) override; - int MessageReplyChannelHandle(Message* message, - const RemoteChannelHandle& handle) override; - ssize_t ReadMessageData(Message* message, const iovec* vector, - size_t vector_length) override; - ssize_t WriteMessageData(Message* message, const iovec* vector, - size_t vector_length) override; - FileReference PushFileHandle(Message* message, - const LocalHandle& handle) override; - FileReference PushFileHandle(Message* message, - const BorrowedHandle& handle) override; - FileReference PushFileHandle(Message* message, - const RemoteHandle& handle) override; - ChannelReference PushChannelHandle(Message* message, - const LocalChannelHandle& handle) override; - ChannelReference PushChannelHandle( + Status<void> MessageReceive(Message* message) override; + Status<void> MessageReply(Message* message, int return_code) override; + Status<void> MessageReplyFd(Message* message, unsigned int push_fd) override; + Status<void> MessageReplyChannelHandle( + Message* message, const LocalChannelHandle& handle) override; + Status<void> MessageReplyChannelHandle( Message* message, const BorrowedChannelHandle& handle) override; - ChannelReference PushChannelHandle( + Status<void> MessageReplyChannelHandle( + Message* message, const RemoteChannelHandle& handle) override; + Status<size_t> ReadMessageData(Message* message, const iovec* vector, + size_t vector_length) override; + Status<size_t> WriteMessageData(Message* message, const iovec* vector, + size_t vector_length) override; + Status<FileReference> PushFileHandle(Message* message, + const LocalHandle& handle) override; + Status<FileReference> PushFileHandle(Message* message, + const BorrowedHandle& handle) override; + Status<FileReference> PushFileHandle(Message* message, + const RemoteHandle& handle) override; + Status<ChannelReference> PushChannelHandle( + Message* message, const LocalChannelHandle& handle) override; + Status<ChannelReference> PushChannelHandle( + Message* message, const BorrowedChannelHandle& handle) override; + Status<ChannelReference> PushChannelHandle( Message* message, const RemoteChannelHandle& handle) override; LocalHandle GetFileHandle(Message* message, FileReference ref) const override; LocalChannelHandle GetChannelHandle(Message* message, @@ -82,15 +81,22 @@ class Endpoint : public pdx::Endpoint { void* AllocateMessageState() override; void FreeMessageState(void* state) override; - int Cancel() override; + Status<void> Cancel() override; // Open an endpoint at the given path. // Second parameter is unused for UDS, but we have it here for compatibility // in signature with servicefs::Endpoint::Create(). + // This method uses |endpoint_path| as a relative path to endpoint socket + // created by init process. static std::unique_ptr<Endpoint> Create(const std::string& endpoint_path, mode_t /*unused_mode*/ = kDefaultMode, bool blocking = kDefaultBlocking); + // Helper method to create an endpoint at the given UDS socket path. This + // method physically creates and binds a socket at that path. + static std::unique_ptr<Endpoint> CreateAndBindSocket( + const std::string& endpoint_path, bool blocking = kDefaultBlocking); + int epoll_fd() const { return epoll_fd_.Get(); } private: @@ -101,7 +107,8 @@ class Endpoint : public pdx::Endpoint { }; // This class must be instantiated using Create() static methods above. - Endpoint(const std::string& endpoint_path, bool blocking); + Endpoint(const std::string& endpoint_path, bool blocking, + bool use_init_socket_fd = true); Endpoint(const Endpoint&) = delete; void operator=(const Endpoint&) = delete; @@ -117,7 +124,7 @@ class Endpoint : public pdx::Endpoint { Status<void> OnNewChannel(LocalHandle channel_fd); Status<ChannelData*> OnNewChannelLocked(LocalHandle channel_fd, Channel* channel_state); - int CloseChannelLocked(int channel_id); + Status<void> CloseChannelLocked(int channel_id); Status<void> ReenableEpollEvent(int fd); Channel* GetChannelState(int channel_id); int GetChannelSocketFd(int channel_id); diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp index 905050092b..3109753dc2 100644 --- a/libs/vr/libpdx_uds/remote_method_tests.cpp +++ b/libs/vr/libpdx_uds/remote_method_tests.cpp @@ -342,87 +342,87 @@ class TestClient : public ClientBase<TestClient> { // Test service that encodes/decodes messages from clients. class TestService : public ServiceBase<TestService> { public: - int HandleMessage(Message& message) override { + Status<void> HandleMessage(Message& message) override { switch (message.GetOp()) { case TestInterface::Add::Opcode: DispatchRemoteMethod<TestInterface::Add>(*this, &TestService::OnAdd, message); - return 0; + return {}; case TestInterface::Foo::Opcode: DispatchRemoteMethod<TestInterface::Foo>(*this, &TestService::OnFoo, message); - return 0; + return {}; case TestInterface::Concatenate::Opcode: DispatchRemoteMethod<TestInterface::Concatenate>( *this, &TestService::OnConcatenate, message); - return 0; + return {}; case TestInterface::SumVector::Opcode: DispatchRemoteMethod<TestInterface::SumVector>( *this, &TestService::OnSumVector, message); - return 0; + return {}; case TestInterface::StringLength::Opcode: DispatchRemoteMethod<TestInterface::StringLength>( *this, &TestService::OnStringLength, message); - return 0; + return {}; case TestInterface::SendTestType::Opcode: DispatchRemoteMethod<TestInterface::SendTestType>( *this, &TestService::OnSendTestType, message); - return 0; + return {}; case TestInterface::SendVector::Opcode: DispatchRemoteMethod<TestInterface::SendVector>( *this, &TestService::OnSendVector, message); - return 0; + return {}; case TestInterface::Rot13::Opcode: DispatchRemoteMethod<TestInterface::Rot13>(*this, &TestService::OnRot13, message); - return 0; + return {}; case TestInterface::NoArgs::Opcode: DispatchRemoteMethod<TestInterface::NoArgs>( *this, &TestService::OnNoArgs, message); - return 0; + return {}; case TestInterface::SendFile::Opcode: DispatchRemoteMethod<TestInterface::SendFile>( *this, &TestService::OnSendFile, message); - return 0; + return {}; case TestInterface::GetFile::Opcode: DispatchRemoteMethod<TestInterface::GetFile>( *this, &TestService::OnGetFile, message); - return 0; + return {}; case TestInterface::GetTestFdType::Opcode: DispatchRemoteMethod<TestInterface::GetTestFdType>( *this, &TestService::OnGetTestFdType, message); - return 0; + return {}; case TestInterface::OpenFiles::Opcode: DispatchRemoteMethod<TestInterface::OpenFiles>( *this, &TestService::OnOpenFiles, message); - return 0; + return {}; case TestInterface::ReadFile::Opcode: DispatchRemoteMethod<TestInterface::ReadFile>( *this, &TestService::OnReadFile, message); - return 0; + return {}; case TestInterface::PushChannel::Opcode: DispatchRemoteMethod<TestInterface::PushChannel>( *this, &TestService::OnPushChannel, message); - return 0; + return {}; case TestInterface::Positive::Opcode: DispatchRemoteMethod<TestInterface::Positive>( *this, &TestService::OnPositive, message); - return 0; + return {}; default: return Service::DefaultHandleMessage(message); @@ -433,7 +433,8 @@ class TestService : public ServiceBase<TestService> { friend BASE; TestService() - : BASE("TestService", Endpoint::Create(TestInterface::kClientPath)) {} + : BASE("TestService", + Endpoint::CreateAndBindSocket(TestInterface::kClientPath)) {} int OnAdd(Message&, int a, int b) { return a + b; } diff --git a/libs/vr/libpdx_uds/service_dispatcher.cpp b/libs/vr/libpdx_uds/service_dispatcher.cpp index fa98f26826..2c52578d1c 100644 --- a/libs/vr/libpdx_uds/service_dispatcher.cpp +++ b/libs/vr/libpdx_uds/service_dispatcher.cpp @@ -30,7 +30,7 @@ ServiceDispatcher::ServiceDispatcher() { return; } - epoll_fd_.Reset(epoll_create(1)); // Size arg is ignored, but must be > 0. + epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC)); if (!epoll_fd_) { ALOGE("Failed to create epoll fd because: %s\n", strerror(errno)); return; diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp index 7bf753d921..6f32867dca 100644 --- a/libs/vr/libpdx_uds/service_endpoint.cpp +++ b/libs/vr/libpdx_uds/service_endpoint.cpp @@ -7,6 +7,9 @@ #include <sys/un.h> #include <algorithm> // std::min +#include <android-base/logging.h> +#include <android-base/strings.h> +#include <cutils/sockets.h> #include <pdx/service.h> #include <uds/channel_manager.h> #include <uds/client_channel_factory.h> @@ -19,6 +22,7 @@ constexpr int kMaxBackLogForSocketListen = 1; using android::pdx::BorrowedChannelHandle; using android::pdx::BorrowedHandle; using android::pdx::ChannelReference; +using android::pdx::ErrorStatus; using android::pdx::FileReference; using android::pdx::LocalChannelHandle; using android::pdx::LocalHandle; @@ -51,14 +55,14 @@ struct MessageState { return true; } - FileReference PushFileHandle(BorrowedHandle handle) { + Status<FileReference> PushFileHandle(BorrowedHandle handle) { if (!handle) return handle.Get(); response.file_descriptors.push_back(std::move(handle)); return response.file_descriptors.size() - 1; } - ChannelReference PushChannelHandle(BorrowedChannelHandle handle) { + Status<ChannelReference> PushChannelHandle(BorrowedChannelHandle handle) { if (!handle) return handle.value(); @@ -70,14 +74,14 @@ struct MessageState { response.channels.push_back(std::move(channel_info)); return response.channels.size() - 1; } else { - return -1; + return ErrorStatus{EINVAL}; } } - ChannelReference PushChannelHandle(BorrowedHandle data_fd, - BorrowedHandle event_fd) { + Status<ChannelReference> PushChannelHandle(BorrowedHandle data_fd, + BorrowedHandle event_fd) { if (!data_fd || !event_fd) - return -1; + return ErrorStatus{EINVAL}; ChannelInfo<BorrowedHandle> channel_info; channel_info.data_fd = std::move(data_fd); channel_info.event_fd = std::move(event_fd); @@ -85,8 +89,8 @@ struct MessageState { return response.channels.size() - 1; } - ssize_t WriteData(const iovec* vector, size_t vector_length) { - ssize_t size = 0; + Status<size_t> WriteData(const iovec* vector, size_t vector_length) { + size_t size = 0; for (size_t i = 0; i < vector_length; i++) { const auto* data = reinterpret_cast<const uint8_t*>(vector[i].iov_base); response_data.insert(response_data.end(), data, data + vector[i].iov_len); @@ -95,9 +99,9 @@ struct MessageState { return size; } - ssize_t ReadData(const iovec* vector, size_t vector_length) { + Status<size_t> ReadData(const iovec* vector, size_t vector_length) { size_t size_remaining = request_data.size() - request_data_read_pos; - ssize_t size = 0; + size_t size = 0; for (size_t i = 0; i < vector_length && size_remaining > 0; i++) { size_t size_to_copy = std::min(size_remaining, vector[i].iov_len); memcpy(vector[i].iov_base, request_data.data() + request_data_read_pos, @@ -123,43 +127,50 @@ namespace android { namespace pdx { namespace uds { -Endpoint::Endpoint(const std::string& endpoint_path, bool blocking) +Endpoint::Endpoint(const std::string& endpoint_path, bool blocking, + bool use_init_socket_fd) : endpoint_path_{ClientChannelFactory::GetEndpointPath(endpoint_path)}, is_blocking_{blocking} { - LocalHandle fd{socket(AF_UNIX, SOCK_STREAM, 0)}; - if (!fd) { - ALOGE("Endpoint::Endpoint: Failed to create socket: %s", strerror(errno)); - return; - } - - sockaddr_un local; - local.sun_family = AF_UNIX; - strncpy(local.sun_path, endpoint_path_.c_str(), sizeof(local.sun_path)); - local.sun_path[sizeof(local.sun_path) - 1] = '\0'; - - unlink(local.sun_path); - if (bind(fd.Get(), (struct sockaddr*)&local, sizeof(local)) == -1) { - ALOGE("Endpoint::Endpoint: bind error: %s", strerror(errno)); - return; - } - if (listen(fd.Get(), kMaxBackLogForSocketListen) == -1) { - ALOGE("Endpoint::Endpoint: listen error: %s", strerror(errno)); - return; + LocalHandle fd; + if (use_init_socket_fd) { + // Cut off the /dev/socket/ prefix from the full socket path and use the + // resulting "name" to retrieve the file descriptor for the socket created + // by the init process. + constexpr char prefix[] = "/dev/socket/"; + CHECK(android::base::StartsWith(endpoint_path_, prefix)) + << "Endpoint::Endpoint: Socket name '" << endpoint_path_ + << "' must begin with '" << prefix << "'"; + std::string socket_name = endpoint_path_.substr(sizeof(prefix) - 1); + fd.Reset(android_get_control_socket(socket_name.c_str())); + CHECK(fd.IsValid()) + << "Endpoint::Endpoint: Unable to obtain the control socket fd for '" + << socket_name << "'"; + fcntl(fd.Get(), F_SETFD, FD_CLOEXEC); + } else { + fd.Reset(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)); + CHECK(fd.IsValid()) << "Endpoint::Endpoint: Failed to create socket: " + << strerror(errno); + + sockaddr_un local; + local.sun_family = AF_UNIX; + strncpy(local.sun_path, endpoint_path_.c_str(), sizeof(local.sun_path)); + local.sun_path[sizeof(local.sun_path) - 1] = '\0'; + + unlink(local.sun_path); + int ret = + bind(fd.Get(), reinterpret_cast<sockaddr*>(&local), sizeof(local)); + CHECK_EQ(ret, 0) << "Endpoint::Endpoint: bind error: " << strerror(errno); } + CHECK_EQ(listen(fd.Get(), kMaxBackLogForSocketListen), 0) + << "Endpoint::Endpoint: listen error: " << strerror(errno); cancel_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - if (!cancel_event_fd_) { - ALOGE("Endpoint::Endpoint: Failed to create event fd: %s\n", - strerror(errno)); - return; - } + CHECK(cancel_event_fd_.IsValid()) + << "Endpoint::Endpoint: Failed to create event fd: " << strerror(errno); - epoll_fd_.Reset(epoll_create(1)); // Size arg is ignored, but must be > 0. - if (!epoll_fd_) { - ALOGE("Endpoint::Endpoint: Failed to create epoll fd: %s\n", - strerror(errno)); - return; - } + epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC)); + CHECK(epoll_fd_.IsValid()) + << "Endpoint::Endpoint: Failed to create epoll fd: " << strerror(errno); epoll_event socket_event; socket_event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT; @@ -169,16 +180,16 @@ Endpoint::Endpoint(const std::string& endpoint_path, bool blocking) cancel_event.events = EPOLLIN; cancel_event.data.fd = cancel_event_fd_.Get(); - if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, fd.Get(), &socket_event) < 0 || - epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, cancel_event_fd_.Get(), - &cancel_event) < 0) { - ALOGE("Endpoint::Endpoint: Failed to add event fd to epoll fd: %s\n", - strerror(errno)); - cancel_event_fd_.Close(); - epoll_fd_.Close(); - } else { - socket_fd_ = std::move(fd); - } + int ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, fd.Get(), &socket_event); + CHECK_EQ(ret, 0) + << "Endpoint::Endpoint: Failed to add socket fd to epoll fd: " + << strerror(errno); + ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, cancel_event_fd_.Get(), + &cancel_event); + CHECK_EQ(ret, 0) + << "Endpoint::Endpoint: Failed to add cancel event fd to epoll fd: " + << strerror(errno); + socket_fd_ = std::move(fd); } void* Endpoint::AllocateMessageState() { return new MessageState; } @@ -190,8 +201,9 @@ void Endpoint::FreeMessageState(void* state) { Status<void> Endpoint::AcceptConnection(Message* message) { sockaddr_un remote; socklen_t addrlen = sizeof(remote); - LocalHandle channel_fd{ - accept(socket_fd_.Get(), reinterpret_cast<sockaddr*>(&remote), &addrlen)}; + LocalHandle channel_fd{accept4(socket_fd_.Get(), + reinterpret_cast<sockaddr*>(&remote), &addrlen, + SOCK_CLOEXEC)}; if (!channel_fd) { ALOGE("Endpoint::AcceptConnection: failed to accept connection: %s", strerror(errno)); @@ -214,18 +226,18 @@ Status<void> Endpoint::AcceptConnection(Message* message) { return status; } -int Endpoint::SetService(Service* service) { +Status<void> Endpoint::SetService(Service* service) { service_ = service; - return 0; + return {}; } -int Endpoint::SetChannel(int channel_id, Channel* channel) { +Status<void> Endpoint::SetChannel(int channel_id, Channel* channel) { std::lock_guard<std::mutex> autolock(channel_mutex_); auto channel_data = channels_.find(channel_id); if (channel_data == channels_.end()) - return -EINVAL; + return ErrorStatus{EINVAL}; channel_data->second.channel_state = channel; - return 0; + return {}; } Status<void> Endpoint::OnNewChannel(LocalHandle channel_fd) { @@ -269,44 +281,46 @@ Status<void> Endpoint::ReenableEpollEvent(int fd) { return {}; } -int Endpoint::CloseChannel(int channel_id) { +Status<void> Endpoint::CloseChannel(int channel_id) { std::lock_guard<std::mutex> autolock(channel_mutex_); return CloseChannelLocked(channel_id); } -int Endpoint::CloseChannelLocked(int channel_id) { +Status<void> Endpoint::CloseChannelLocked(int channel_id) { ALOGD_IF(TRACE, "Endpoint::CloseChannelLocked: channel_id=%d", channel_id); auto channel_data = channels_.find(channel_id); if (channel_data == channels_.end()) - return -EINVAL; + return ErrorStatus{EINVAL}; - int ret = 0; + Status<void> status; epoll_event dummy; // See BUGS in man 2 epoll_ctl. if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, channel_id, &dummy) < 0) { - ret = -errno; + status.SetError(errno); ALOGE( "Endpoint::CloseChannelLocked: Failed to remove channel from endpoint: " "%s\n", strerror(errno)); + } else { + status.SetValue(); } channels_.erase(channel_data); - return ret; + return status; } -int Endpoint::ModifyChannelEvents(int channel_id, int clear_mask, - int set_mask) { +Status<void> Endpoint::ModifyChannelEvents(int channel_id, int clear_mask, + int set_mask) { std::lock_guard<std::mutex> autolock(channel_mutex_); auto search = channels_.find(channel_id); if (search != channels_.end()) { auto& channel_data = search->second; channel_data.event_set.ModifyEvents(clear_mask, set_mask); - return 0; + return {}; } - return -EINVAL; + return ErrorStatus{EINVAL}; } Status<RemoteChannelHandle> Endpoint::PushChannel(Message* message, @@ -314,7 +328,7 @@ Status<RemoteChannelHandle> Endpoint::PushChannel(Message* message, Channel* channel, int* channel_id) { int channel_pair[2] = {}; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel_pair) == -1) { + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, channel_pair) == -1) { ALOGE("Endpoint::PushChannel: Failed to create a socket pair: %s", strerror(errno)); return ErrorStatus(errno); @@ -337,17 +351,19 @@ Status<RemoteChannelHandle> Endpoint::PushChannel(Message* message, *channel_id = local_socket.Get(); auto channel_data = OnNewChannelLocked(std::move(local_socket), channel); if (!channel_data) - return ErrorStatus(channel_data.error()); + return channel_data.error_status(); // Flags are ignored for now. // TODO(xiaohuit): Implement those. auto* state = static_cast<MessageState*>(message->GetState()); - ChannelReference ref = state->PushChannelHandle( + Status<ChannelReference> ref = state->PushChannelHandle( remote_socket.Borrow(), channel_data.get()->event_set.event_fd().Borrow()); + if (!ref) + return ref.error_status(); state->sockets_to_close.push_back(std::move(remote_socket)); - return RemoteChannelHandle{ref}; + return RemoteChannelHandle{ref.get()}; } Status<int> Endpoint::CheckChannel(const Message* /*message*/, @@ -357,13 +373,6 @@ Status<int> Endpoint::CheckChannel(const Message* /*message*/, return ErrorStatus(EFAULT); } -int Endpoint::DefaultHandleMessage(const MessageInfo& /* info */) { - ALOGE( - "Endpoint::CheckChannel: Not implemented! Endpoint DefaultHandleMessage " - "does nothing!"); - return 0; -} - Channel* Endpoint::GetChannelState(int channel_id) { std::lock_guard<std::mutex> autolock(channel_mutex_); auto channel_data = channels_.find(channel_id); @@ -464,7 +473,7 @@ void Endpoint::BuildCloseMessage(int channel_id, Message* message) { *message = Message{info}; } -int Endpoint::MessageReceive(Message* message) { +Status<void> Endpoint::MessageReceive(Message* message) { // Receive at most one event from the epoll set. This should prevent multiple // dispatch threads from attempting to handle messages on the same socket at // the same time. @@ -474,40 +483,36 @@ int Endpoint::MessageReceive(Message* message) { if (count < 0) { ALOGE("Endpoint::MessageReceive: Failed to wait for epoll events: %s\n", strerror(errno)); - return -errno; + return ErrorStatus{errno}; } else if (count == 0) { - return -ETIMEDOUT; + return ErrorStatus{ETIMEDOUT}; } if (event.data.fd == cancel_event_fd_.Get()) { - return -ESHUTDOWN; + return ErrorStatus{ESHUTDOWN}; } if (event.data.fd == socket_fd_.Get()) { auto status = AcceptConnection(message); if (!status) - return -status.error(); - status = ReenableEpollEvent(socket_fd_.Get()); - return status ? 0 : -status.error(); + return status; + return ReenableEpollEvent(socket_fd_.Get()); } int channel_id = event.data.fd; if (event.events & (EPOLLRDHUP | EPOLLHUP)) { BuildCloseMessage(channel_id, message); - return 0; + return {}; } - auto status = ReceiveMessageForChannel(channel_id, message); - if (!status) - return -status.error(); - return 0; + return ReceiveMessageForChannel(channel_id, message); } -int Endpoint::MessageReply(Message* message, int return_code) { +Status<void> Endpoint::MessageReply(Message* message, int return_code) { const int channel_id = message->GetChannelId(); const int channel_socket = GetChannelSocketFd(channel_id); if (channel_socket < 0) - return -EBADF; + return ErrorStatus{EBADF}; auto* state = static_cast<MessageState*>(message->GetState()); switch (message->GetOp()) { @@ -515,12 +520,17 @@ int Endpoint::MessageReply(Message* message, int return_code) { return CloseChannel(channel_id); case opcodes::CHANNEL_OPEN: - if (return_code < 0) + if (return_code < 0) { return CloseChannel(channel_id); - // Reply with the event fd. - return_code = state->PushFileHandle( - BorrowedHandle{GetChannelEventFd(channel_socket)}); - state->response_data.clear(); // Just in case... + } else { + // Reply with the event fd. + auto push_status = state->PushFileHandle( + BorrowedHandle{GetChannelEventFd(channel_socket)}); + state->response_data.clear(); // Just in case... + if (!push_status) + return push_status.error_status(); + return_code = push_status.get(); + } break; } @@ -535,76 +545,82 @@ int Endpoint::MessageReply(Message* message, int return_code) { if (status) status = ReenableEpollEvent(channel_socket); - return status ? 0 : -status.error(); + return status; } -int Endpoint::MessageReplyFd(Message* message, unsigned int push_fd) { +Status<void> Endpoint::MessageReplyFd(Message* message, unsigned int push_fd) { auto* state = static_cast<MessageState*>(message->GetState()); auto ref = state->PushFileHandle(BorrowedHandle{static_cast<int>(push_fd)}); - return MessageReply(message, ref); + if (!ref) + return ref.error_status(); + return MessageReply(message, ref.get()); } -int Endpoint::MessageReplyChannelHandle(Message* message, - const LocalChannelHandle& handle) { +Status<void> Endpoint::MessageReplyChannelHandle( + Message* message, const LocalChannelHandle& handle) { auto* state = static_cast<MessageState*>(message->GetState()); auto ref = state->PushChannelHandle(handle.Borrow()); - return MessageReply(message, ref); + if (!ref) + return ref.error_status(); + return MessageReply(message, ref.get()); } -int Endpoint::MessageReplyChannelHandle(Message* message, - const BorrowedChannelHandle& handle) { +Status<void> Endpoint::MessageReplyChannelHandle( + Message* message, const BorrowedChannelHandle& handle) { auto* state = static_cast<MessageState*>(message->GetState()); auto ref = state->PushChannelHandle(handle.Duplicate()); - return MessageReply(message, ref); + if (!ref) + return ref.error_status(); + return MessageReply(message, ref.get()); } -int Endpoint::MessageReplyChannelHandle(Message* message, - const RemoteChannelHandle& handle) { +Status<void> Endpoint::MessageReplyChannelHandle( + Message* message, const RemoteChannelHandle& handle) { return MessageReply(message, handle.value()); } -ssize_t Endpoint::ReadMessageData(Message* message, const iovec* vector, - size_t vector_length) { +Status<size_t> Endpoint::ReadMessageData(Message* message, const iovec* vector, + size_t vector_length) { auto* state = static_cast<MessageState*>(message->GetState()); return state->ReadData(vector, vector_length); } -ssize_t Endpoint::WriteMessageData(Message* message, const iovec* vector, - size_t vector_length) { +Status<size_t> Endpoint::WriteMessageData(Message* message, const iovec* vector, + size_t vector_length) { auto* state = static_cast<MessageState*>(message->GetState()); return state->WriteData(vector, vector_length); } -FileReference Endpoint::PushFileHandle(Message* message, - const LocalHandle& handle) { +Status<FileReference> Endpoint::PushFileHandle(Message* message, + const LocalHandle& handle) { auto* state = static_cast<MessageState*>(message->GetState()); return state->PushFileHandle(handle.Borrow()); } -FileReference Endpoint::PushFileHandle(Message* message, - const BorrowedHandle& handle) { +Status<FileReference> Endpoint::PushFileHandle(Message* message, + const BorrowedHandle& handle) { auto* state = static_cast<MessageState*>(message->GetState()); return state->PushFileHandle(handle.Duplicate()); } -FileReference Endpoint::PushFileHandle(Message* /*message*/, - const RemoteHandle& handle) { +Status<FileReference> Endpoint::PushFileHandle(Message* /*message*/, + const RemoteHandle& handle) { return handle.Get(); } -ChannelReference Endpoint::PushChannelHandle(Message* message, - const LocalChannelHandle& handle) { +Status<ChannelReference> Endpoint::PushChannelHandle( + Message* message, const LocalChannelHandle& handle) { auto* state = static_cast<MessageState*>(message->GetState()); return state->PushChannelHandle(handle.Borrow()); } -ChannelReference Endpoint::PushChannelHandle( +Status<ChannelReference> Endpoint::PushChannelHandle( Message* message, const BorrowedChannelHandle& handle) { auto* state = static_cast<MessageState*>(message->GetState()); return state->PushChannelHandle(handle.Duplicate()); } -ChannelReference Endpoint::PushChannelHandle( +Status<ChannelReference> Endpoint::PushChannelHandle( Message* /*message*/, const RemoteChannelHandle& handle) { return handle.value(); } @@ -624,8 +640,10 @@ LocalChannelHandle Endpoint::GetChannelHandle(Message* message, return handle; } -int Endpoint::Cancel() { - return (eventfd_write(cancel_event_fd_.Get(), 1) < 0) ? -errno : 0; +Status<void> Endpoint::Cancel() { + if (eventfd_write(cancel_event_fd_.Get(), 1) < 0) + return ErrorStatus{errno}; + return {}; } std::unique_ptr<Endpoint> Endpoint::Create(const std::string& endpoint_path, @@ -634,6 +652,12 @@ std::unique_ptr<Endpoint> Endpoint::Create(const std::string& endpoint_path, return std::unique_ptr<Endpoint>(new Endpoint(endpoint_path, blocking)); } +std::unique_ptr<Endpoint> Endpoint::CreateAndBindSocket( + const std::string& endpoint_path, bool blocking) { + return std::unique_ptr<Endpoint>( + new Endpoint(endpoint_path, blocking, false)); +} + } // namespace uds } // namespace pdx } // namespace android diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp index 9e31e82097..2943239495 100644 --- a/libs/vr/libpdx_uds/service_framework_tests.cpp +++ b/libs/vr/libpdx_uds/service_framework_tests.cpp @@ -119,106 +119,106 @@ class TestService : public ServiceBase<TestService> { } } - int HandleMessage(Message& message) override { + Status<void> HandleMessage(Message& message) override { switch (message.GetOp()) { case TEST_OP_GET_SERVICE_ID: - REPLY_MESSAGE_RETURN(message, service_id_, 0); + REPLY_MESSAGE_RETURN(message, service_id_, {}); // Set the test channel to the TestChannel for the current channel. Other // messages can use this to perform tests. case TEST_OP_SET_TEST_CHANNEL: test_channel_ = message.GetChannel<TestChannel>(); - REPLY_MESSAGE_RETURN(message, 0, 0); + REPLY_MESSAGE_RETURN(message, 0, {}); // Return the channel id for the current channel. case TEST_OP_GET_THIS_CHANNEL_ID: - REPLY_MESSAGE_RETURN(message, message.GetChannelId(), 0); + REPLY_MESSAGE_RETURN(message, message.GetChannelId(), {}); // Return the channel id for the test channel. case TEST_OP_GET_TEST_CHANNEL_ID: if (test_channel_) - REPLY_MESSAGE_RETURN(message, test_channel_->channel_id(), 0); + REPLY_MESSAGE_RETURN(message, test_channel_->channel_id(), {}); else - REPLY_ERROR_RETURN(message, ENOENT, 0); + REPLY_ERROR_RETURN(message, ENOENT, {}); // Test check channel feature. case TEST_OP_CHECK_CHANNEL_ID: { ChannelReference ref = 0; - if (message.Read(&ref, sizeof(ref)) < static_cast<ssize_t>(sizeof(ref))) - REPLY_ERROR_RETURN(message, EIO, 0); + if (!message.ReadAll(&ref, sizeof(ref))) + REPLY_ERROR_RETURN(message, EIO, {}); const Status<int> ret = message.CheckChannel<TestChannel>(ref, nullptr); - REPLY_MESSAGE_RETURN(message, ret, 0); + REPLY_MESSAGE_RETURN(message, ret, {}); } case TEST_OP_CHECK_CHANNEL_OBJECT: { std::shared_ptr<TestChannel> channel; ChannelReference ref = 0; - if (message.Read(&ref, sizeof(ref)) < static_cast<ssize_t>(sizeof(ref))) - REPLY_ERROR_RETURN(message, EIO, 0); + if (!message.ReadAll(&ref, sizeof(ref))) + REPLY_ERROR_RETURN(message, EIO, {}); const Status<int> ret = message.CheckChannel<TestChannel>(ref, &channel); if (!ret) - REPLY_MESSAGE_RETURN(message, ret, 0); + REPLY_MESSAGE_RETURN(message, ret, {}); if (channel != nullptr) - REPLY_MESSAGE_RETURN(message, channel->channel_id(), 0); + REPLY_MESSAGE_RETURN(message, channel->channel_id(), {}); else - REPLY_ERROR_RETURN(message, ENODATA, 0); + REPLY_ERROR_RETURN(message, ENODATA, {}); } case TEST_OP_CHECK_CHANNEL_FROM_OTHER_SERVICE: { ChannelReference ref = 0; - if (message.Read(&ref, sizeof(ref)) < static_cast<ssize_t>(sizeof(ref))) - REPLY_ERROR_RETURN(message, EIO, 0); + if (!message.ReadAll(&ref, sizeof(ref))) + REPLY_ERROR_RETURN(message, EIO, {}); const Status<int> ret = message.CheckChannel<TestChannel>( other_service_.get(), ref, nullptr); - REPLY_MESSAGE_RETURN(message, ret, 0); + REPLY_MESSAGE_RETURN(message, ret, {}); } case TEST_OP_GET_NEW_CHANNEL: { auto channel = std::make_shared<TestChannel>(-1); Status<RemoteChannelHandle> channel_handle = message.PushChannel(0, channel, &channel->channel_id_); - REPLY_MESSAGE_RETURN(message, channel_handle, 0); + REPLY_MESSAGE_RETURN(message, channel_handle, {}); } case TEST_OP_GET_NEW_CHANNEL_FROM_OTHER_SERVICE: { if (!other_service_) - REPLY_ERROR_RETURN(message, EINVAL, 0); + REPLY_ERROR_RETURN(message, EINVAL, {}); auto channel = std::make_shared<TestChannel>(-1); Status<RemoteChannelHandle> channel_handle = message.PushChannel( other_service_.get(), 0, channel, &channel->channel_id_); - REPLY_MESSAGE_RETURN(message, channel_handle, 0); + REPLY_MESSAGE_RETURN(message, channel_handle, {}); } case TEST_OP_GET_THIS_PROCESS_ID: - REPLY_MESSAGE_RETURN(message, message.GetProcessId(), 0); + REPLY_MESSAGE_RETURN(message, message.GetProcessId(), {}); case TEST_OP_GET_THIS_THREAD_ID: - REPLY_MESSAGE_RETURN(message, message.GetThreadId(), 0); + REPLY_MESSAGE_RETURN(message, message.GetThreadId(), {}); case TEST_OP_GET_THIS_EUID: - REPLY_MESSAGE_RETURN(message, message.GetEffectiveUserId(), 0); + REPLY_MESSAGE_RETURN(message, message.GetEffectiveUserId(), {}); case TEST_OP_GET_THIS_EGID: - REPLY_MESSAGE_RETURN(message, message.GetEffectiveGroupId(), 0); + REPLY_MESSAGE_RETURN(message, message.GetEffectiveGroupId(), {}); case TEST_OP_POLLIN_FROM_SERVICE: REPLY_MESSAGE_RETURN(message, message.ModifyChannelEvents(0, EPOLLIN), - 0); + {}); case TEST_OP_SEND_LARGE_DATA_RETURN_SUM: { std::array<int, kLargeDataSize> data_array; - ssize_t size_to_read = data_array.size() * sizeof(int); - ssize_t read = message.Read(data_array.data(), size_to_read); - if (read < size_to_read) - REPLY_ERROR_RETURN(message, EIO, 0); + size_t size_to_read = data_array.size() * sizeof(int); + if (!message.ReadAll(data_array.data(), size_to_read)) { + REPLY_ERROR_RETURN(message, EIO, {}); + } int sum = std::accumulate(data_array.begin(), data_array.end(), 0); - REPLY_MESSAGE_RETURN(message, sum, 0); + REPLY_MESSAGE_RETURN(message, sum, {}); } default: @@ -245,7 +245,7 @@ class TestService : public ServiceBase<TestService> { TestService(const std::string& name, const std::shared_ptr<TestService>& other_service, bool blocking) : BASE(std::string("TestService") + name, - Endpoint::Create(kTestServicePath + name, blocking)), + Endpoint::CreateAndBindSocket(kTestServicePath + name, blocking)), other_service_(other_service), service_id_(service_counter_++) {} @@ -300,7 +300,7 @@ class TestClient : public ClientBase<TestClient> { // Returns the channel id of the channel. int CheckChannelIdArgument(BorrowedChannelHandle channel) { Transaction trans{*this}; - ChannelReference ref = trans.PushChannelHandle(channel); + ChannelReference ref = trans.PushChannelHandle(channel).get(); return ReturnStatusOrError(trans.Send<int>(TEST_OP_CHECK_CHANNEL_ID, &ref, sizeof(ref), nullptr, 0)); } @@ -309,7 +309,7 @@ class TestClient : public ClientBase<TestClient> { // Returns the channel id of the channel exercising the context pointer. int CheckChannelObjectArgument(BorrowedChannelHandle channel) { Transaction trans{*this}; - ChannelReference ref = trans.PushChannelHandle(channel); + ChannelReference ref = trans.PushChannelHandle(channel).get(); return ReturnStatusOrError(trans.Send<int>(TEST_OP_CHECK_CHANNEL_OBJECT, &ref, sizeof(ref), nullptr, 0)); } @@ -318,7 +318,7 @@ class TestClient : public ClientBase<TestClient> { // Returns 0 on success. int CheckChannelFromOtherService(BorrowedChannelHandle channel) { Transaction trans{*this}; - ChannelReference ref = trans.PushChannelHandle(channel); + ChannelReference ref = trans.PushChannelHandle(channel).get(); return ReturnStatusOrError( trans.Send<int>(TEST_OP_CHECK_CHANNEL_FROM_OTHER_SERVICE, &ref, sizeof(ref), nullptr, 0)); diff --git a/libs/vr/libposepredictor/include/polynomial_predictor.h b/libs/vr/libposepredictor/include/polynomial_predictor.h index 762afd3b90..4b8d51bcb2 100644 --- a/libs/vr/libposepredictor/include/polynomial_predictor.h +++ b/libs/vr/libposepredictor/include/polynomial_predictor.h @@ -19,7 +19,7 @@ class PolynomialPosePredictor : public BufferedPredictor { public: PolynomialPosePredictor(real regularization = 1e-9) : BufferedPredictor(TrainingWindow), regularization_(regularization) { - static_assert(PolynomialDegree + 1 >= TrainingWindow, + static_assert(TrainingWindow >= PolynomialDegree + 1, "Underconstrained polynomial regressor"); } diff --git a/libs/vr/libposepredictor/predictor.cpp b/libs/vr/libposepredictor/predictor.cpp index 4d2eafdb2e..beba156378 100644 --- a/libs/vr/libposepredictor/predictor.cpp +++ b/libs/vr/libposepredictor/predictor.cpp @@ -5,7 +5,7 @@ namespace posepredictor { vec3 Predictor::AngularVelocity(const quat& a, const quat& b, real delta_time) { - const auto delta_q = b.inverse() * a; + const auto delta_q = a.inverse() * b; // Check that delta_q.w() == 1, Eigen doesn't respect this convention. If // delta_q.w() == -1, we'll get the opposite velocity. return 2.0 * (delta_q.w() < 0 ? static_cast<vec3>(-delta_q.vec()) : delta_q.vec()) / delta_time; diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp index e07901d0e6..49b6f095b7 100644 --- a/libs/vr/libvrflinger/display_manager_service.cpp +++ b/libs/vr/libvrflinger/display_manager_service.cpp @@ -32,12 +32,12 @@ namespace android { namespace dvr { void DisplayManager::SetNotificationsPending(bool pending) { - int ret = service_->ModifyChannelEvents(channel_id_, pending ? 0 : POLLIN, - pending ? POLLIN : 0); - ALOGE_IF(ret < 0, + auto status = service_->ModifyChannelEvents(channel_id_, pending ? 0 : POLLIN, + pending ? POLLIN : 0); + ALOGE_IF(!status, "DisplayManager::SetNotificationPending: Failed to modify channel " "events: %s", - strerror(-ret)); + status.GetErrorMessage().c_str()); } DisplayManagerService::DisplayManagerService( @@ -68,24 +68,24 @@ void DisplayManagerService::OnChannelClose( display_manager_ = nullptr; } -int DisplayManagerService::HandleMessage(pdx::Message& message) { +pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) { auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel()); switch (message.GetOp()) { case DisplayManagerRPC::GetSurfaceList::Opcode: DispatchRemoteMethod<DisplayManagerRPC::GetSurfaceList>( *this, &DisplayManagerService::OnGetSurfaceList, message); - return 0; + return {}; case DisplayManagerRPC::UpdateSurfaces::Opcode: DispatchRemoteMethod<DisplayManagerRPC::UpdateSurfaces>( *this, &DisplayManagerService::OnUpdateSurfaces, message); - return 0; + return {}; case DisplayManagerRPC::SetupPoseBuffer::Opcode: DispatchRemoteMethod<DisplayManagerRPC::SetupPoseBuffer>( *this, &DisplayManagerService::OnSetupPoseBuffer, message); - return 0; + return {}; default: return Service::DefaultHandleMessage(message); @@ -189,7 +189,7 @@ int DisplayManagerService::OnUpdateSurfaces( } pdx::BorrowedChannelHandle DisplayManagerService::OnSetupPoseBuffer( - pdx::Message& message, size_t extended_region_size, int usage) { + pdx::Message& /*message*/, size_t extended_region_size, int usage) { return display_service_->SetupPoseBuffer(extended_region_size, usage); } diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h index 19098c27c2..80324fd6d4 100644 --- a/libs/vr/libvrflinger/display_manager_service.h +++ b/libs/vr/libvrflinger/display_manager_service.h @@ -42,7 +42,7 @@ class DisplayManagerService : public pdx::ServiceBase<DisplayManagerService> { std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& message) override; void OnChannelClose(pdx::Message& message, const std::shared_ptr<pdx::Channel>& channel) override; - int HandleMessage(pdx::Message& message) override; + pdx::Status<void> HandleMessage(pdx::Message& message) override; private: friend BASE; diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index c0791879a2..3750ea37a4 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -65,39 +65,39 @@ void DisplayService::OnChannelClose(pdx::Message& /*message*/, // First-level dispatch for display service messages. Directly handles messages // that are independent of the display surface (metrics, creation) and routes // surface-specific messages to the per-instance handlers. -int DisplayService::HandleMessage(pdx::Message& message) { +pdx::Status<void> DisplayService::HandleMessage(pdx::Message& message) { auto channel = message.GetChannel<SurfaceChannel>(); switch (message.GetOp()) { case DisplayRPC::GetMetrics::Opcode: DispatchRemoteMethod<DisplayRPC::GetMetrics>( *this, &DisplayService::OnGetMetrics, message); - return 0; + return {}; case DisplayRPC::GetEdsCapture::Opcode: DispatchRemoteMethod<DisplayRPC::GetEdsCapture>( *this, &DisplayService::OnGetEdsCapture, message); - return 0; + return {}; case DisplayRPC::CreateSurface::Opcode: DispatchRemoteMethod<DisplayRPC::CreateSurface>( *this, &DisplayService::OnCreateSurface, message); - return 0; + return {}; case DisplayRPC::SetViewerParams::Opcode: DispatchRemoteMethod<DisplayRPC::SetViewerParams>( *this, &DisplayService::OnSetViewerParams, message); - return 0; + return {}; case DisplayRPC::GetPoseBuffer::Opcode: DispatchRemoteMethod<DisplayRPC::GetPoseBuffer>( *this, &DisplayService::OnGetPoseBuffer, message); - return 0; + return {}; case DisplayRPC::IsVrAppRunning::Opcode: DispatchRemoteMethod<DisplayRPC::IsVrAppRunning>( *this, &DisplayService::IsVrAppRunning, message); - return 0; + return {}; // Direct the surface specific messages to the surface instance. case DisplayRPC::CreateBufferQueue::Opcode: @@ -265,7 +265,7 @@ pdx::LocalChannelHandle DisplayService::OnGetPoseBuffer(pdx::Message& message) { // Calls the message handler for the DisplaySurface associated with this // channel. -int DisplayService::HandleSurfaceMessage(pdx::Message& message) { +pdx::Status<void> DisplayService::HandleSurfaceMessage(pdx::Message& message) { auto surface = std::static_pointer_cast<SurfaceChannel>(message.GetChannel()); ALOGW_IF(!surface, "DisplayService::HandleSurfaceMessage: surface is nullptr!"); @@ -273,7 +273,7 @@ int DisplayService::HandleSurfaceMessage(pdx::Message& message) { if (surface) return surface->HandleMessage(message); else - REPLY_ERROR_RETURN(message, EINVAL, 0); + REPLY_ERROR_RETURN(message, EINVAL, {}); } std::shared_ptr<DisplaySurface> DisplayService::GetDisplaySurface( diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 8e961725ee..da80a84510 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -27,7 +27,7 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { void OnChannelClose(pdx::Message& message, const std::shared_ptr<pdx::Channel>& channel) override; - int HandleMessage(pdx::Message& message) override; + pdx::Status<void> HandleMessage(pdx::Message& message) override; std::shared_ptr<DisplaySurface> GetDisplaySurface(int surface_id) const; std::vector<std::shared_ptr<DisplaySurface>> GetDisplaySurfaces() const; @@ -94,7 +94,7 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { // the display manager should be notified. void NotifyDisplayConfigurationUpdate(); - int HandleSurfaceMessage(pdx::Message& message); + pdx::Status<void> HandleSurfaceMessage(pdx::Message& message); DisplayService(const DisplayService&) = delete; void operator=(const DisplayService&) = delete; diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp index 66e99255e1..a7220feedd 100644 --- a/libs/vr/libvrflinger/display_surface.cpp +++ b/libs/vr/libvrflinger/display_surface.cpp @@ -206,7 +206,7 @@ bool DisplaySurface::IsBufferPosted() { return !acquired_buffers_.IsEmpty(); } -int DisplaySurface::HandleMessage(pdx::Message& message) { +pdx::Status<void> DisplaySurface::HandleMessage(pdx::Message& message) { switch (message.GetOp()) { case DisplayRPC::SetAttributes::Opcode: DispatchRemoteMethod<DisplayRPC::SetAttributes>( @@ -227,7 +227,7 @@ int DisplaySurface::HandleMessage(pdx::Message& message) { return SurfaceChannel::HandleMessage(message); } - return 0; + return {}; } int DisplaySurface::OnClientSetAttributes( @@ -301,7 +301,7 @@ RemoteChannelHandle DisplaySurface::OnCreateVideoMeshSurface( pdx::Message& message) { if (flags_ & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION) { ALOGE( - "DisplaySurface::OnCreateVideoMeshSurface: system distorion is " + "DisplaySurface::OnCreateVideoMeshSurface: system distortion is " "disabled on this display surface, cannot create VideoMeshSurface on " "top of it."); REPLY_ERROR_RETURN(message, EINVAL, {}); @@ -309,22 +309,21 @@ RemoteChannelHandle DisplaySurface::OnCreateVideoMeshSurface( int channel_id; auto status = message.PushChannel(0, nullptr, &channel_id); - if (!status) { ALOGE( "DisplaySurface::OnCreateVideoMeshSurface: failed to push channel: %s", status.GetErrorMessage().c_str()); - REPLY_ERROR_RETURN(message, ENOMEM, {}); + REPLY_ERROR_RETURN(message, status.error(), {}); } auto surface = std::make_shared<VideoMeshSurface>(service(), channel_id); - const int ret = service()->SetChannel(channel_id, surface); - if (ret < 0) { + auto channel_status = service()->SetChannel(channel_id, surface); + if (!channel_status) { ALOGE( "DisplaySurface::OnCreateVideoMeshSurface: failed to set new video " "mesh surface channel: %s", - strerror(-ret)); - REPLY_ERROR_RETURN(message, ENOMEM, {}); + channel_status.GetErrorMessage().c_str()); + REPLY_ERROR_RETURN(message, channel_status.error(), {}); } { diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h index d31a3a9288..2e4cf75d4d 100644 --- a/libs/vr/libvrflinger/display_surface.h +++ b/libs/vr/libvrflinger/display_surface.h @@ -106,7 +106,7 @@ class DisplaySurface : public SurfaceChannel { // Dispatches display surface messages to the appropriate handlers. This // handler runs on the displayd message dispatch thread. - int HandleMessage(pdx::Message& message) override; + pdx::Status<void> HandleMessage(pdx::Message& message) override; // Sets display surface's client-controlled attributes. int OnClientSetAttributes(pdx::Message& message, diff --git a/libs/vr/libvrflinger/screenshot_service.cpp b/libs/vr/libvrflinger/screenshot_service.cpp index fd1c5820e7..d14d58839a 100644 --- a/libs/vr/libvrflinger/screenshot_service.cpp +++ b/libs/vr/libvrflinger/screenshot_service.cpp @@ -19,17 +19,17 @@ namespace dvr { ScreenshotService::~ScreenshotService() { instance_ = nullptr; } -int ScreenshotService::HandleMessage(pdx::Message& message) { +pdx::Status<void> ScreenshotService::HandleMessage(pdx::Message& message) { switch (message.GetOp()) { case DisplayScreenshotRPC::GetFormat::Opcode: DispatchRemoteMethod<DisplayScreenshotRPC::GetFormat>( *this, &ScreenshotService::OnGetFormat, message); - return 0; + return {}; case DisplayScreenshotRPC::TakeScreenshot::Opcode: DispatchRemoteMethod<DisplayScreenshotRPC::TakeScreenshot>( *this, &ScreenshotService::OnTakeScreenshot, message); - return 0; + return {}; default: return Service::HandleMessage(message); diff --git a/libs/vr/libvrflinger/screenshot_service.h b/libs/vr/libvrflinger/screenshot_service.h index ec4c5270de..f59e87224f 100644 --- a/libs/vr/libvrflinger/screenshot_service.h +++ b/libs/vr/libvrflinger/screenshot_service.h @@ -38,7 +38,7 @@ class ScreenshotService : public pdx::ServiceBase<ScreenshotService> { public: ~ScreenshotService(); - int HandleMessage(pdx::Message& message) override; + pdx::Status<void> HandleMessage(pdx::Message& message) override; // Returns true if there is a pending screenshot request. bool IsScreenshotRequestPending() const { diff --git a/libs/vr/libvrflinger/surface_channel.cpp b/libs/vr/libvrflinger/surface_channel.cpp index 8aa220b989..263b382993 100644 --- a/libs/vr/libvrflinger/surface_channel.cpp +++ b/libs/vr/libvrflinger/surface_channel.cpp @@ -7,7 +7,7 @@ using android::pdx::rpc::DispatchRemoteMethod; namespace android { namespace dvr { -int SurfaceChannel::HandleMessage(Message& message) { +pdx::Status<void> SurfaceChannel::HandleMessage(Message& message) { switch (message.GetOp()) { case DisplayRPC::GetMetadataBuffer::Opcode: DispatchRemoteMethod<DisplayRPC::GetMetadataBuffer>( @@ -15,7 +15,7 @@ int SurfaceChannel::HandleMessage(Message& message) { break; } - return 0; + return {}; } BorrowedChannelHandle SurfaceChannel::OnGetMetadataBuffer(Message& message) { diff --git a/libs/vr/libvrflinger/surface_channel.h b/libs/vr/libvrflinger/surface_channel.h index 870e1a4f30..bb6b1c5e92 100644 --- a/libs/vr/libvrflinger/surface_channel.h +++ b/libs/vr/libvrflinger/surface_channel.h @@ -33,7 +33,7 @@ class SurfaceChannel : public pdx::Channel { // Dispatches surface channel messages to the appropriate handlers. This // handler runs on the displayd message dispatch thread. - virtual int HandleMessage(pdx::Message& message); + virtual pdx::Status<void> HandleMessage(pdx::Message& message); protected: // Contains the surface metadata. diff --git a/libs/vr/libvrflinger/video_mesh_surface.cpp b/libs/vr/libvrflinger/video_mesh_surface.cpp index a961a3db51..d915a4a382 100644 --- a/libs/vr/libvrflinger/video_mesh_surface.cpp +++ b/libs/vr/libvrflinger/video_mesh_surface.cpp @@ -14,7 +14,7 @@ VideoMeshSurface::VideoMeshSurface(DisplayService* service, int surface_id) VideoMeshSurface::~VideoMeshSurface() {} -int VideoMeshSurface::HandleMessage(Message& message) { +pdx::Status<void> VideoMeshSurface::HandleMessage(Message& message) { ATRACE_NAME("VideoMeshSurface::HandleMessage"); switch (message.GetOp()) { @@ -27,7 +27,7 @@ int VideoMeshSurface::HandleMessage(Message& message) { return SurfaceChannel::HandleMessage(message); } - return 0; + return {}; } std::shared_ptr<ConsumerQueue> VideoMeshSurface::GetConsumerQueue() { diff --git a/libs/vr/libvrflinger/video_mesh_surface.h b/libs/vr/libvrflinger/video_mesh_surface.h index 1370793acf..2c9f3e8767 100644 --- a/libs/vr/libvrflinger/video_mesh_surface.h +++ b/libs/vr/libvrflinger/video_mesh_surface.h @@ -12,7 +12,7 @@ class DisplayService; // VideoMeshSurface takes three inputs: 1) buffers filled by Android system // components (e.g. MediaCodec or camera stack) other than applications' GL -// context; 2) a 3D mesh choosen by application to define the shape of the +// context; 2) a 3D mesh chosen by application to define the shape of the // surface; 3) a transformation matrix from application to define the rotation, // position, and scaling of the video surface. class VideoMeshSurface : public SurfaceChannel { @@ -33,7 +33,7 @@ class VideoMeshSurface : public SurfaceChannel { } } - int HandleMessage(Message& message) override; + pdx::Status<void> HandleMessage(Message& message) override; std::shared_ptr<ConsumerQueue> GetConsumerQueue(); diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp index 48fa2c27af..612b9b2ba1 100644 --- a/libs/vr/libvrflinger/vsync_service.cpp +++ b/libs/vr/libvrflinger/vsync_service.cpp @@ -107,26 +107,26 @@ void VSyncService::UpdateClients() { } } -int VSyncService::HandleMessage(pdx::Message& message) { +pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) { switch (message.GetOp()) { case DisplayVSyncRPC::Wait::Opcode: AddWaiter(message); - return 0; + return {}; case DisplayVSyncRPC::GetLastTimestamp::Opcode: DispatchRemoteMethod<DisplayVSyncRPC::GetLastTimestamp>( *this, &VSyncService::OnGetLastTimestamp, message); - return 0; + return {}; case DisplayVSyncRPC::GetSchedInfo::Opcode: DispatchRemoteMethod<DisplayVSyncRPC::GetSchedInfo>( *this, &VSyncService::OnGetSchedInfo, message); - return 0; + return {}; case DisplayVSyncRPC::Acknowledge::Opcode: DispatchRemoteMethod<DisplayVSyncRPC::Acknowledge>( *this, &VSyncService::OnAcknowledge, message); - return 0; + return {}; default: return Service::HandleMessage(message); diff --git a/libs/vr/libvrflinger/vsync_service.h b/libs/vr/libvrflinger/vsync_service.h index ba1d4df60b..1c86d4272d 100644 --- a/libs/vr/libvrflinger/vsync_service.h +++ b/libs/vr/libvrflinger/vsync_service.h @@ -56,7 +56,7 @@ class VSyncService : public pdx::ServiceBase<VSyncService> { public: ~VSyncService() override; - int HandleMessage(pdx::Message& message) override; + pdx::Status<void> HandleMessage(pdx::Message& message) override; std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& message) override; void OnChannelClose(pdx::Message& message, diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp index 6d48f18385..d59182efe7 100644 --- a/libs/vr/libvrsensor/Android.bp +++ b/libs/vr/libvrsensor/Android.bp @@ -15,6 +15,7 @@ sourceFiles = [ "pose_client.cpp", "sensor_client.cpp", + "latency_model.cpp", ] includeFiles = [ diff --git a/libs/vr/libvrsensor/include/private/dvr/latency_model.h b/libs/vr/libvrsensor/include/private/dvr/latency_model.h new file mode 100644 index 0000000000..1bb3c4fdd8 --- /dev/null +++ b/libs/vr/libvrsensor/include/private/dvr/latency_model.h @@ -0,0 +1,31 @@ +#ifndef ANDROID_DVR_LATENCY_MODEL_H_ +#define ANDROID_DVR_LATENCY_MODEL_H_ + +#include <vector> + +namespace android { +namespace dvr { + +// This class holds a rolling average of the sensor latency. +class LatencyModel { + public: + LatencyModel(size_t window_size, double weight_mass_in_window); + ~LatencyModel() = default; + + void AddLatency(int64_t latency_ns); + int64_t CurrentLatencyEstimate() const { + return static_cast<int64_t>(rolling_average_); + } + + private: + // The rolling average of the latencies. + double rolling_average_ = 0; + + // The alpha parameter for an exponential moving average. + double alpha_; +}; + +} // namespace dvr +} // namespace android + +#endif // ANDROID_DVR_LATENCY_MODEL_H_ diff --git a/libs/vr/libvrsensor/latency_model.cpp b/libs/vr/libvrsensor/latency_model.cpp new file mode 100644 index 0000000000..8233889383 --- /dev/null +++ b/libs/vr/libvrsensor/latency_model.cpp @@ -0,0 +1,33 @@ +#include <private/dvr/latency_model.h> + +#include <cmath> + +namespace android { +namespace dvr { + +LatencyModel::LatencyModel(size_t window_size, double weight_mass_in_window) { + // Compute an alpha so the weight of the last window_size measurements is + // weight_mass_in_window of the total weights. + + // The weight in a series of k measurements: + // alpha + (1 + (1 - alpha) + (1 - alpha)^2 + ... (1 - alpha)^k-1) + // = alpha x (1 - (1 - alpha) ^ k) / alpha + // = 1 - (1 - alpha) ^ k + // weight_mass_in_window = 1 - (1 - alpha) ^ k / lim_k->inf (1 - alpha) ^ k + // weight_mass_in_window = 1 - (1 - alpha) ^ k / 1 + // 1 - weight_mass_in_window = (1 - alpha) ^ k + // log(1 - weight_mass_in_window) = k * log(1 - alpha) + // 10 ^ (log(1 - weight_mass_in_window) / k) = 1 - alpha + // alpha = 1 - 10 ^ (log(1 - weight_mass_in_window) / k) + // alpha = 1 - 10 ^ (log(1 - weight_mass_in_window) / window_size) + + alpha_ = 1 - std::pow(10.0, std::log10(1 - weight_mass_in_window) / + static_cast<double>(window_size)); +} + +void LatencyModel::AddLatency(int64_t latency_ns) { + rolling_average_ = latency_ns * alpha_ + rolling_average_ * (1 - alpha_); +} + +} // namespace dvr +} // namespace android diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index 7ed34be89a..623878062b 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -114,7 +114,7 @@ void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) { // call the implementation's glGetString(GL_EXTENSIONS) const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS); gl_extensions = exts; - if (gl_extensions.find("GL_EXT_debug_marker") != std::string::npos) { + if (gl_extensions.find("GL_EXT_debug_marker") == std::string::npos) { gl_extensions.insert(0, "GL_EXT_debug_marker "); } diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp index f00c297c72..748dafcf62 100644 --- a/services/sensorservice/hidl/Android.bp +++ b/services/sensorservice/hidl/Android.bp @@ -1,6 +1,7 @@ cc_library_shared { name: "libsensorservicehidl", srcs: [ + "EventQueue.cpp", "DirectReportChannel.cpp", "SensorManager.cpp", "utils.cpp", @@ -19,6 +20,9 @@ cc_library_shared { "android.hardware.sensors@1.0", "android.hidl.base@1.0", ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + ], export_include_dirs: [ "include/" ], diff --git a/services/sensorservice/hidl/DirectReportChannel.cpp b/services/sensorservice/hidl/DirectReportChannel.cpp index 9caba47912..773ce8cd0a 100644 --- a/services/sensorservice/hidl/DirectReportChannel.cpp +++ b/services/sensorservice/hidl/DirectReportChannel.cpp @@ -32,8 +32,9 @@ DirectReportChannel::~DirectReportChannel() { // Methods from ::android::frameworks::sensorservice::V1_0::IDirectReportChannel follow. Return<Result> DirectReportChannel::configure(int32_t sensorHandle, RateLevel rate) { - return convertResult(mManager.configureDirectChannel(mId, - static_cast<int>(sensorHandle), static_cast<int>(rate))); + int token = mManager.configureDirectChannel(mId, + static_cast<int>(sensorHandle), static_cast<int>(rate)); + return token <= 0 ? convertResult(token) : Result::OK; } diff --git a/services/sensorservice/hidl/DirectReportChannel.h b/services/sensorservice/hidl/DirectReportChannel.h index f4cd4e77d3..913494427d 100644 --- a/services/sensorservice/hidl/DirectReportChannel.h +++ b/services/sensorservice/hidl/DirectReportChannel.h @@ -41,7 +41,7 @@ using ::android::hardware::Return; using ::android::hardware::Void; using ::android::sp; -struct DirectReportChannel : public IDirectReportChannel { +struct DirectReportChannel final : public IDirectReportChannel { DirectReportChannel(::android::SensorManager& manager, int channelId); ~DirectReportChannel(); diff --git a/services/sensorservice/hidl/EventQueue.cpp b/services/sensorservice/hidl/EventQueue.cpp new file mode 100644 index 0000000000..86d365c0c2 --- /dev/null +++ b/services/sensorservice/hidl/EventQueue.cpp @@ -0,0 +1,84 @@ +/* + * 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 "EventQueue.h" +#include "utils.h" + +#include <utils/Looper.h> + +namespace android { +namespace frameworks { +namespace sensorservice { +namespace V1_0 { +namespace implementation { + +class EventQueueLooperCallback : public ::android::LooperCallback { +public: + EventQueueLooperCallback(sp<EventQueue> queue, sp<IEventQueueCallback> callback) + : mQueue(queue), mCallback(callback) { + } + + int handleEvent(__unused int fd, __unused int events, __unused void* data) { + + ASensorEvent event; + ssize_t actual; + const sp<::android::SensorEventQueue>& internalQueue = mQueue->mInternalQueue; + + while ((actual = internalQueue->read(&event, 1 /* count */)) > 0) { + internalQueue->sendAck(&event, actual); + mCallback->onEvent(convertEvent(event)); + } + + return 1; // continue to receive callbacks + } + +private: + sp<EventQueue> mQueue; + sp<IEventQueueCallback> mCallback; +}; + +EventQueue::EventQueue( + sp<IEventQueueCallback> callback, + sp<::android::Looper> looper, + sp<::android::SensorEventQueue> internalQueue) + : mLooper(looper), + mInternalQueue(internalQueue) { + + mLooper->addFd(mInternalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT, + new EventQueueLooperCallback(this, callback), NULL /* data */); +} + +EventQueue::~EventQueue() { + mLooper->removeFd(mInternalQueue->getFd()); +} + +// Methods from ::android::frameworks::sensorservice::V1_0::IEventQueue follow. +Return<Result> EventQueue::enableSensor(int32_t sensorHandle, int32_t samplingPeriodUs, + int64_t maxBatchReportLatencyUs) { + // TODO implement + return convertResult(mInternalQueue->enableSensor(sensorHandle, samplingPeriodUs, + maxBatchReportLatencyUs, 0 /* reserved flags */)); +} + +Return<Result> EventQueue::disableSensor(int32_t sensorHandle) { + return convertResult(mInternalQueue->disableSensor(sensorHandle)); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace sensorservice +} // namespace frameworks +} // namespace android diff --git a/services/sensorservice/hidl/EventQueue.h b/services/sensorservice/hidl/EventQueue.h new file mode 100644 index 0000000000..87c614b0dc --- /dev/null +++ b/services/sensorservice/hidl/EventQueue.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_EVENTQUEUE_H +#define ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_EVENTQUEUE_H + +#include "SensorManager.h" + +#include <android/frameworks/sensorservice/1.0/IEventQueue.h> +#include <android/frameworks/sensorservice/1.0/IEventQueueCallback.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <sensor/SensorManager.h> + +namespace android { +namespace frameworks { +namespace sensorservice { +namespace V1_0 { +namespace implementation { + +using ::android::frameworks::sensorservice::V1_0::IEventQueue; +using ::android::frameworks::sensorservice::V1_0::IEventQueueCallback; +using ::android::frameworks::sensorservice::V1_0::Result; +using ::android::hardware::Return; +using ::android::sp; + +struct EventQueue final : public IEventQueue { + EventQueue( + sp<IEventQueueCallback> callback, + sp<::android::Looper> looper, + sp<::android::SensorEventQueue> internalQueue); + ~EventQueue(); + + // Methods from ::android::frameworks::sensorservice::V1_0::IEventQueue follow. + Return<Result> enableSensor(int32_t sensorHandle, int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs) override; + Return<Result> disableSensor(int32_t sensorHandle) override; + +private: + friend class EventQueueLooperCallback; + sp<::android::Looper> mLooper; + sp<::android::SensorEventQueue> mInternalQueue; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace sensorservice +} // namespace frameworks +} // namespace android + +#endif // ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_EVENTQUEUE_H diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp index 37e53dc9fc..0743fc39d6 100644 --- a/services/sensorservice/hidl/SensorManager.cpp +++ b/services/sensorservice/hidl/SensorManager.cpp @@ -20,10 +20,14 @@ #endif #include <android-base/logging.h> -#include "DirectReportChannel.h" #include "SensorManager.h" + +#include "EventQueue.h" +#include "DirectReportChannel.h" #include "utils.h" +#include <thread> + namespace android { namespace frameworks { namespace sensorservice { @@ -31,19 +35,28 @@ namespace V1_0 { namespace implementation { using ::android::hardware::sensors::V1_0::SensorInfo; +using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset; using ::android::hardware::hidl_vec; using ::android::hardware::Void; using ::android::sp; SensorManager::SensorManager() - : mManager{::android::SensorManager::getInstanceForPackage( + : mInternalManager{::android::SensorManager::getInstanceForPackage( String16(ISensorManager::descriptor))} { } +SensorManager::~SensorManager() { + // Stops pollAll inside the thread. + std::unique_lock<std::mutex> lock(mLooperMutex); + if (mLooper != nullptr) { + mLooper->wake(); + } +} + // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow. Return<void> SensorManager::getSensorList(getSensorList_cb _hidl_cb) { ::android::Sensor const* const* list; - ssize_t count = mManager.getSensorList(&list); + ssize_t count = mInternalManager.getSensorList(&list); if (count < 0 || !list) { LOG(ERROR) << "::android::SensorManager::getSensorList encounters " << count; _hidl_cb({}, Result::UNKNOWN_ERROR); @@ -59,7 +72,7 @@ Return<void> SensorManager::getSensorList(getSensorList_cb _hidl_cb) { } Return<void> SensorManager::getDefaultSensor(SensorType type, getDefaultSensor_cb _hidl_cb) { - ::android::Sensor const* sensor = mManager.getDefaultSensor(static_cast<int>(type)); + ::android::Sensor const* sensor = mInternalManager.getDefaultSensor(static_cast<int>(type)); if (!sensor) { _hidl_cb({}, Result::NOT_EXIST); return Void(); @@ -90,12 +103,12 @@ void createDirectChannel(::android::SensorManager& manager, size_t size, int typ Return<void> SensorManager::createAshmemDirectChannel( const hidl_memory& mem, uint64_t size, createAshmemDirectChannel_cb _hidl_cb) { - if (size > mem.size()) { + if (size > mem.size() || size < (uint64_t)SensorsEventFormatOffset::TOTAL_LENGTH) { _hidl_cb(nullptr, Result::BAD_VALUE); return Void(); } - createDirectChannel(mManager, size, SENSOR_DIRECT_MEM_TYPE_ASHMEM, + createDirectChannel(mInternalManager, size, SENSOR_DIRECT_MEM_TYPE_ASHMEM, mem.handle(), _hidl_cb); return Void(); @@ -105,16 +118,53 @@ Return<void> SensorManager::createGrallocDirectChannel( const hidl_handle& buffer, uint64_t size, createGrallocDirectChannel_cb _hidl_cb) { - createDirectChannel(mManager, size, SENSOR_DIRECT_MEM_TYPE_GRALLOC, + createDirectChannel(mInternalManager, size, SENSOR_DIRECT_MEM_TYPE_GRALLOC, buffer.getNativeHandle(), _hidl_cb); return Void(); } +/* One global looper for all event queues created from this SensorManager. */ +sp<::android::Looper> SensorManager::getLooper() { + std::unique_lock<std::mutex> lock(mLooperMutex); + if (mLooper == nullptr) { + std::condition_variable looperSet; + + std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet] { + std::unique_lock<std::mutex> lock(mutex); + looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */); + lock.unlock(); + + looperSet.notify_one(); + int pollResult = looper->pollAll(-1 /* timeout */); + if (pollResult != ALOOPER_POLL_WAKE) { + LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult; + } + LOG(INFO) << "Looper thread is terminated."; + }}.detach(); + looperSet.wait(lock, [this]{ return this->mLooper != nullptr; }); + } + return mLooper; +} + Return<void> SensorManager::createEventQueue( - __unused const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb) { - // TODO(b/35219747) Implement this - _hidl_cb(nullptr, Result::UNKNOWN_ERROR); + const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb) { + if (callback == nullptr) { + _hidl_cb(nullptr, Result::BAD_VALUE); + return Void(); + } + + sp<::android::Looper> looper = getLooper(); + sp<::android::SensorEventQueue> internalQueue = mInternalManager.createEventQueue(); + if (internalQueue == nullptr) { + LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr."; + _hidl_cb(nullptr, Result::UNKNOWN_ERROR); + return Void(); + } + + sp<IEventQueue> queue = new EventQueue(callback, looper, internalQueue); + _hidl_cb(queue, Result::OK); + return Void(); } diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h index 0b026c9dcd..a2372df3d1 100644 --- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h +++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h @@ -17,11 +17,14 @@ #ifndef ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_SENSORMANAGER_H #define ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_SENSORMANAGER_H +#include <mutex> + #include <android/frameworks/sensorservice/1.0/ISensorManager.h> #include <android/frameworks/sensorservice/1.0/types.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> #include <sensor/SensorManager.h> +#include <utils/Looper.h> namespace android { namespace frameworks { @@ -34,9 +37,10 @@ using ::android::hardware::hidl_handle; using ::android::hardware::hidl_memory; using ::android::hardware::Return; -struct SensorManager : public ISensorManager { +struct SensorManager final : public ISensorManager { SensorManager(); + ~SensorManager(); // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow. Return<void> getSensorList(getSensorList_cb _hidl_cb) override; @@ -44,9 +48,13 @@ struct SensorManager : public ISensorManager { Return<void> createAshmemDirectChannel(const hidl_memory& mem, uint64_t size, createAshmemDirectChannel_cb _hidl_cb) override; Return<void> createGrallocDirectChannel(const hidl_handle& buffer, uint64_t size, createGrallocDirectChannel_cb _hidl_cb) override; Return<void> createEventQueue(const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb); + private: - ::android::SensorManager& mManager; + sp<::android::Looper> getLooper(); + ::android::SensorManager& mInternalManager; + std::mutex mLooperMutex; + sp<::android::Looper> mLooper; }; } // namespace implementation diff --git a/services/sensorservice/hidl/utils.cpp b/services/sensorservice/hidl/utils.cpp index 4e027412a7..b5405254d9 100644 --- a/services/sensorservice/hidl/utils.cpp +++ b/services/sensorservice/hidl/utils.cpp @@ -16,6 +16,8 @@ #include "utils.h" +#include <sensors/convert.h> + namespace android { namespace frameworks { namespace sensorservice { @@ -26,7 +28,7 @@ using ::android::Sensor; using ::android::hardware::hidl_string; using ::android::hardware::sensors::V1_0::SensorInfo; -SensorInfo convertSensor(const Sensor &src) { +SensorInfo convertSensor(const Sensor& src) { SensorInfo dst; const String8& name = src.getName(); const String8& vendor = src.getVendor(); @@ -36,7 +38,7 @@ SensorInfo convertSensor(const Sensor &src) { dst.sensorHandle = src.getHandle(); dst.type = static_cast<::android::hardware::sensors::V1_0::SensorType>( src.getType()); - // FIXME maxRange uses maxValue because ::android::Sensor wraps the + // maxRange uses maxValue because ::android::Sensor wraps the // internal sensor_t in this way. dst.maxRange = src.getMaxValue(); dst.resolution = src.getResolution(); @@ -70,6 +72,13 @@ Result convertResult(status_t status) { } } +::android::hardware::sensors::V1_0::Event convertEvent(const ::ASensorEvent& src) { + ::android::hardware::sensors::V1_0::Event dst; + ::android::hardware::sensors::V1_0::implementation::convertFromSensorEvent( + reinterpret_cast<const sensors_event_t&>(src), &dst); + return dst; +} + } // namespace implementation } // namespace V1_0 } // namespace sensorservice diff --git a/services/sensorservice/hidl/utils.h b/services/sensorservice/hidl/utils.h index 0606e697b0..b350928187 100644 --- a/services/sensorservice/hidl/utils.h +++ b/services/sensorservice/hidl/utils.h @@ -30,6 +30,8 @@ namespace implementation { ::android::hardware::sensors::V1_0::SensorInfo convertSensor(const ::android::Sensor &src); Result convertResult(status_t status); +::android::hardware::sensors::V1_0::Event convertEvent(const ::ASensorEvent &event); + } // namespace implementation } // namespace V1_0 } // namespace sensorservice diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 647a4c0286..ebf72bcc87 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -66,9 +66,6 @@ endif LOCAL_CFLAGS += -fvisibility=hidden -Werror=format -LOCAL_HEADER_LIBRARIES := \ - android.hardware.configstore-utils - LOCAL_STATIC_LIBRARIES := \ libhwcomposer-command-buffer \ libtrace_proto \ @@ -81,6 +78,7 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.graphics.allocator@2.0 \ android.hardware.graphics.composer@2.1 \ android.hardware.configstore@1.0 \ + android.hardware.configstore-utils \ libcutils \ liblog \ libdl \ diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 9ddae2b4dc..e9a251305f 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -210,15 +210,5 @@ status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outSt return NO_ERROR; } -status_t Client::getTransformToDisplayInverse(const sp<IBinder>& handle, - bool* outTransformToDisplayInverse) const { - sp<Layer> layer = getLayerUser(handle); - if (layer == NULL) { - return NAME_NOT_FOUND; - } - *outTransformToDisplayInverse = layer->getTransformToDisplayInverse(); - return NO_ERROR; -} - // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h index 141f6c767e..b5f98b8a6f 100644 --- a/services/surfaceflinger/Client.h +++ b/services/surfaceflinger/Client.h @@ -67,8 +67,6 @@ private: virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const; virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const; - virtual status_t getTransformToDisplayInverse( - const sp<IBinder>& handle, bool* outTransformToDisplayInverse) const; virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index ac7e08393a..16d8160f79 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -505,7 +505,7 @@ FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { // which means using the inverse of the current transform set on the // SurfaceFlingerConsumer. uint32_t invTransform = mCurrentTransform; - if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { + if (getTransformToDisplayInverse()) { /* * the code below applies the primary display's inverse transform to the * buffer @@ -713,7 +713,7 @@ void Layer::setGeometry( const Transform bufferOrientation(mCurrentTransform); Transform transform(tr * t * bufferOrientation); - if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { + if (getTransformToDisplayInverse()) { /* * the code below applies the primary display's inverse transform to the * buffer @@ -725,8 +725,14 @@ void Layer::setGeometry( invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H; } - // and apply to the current transform - transform = Transform(invTransform) * transform; + + /* + * Here we cancel out the orientation component of the WM transform. + * The scaling and translate components are already included in our bounds + * computation so it's enough to just omit it in the composition. + * See comment in onDraw with ref to b/36727915 for why. + */ + transform = Transform(invTransform) * tr * bufferOrientation; } // this gives us only the "orientation" component of the transform @@ -987,6 +993,24 @@ void Layer::draw(const sp<const DisplayDevice>& hw) const { onDraw(hw, Region(hw->bounds()), false); } +static constexpr mat4 inverseOrientation(uint32_t transform) { + const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1); + const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1); + const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1); + mat4 tr; + + if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + tr = tr * rot90; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { + tr = tr * flipH; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { + tr = tr * flipV; + } + return inverse(tr); +} + void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, bool useIdentityTransform) const { @@ -1041,30 +1065,29 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering); mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix); - if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { + if (getTransformToDisplayInverse()) { /* * the code below applies the primary display's inverse transform to * the texture transform */ - - // create a 4x4 transform matrix from the display transform flags - const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1); - const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1); - const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1); - - mat4 tr; uint32_t transform = DisplayDevice::getPrimaryDisplayOrientationTransform(); - if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) - tr = tr * rot90; - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) - tr = tr * flipH; - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) - tr = tr * flipV; - - // calculate the inverse - tr = inverse(tr); + mat4 tr = inverseOrientation(transform); + + /** + * TODO(b/36727915): This is basically a hack. + * + * Ensure that regardless of the parent transformation, + * this buffer is always transformed from native display + * orientation to display orientation. For example, in the case + * of a camera where the buffer remains in native orientation, + * we want the pixels to always be upright. + */ + if (getParent() != nullptr) { + const auto parentTransform = getParent()->getTransform(); + tr = tr * inverseOrientation(parentTransform.getOrientation()); + } // and finally apply it to the original texture matrix const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr); diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index e3dbecc55d..75642699c3 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -382,6 +382,7 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, attribs[EGL_RED_SIZE] = 8; attribs[EGL_GREEN_SIZE] = 8; attribs[EGL_BLUE_SIZE] = 8; + attribs[EGL_ALPHA_SIZE] = 8; wantedAttribute = EGL_NONE; wantedAttributeValue = EGL_NONE; } else { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f82b363cb5..834c1c4b99 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1903,7 +1903,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // etc.) but no internal state (i.e. a DisplayDevice). if (state.surface != NULL) { - if (mUseHwcVirtualDisplays) { + // Allow VR composer to use virtual displays. + if (mUseHwcVirtualDisplays || mHwc == mVrHwc) { int width = 0; int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); @@ -2839,15 +2840,17 @@ status_t SurfaceFlinger::createLayer( sp<Layer> layer; + String8 uniqueName = getUniqueLayerName(name); + switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceNormal: result = createNormalLayer(client, - name, w, h, flags, format, + uniqueName, w, h, flags, format, handle, gbp, &layer); break; case ISurfaceComposerClient::eFXSurfaceDim: result = createDimLayer(client, - name, w, h, flags, + uniqueName, w, h, flags, handle, gbp, &layer); break; default: @@ -2871,6 +2874,30 @@ status_t SurfaceFlinger::createLayer( return result; } +String8 SurfaceFlinger::getUniqueLayerName(const String8& name) +{ + bool matchFound = true; + uint32_t dupeCounter = 0; + + // Tack on our counter whether there is a hit or not, so everyone gets a tag + String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str()); + + // Loop over layers until we're sure there is no matching name + while (matchFound) { + matchFound = false; + mDrawingState.traverseInZOrder([&](Layer* layer) { + if (layer->getName() == uniqueName) { + matchFound = true; + uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str()); + } + }); + } + + ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str()); + + return uniqueName; +} + status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 581bbfdede..4ecbddd9a2 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -364,6 +364,8 @@ private: uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer); + String8 getUniqueLayerName(const String8& name); + // called in response to the window-manager calling // ISurfaceComposerClient::destroySurface() status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle); diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index c26847f927..a6c0b9c686 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -2637,15 +2637,17 @@ status_t SurfaceFlinger::createLayer( sp<Layer> layer; + String8 uniqueName = getUniqueLayerName(name); + switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceNormal: result = createNormalLayer(client, - name, w, h, flags, format, + uniqueName, w, h, flags, format, handle, gbp, &layer); break; case ISurfaceComposerClient::eFXSurfaceDim: result = createDimLayer(client, - name, w, h, flags, + uniqueName, w, h, flags, handle, gbp, &layer); break; default: @@ -2669,6 +2671,30 @@ status_t SurfaceFlinger::createLayer( return result; } +String8 SurfaceFlinger::getUniqueLayerName(const String8& name) +{ + bool matchFound = true; + uint32_t dupeCounter = 0; + + // Tack on our counter whether there is a hit or not, so everyone gets a tag + String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str()); + + // Loop over layers until we're sure there is no matching name + while (matchFound) { + matchFound = false; + mDrawingState.traverseInZOrder([&](Layer* layer) { + if (layer->getName() == uniqueName) { + matchFound = true; + uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str()); + } + }); + } + + ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str()); + + return uniqueName; +} + status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc index 435aa0cce7..41b6225302 100644 --- a/services/surfaceflinger/surfaceflinger.rc +++ b/services/surfaceflinger/surfaceflinger.rc @@ -1,6 +1,10 @@ service surfaceflinger /system/bin/surfaceflinger - class core + class core animation user system group graphics drmrpc readproc onrestart restart zygote writepid /dev/stune/foreground/tasks + socket pdx/system/vr/display/client stream 0666 system graphics + socket pdx/system/vr/display/manager stream 0660 system graphics + socket pdx/system/vr/display/screenshot stream 0660 system graphics + socket pdx/system/vr/display/vsync stream 0666 system graphics diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk index c1a0b6f1f4..b3d777e207 100644 --- a/services/vr/bufferhubd/Android.mk +++ b/services/vr/bufferhubd/Android.mk @@ -30,7 +30,6 @@ staticLibraries := \ sharedLibraries := \ libbase \ libcutils \ - libhardware \ liblog \ libsync \ libutils \ diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp index 80efcf8452..de4950ea81 100644 --- a/services/vr/bufferhubd/buffer_hub.cpp +++ b/services/vr/bufferhubd/buffer_hub.cpp @@ -189,7 +189,7 @@ void BufferHubService::HandleImpulse(Message& message) { channel->HandleImpulse(message); } -int BufferHubService::HandleMessage(Message& message) { +pdx::Status<void> BufferHubService::HandleMessage(Message& message) { ATRACE_NAME("BufferHubService::HandleMessage"); auto channel = message.GetChannel<BufferHubChannel>(); @@ -207,22 +207,22 @@ int BufferHubService::HandleMessage(Message& message) { case BufferHubRPC::CreateBuffer::Opcode: DispatchRemoteMethod<BufferHubRPC::CreateBuffer>( *this, &BufferHubService::OnCreateBuffer, message); - return 0; + return {}; case BufferHubRPC::CreatePersistentBuffer::Opcode: DispatchRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( *this, &BufferHubService::OnCreatePersistentBuffer, message); - return 0; + return {}; case BufferHubRPC::GetPersistentBuffer::Opcode: DispatchRemoteMethod<BufferHubRPC::GetPersistentBuffer>( *this, &BufferHubService::OnGetPersistentBuffer, message); - return 0; + return {}; case BufferHubRPC::CreateProducerQueue::Opcode: DispatchRemoteMethod<BufferHubRPC::CreateProducerQueue>( *this, &BufferHubService::OnCreateProducerQueue, message); - return 0; + return {}; default: return DefaultHandleMessage(message); @@ -438,11 +438,11 @@ void BufferHubChannel::SignalAvailable() { "BufferHubChannel::SignalAvailable: channel_id=%d buffer_id=%d", channel_id(), buffer_id()); if (!IsDetached()) { - const int ret = service_->ModifyChannelEvents(channel_id_, 0, POLLIN); - ALOGE_IF(ret < 0, + const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN); + ALOGE_IF(!status, "BufferHubChannel::SignalAvailable: failed to signal availability " "channel_id=%d: %s", - channel_id_, strerror(-ret)); + channel_id_, status.GetErrorMessage().c_str()); } else { ALOGD_IF(TRACE, "BufferHubChannel::SignalAvailable: detached buffer."); } @@ -454,11 +454,11 @@ void BufferHubChannel::ClearAvailable() { "BufferHubChannel::ClearAvailable: channel_id=%d buffer_id=%d", channel_id(), buffer_id()); if (!IsDetached()) { - const int ret = service_->ModifyChannelEvents(channel_id_, POLLIN, 0); - ALOGE_IF(ret < 0, + const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0); + ALOGE_IF(!status, "BufferHubChannel::ClearAvailable: failed to clear availability " "channel_id=%d: %s", - channel_id_, strerror(-ret)); + channel_id_, status.GetErrorMessage().c_str()); } else { ALOGD_IF(TRACE, "BufferHubChannel::ClearAvailable: detached buffer."); } @@ -469,11 +469,11 @@ void BufferHubChannel::Hangup() { ALOGD_IF(TRACE, "BufferHubChannel::Hangup: channel_id=%d buffer_id=%d", channel_id(), buffer_id()); if (!IsDetached()) { - const int ret = service_->ModifyChannelEvents(channel_id_, 0, POLLHUP); + const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLHUP); ALOGE_IF( - ret < 0, + !status, "BufferHubChannel::Hangup: failed to signal hangup channel_id=%d: %s", - channel_id_, strerror(-ret)); + channel_id_, status.GetErrorMessage().c_str()); } else { ALOGD_IF(TRACE, "BufferHubChannel::Hangup: detached buffer."); } diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h index 28cb468239..8a7dca843d 100644 --- a/services/vr/bufferhubd/buffer_hub.h +++ b/services/vr/bufferhubd/buffer_hub.h @@ -141,7 +141,7 @@ class BufferHubService : public pdx::ServiceBase<BufferHubService> { BufferHubService(); ~BufferHubService() override; - int HandleMessage(pdx::Message& message) override; + pdx::Status<void> HandleMessage(pdx::Message& message) override; void HandleImpulse(pdx::Message& message) override; void OnChannelClose(pdx::Message& message, diff --git a/services/vr/bufferhubd/bufferhubd.rc b/services/vr/bufferhubd/bufferhubd.rc index 65b7293160..8d57723994 100644 --- a/services/vr/bufferhubd/bufferhubd.rc +++ b/services/vr/bufferhubd/bufferhubd.rc @@ -3,4 +3,4 @@ service bufferhubd /system/bin/bufferhubd user system group system writepid /dev/cpuset/tasks - + socket pdx/system/buffer_hub/client stream 0660 system system diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index 98a419f976..903d17464a 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp @@ -161,12 +161,12 @@ RemoteChannelHandle ProducerChannel::CreateConsumer(Message& message) { auto consumer = std::make_shared<ConsumerChannel>( service(), buffer_id(), channel_id, shared_from_this()); - const int ret = service()->SetChannel(channel_id, consumer); - if (ret < 0) { + const auto channel_status = service()->SetChannel(channel_id, consumer); + if (!channel_status) { ALOGE( "ProducerChannel::CreateConsumer: failed to set new consumer channel: " "%s", - strerror(-ret)); + channel_status.GetErrorMessage().c_str()); return RemoteChannelHandle(); } @@ -238,7 +238,7 @@ LocalFence ProducerChannel::OnProducerGain(Message& message) { ClearAvailable(); producer_owns_ = true; - post_fence_.get_fd(); + post_fence_.close(); return std::move(returned_fence_); } diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp index 08f1e9d119..7952642456 100644 --- a/services/vr/bufferhubd/producer_queue_channel.cpp +++ b/services/vr/bufferhubd/producer_queue_channel.cpp @@ -97,18 +97,18 @@ ProducerQueueChannel::OnCreateConsumerQueue(Message& message) { "ProducerQueueChannel::OnCreateConsumerQueue: failed to push consumer " "channel: %s", status.GetErrorMessage().c_str()); - REPLY_ERROR_RETURN(message, ENOMEM, {}); + REPLY_ERROR_RETURN(message, status.error(), {}); } - const int ret = service()->SetChannel( + const auto channel_status = service()->SetChannel( channel_id, std::make_shared<ConsumerQueueChannel>( service(), buffer_id(), channel_id, shared_from_this())); - if (ret < 0) { + if (!channel_status) { ALOGE( "ProducerQueueChannel::OnCreateConsumerQueue: failed to set new " "consumer channel: %s", - strerror(-ret)); - REPLY_ERROR_RETURN(message, ENOMEM, {}); + channel_status.GetErrorMessage().c_str()); + REPLY_ERROR_RETURN(message, channel_status.error(), {}); } return std::make_pair(status.take(), meta_size_bytes_); @@ -214,12 +214,13 @@ std::pair<RemoteChannelHandle, size_t> ProducerQueueChannel::AllocateBuffer( "ProducerQueueChannel::AllocateBuffer: buffer_id=%d, buffer_handle=%d", buffer_id, buffer_handle.value()); - const int ret = service()->SetChannel(buffer_id, producer_channel); - if (ret < 0) { + const auto channel_status = + service()->SetChannel(buffer_id, producer_channel); + if (!channel_status) { ALOGE( - "ProducerQueueChannel::AllocateBuffer: failed to set prodcuer channel " + "ProducerQueueChannel::AllocateBuffer: failed to set producer channel " "for new BufferHubBuffer: %s", - strerror(-ret)); + channel_status.GetErrorMessage().c_str()); return {}; } @@ -252,7 +253,7 @@ std::pair<RemoteChannelHandle, size_t> ProducerQueueChannel::AllocateBuffer( return {std::move(buffer_handle), slot}; } -int ProducerQueueChannel::OnProducerQueueDetachBuffer(Message& message, +int ProducerQueueChannel::OnProducerQueueDetachBuffer(Message& /*message*/, size_t slot) { if (buffers_[slot].expired()) { ALOGE( diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index 1601c7f6e0..629d65bb5a 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -75,31 +75,6 @@ cc_binary { ], } -cc_library_static { - name: "libdvr_hwc", - srcs: [ - "dvr_hardware_composer_client.cpp", - ], - static_libs: [ - "libvr_hwc-impl", - // NOTE: This needs to be included after the *-impl lib otherwise the - // symbols in the *-binder library get optimized out. - "libvr_hwc-binder", - ], - shared_libs: [ - "libbase", - "libbinder", - "liblog", - "libnativewindow", - "libui", - "libutils", - ], - export_include_dirs: ["private"], - export_shared_lib_headers: [ - "libnativewindow", - ], -} - cc_test { name: "vr_hwc_test", gtest: true, diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp index cb3e49d458..45eabcab28 100644 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp +++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp @@ -19,6 +19,12 @@ status_t ParcelableComposerFrame::writeToParcel(Parcel* parcel) const { status_t ret = parcel->writeUint64(frame_.display_id); if (ret != OK) return ret; + ret = parcel->writeInt32(frame_.display_width); + if (ret != OK) return ret; + + ret = parcel->writeInt32(frame_.display_height); + if (ret != OK) return ret; + ret = parcel->writeBool(frame_.removed); if (ret != OK) return ret; @@ -35,6 +41,12 @@ status_t ParcelableComposerFrame::readFromParcel(const Parcel* parcel) { status_t ret = parcel->readUint64(&frame_.display_id); if (ret != OK) return ret; + ret = parcel->readInt32(&frame_.display_width); + if (ret != OK) return ret; + + ret = parcel->readInt32(&frame_.display_height); + if (ret != OK) return ret; + ret = parcel->readBool(&frame_.removed); if (ret != OK) return ret; diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp index 34e2b7ec36..999d71efb3 100644 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp +++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp @@ -34,9 +34,9 @@ sp<GraphicBuffer> GetBufferFromHandle(native_handle_t* handle) { // capability. Otherwise assume a count of 1. mapper.getLayerCount(handle, &layer_count); - sp<GraphicBuffer> buffer = new GraphicBuffer( - width, height, format, layer_count, producer_usage, consumer_usage, - stride, handle, true); + sp<GraphicBuffer> buffer = new GraphicBuffer(handle, + GraphicBuffer::TAKE_HANDLE, width, height, format, layer_count, + producer_usage, consumer_usage, stride); return buffer; } diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp index cfc2708e46..d082f4bc92 100644 --- a/services/vr/hardware_composer/tests/vr_composer_test.cpp +++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp @@ -104,6 +104,8 @@ TEST_F(VrComposerTest, TestWithOneLayer) { ComposerView::Frame frame; frame.display_id = 1; frame.removed = false; + frame.display_width = 600; + frame.display_height = 400; frame.layers.push_back(ComposerView::ComposerLayer{ .id = 1, .buffer = CreateBuffer(), @@ -120,6 +122,8 @@ TEST_F(VrComposerTest, TestWithOneLayer) { ComposerView::Frame received_frame = callback->last_frame(); ASSERT_EQ(frame.display_id, received_frame.display_id); + ASSERT_EQ(frame.display_width, received_frame.display_width); + ASSERT_EQ(frame.display_height, received_frame.display_height); ASSERT_EQ(frame.removed, received_frame.removed); ASSERT_EQ(1u, received_frame.layers.size()); ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id); diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc index 5d3c4f74f8..52d4da8d57 100644 --- a/services/vr/hardware_composer/vr_hwc.rc +++ b/services/vr/hardware_composer/vr_hwc.rc @@ -3,4 +3,3 @@ service vr_hwc /system/bin/vr_hwc user system group system graphics onrestart restart surfaceflinger - disabled diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp index c99c8d4801..955c6610cc 100644 --- a/services/vr/performanced/performance_service.cpp +++ b/services/vr/performanced/performance_service.cpp @@ -170,22 +170,22 @@ std::string PerformanceService::OnGetCpuPartition(Message& message, return task.GetCpuSetPath(); } -int PerformanceService::HandleMessage(Message& message) { +pdx::Status<void> PerformanceService::HandleMessage(Message& message) { switch (message.GetOp()) { case PerformanceRPC::SetCpuPartition::Opcode: DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>( *this, &PerformanceService::OnSetCpuPartition, message); - return 0; + return {}; case PerformanceRPC::SetSchedulerClass::Opcode: DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>( *this, &PerformanceService::OnSetSchedulerClass, message); - return 0; + return {}; case PerformanceRPC::GetCpuPartition::Opcode: DispatchRemoteMethod<PerformanceRPC::GetCpuPartition>( *this, &PerformanceService::OnGetCpuPartition, message); - return 0; + return {}; default: return Service::HandleMessage(message); diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h index e32d83441b..34abba7bd9 100644 --- a/services/vr/performanced/performance_service.h +++ b/services/vr/performanced/performance_service.h @@ -17,7 +17,7 @@ namespace dvr { // achieve system performance goals. class PerformanceService : public pdx::ServiceBase<PerformanceService> { public: - int HandleMessage(pdx::Message& message) override; + pdx::Status<void> HandleMessage(pdx::Message& message) override; bool IsInitialized() const override; std::string DumpState(size_t max_length) override; diff --git a/services/vr/performanced/performanced.rc b/services/vr/performanced/performanced.rc index 5042982d80..6283f37178 100644 --- a/services/vr/performanced/performanced.rc +++ b/services/vr/performanced/performanced.rc @@ -3,3 +3,4 @@ service performanced /system/bin/performanced user root group system readproc writepid /dev/cpuset/tasks + socket pdx/system/performance/client stream 0666 system system diff --git a/services/vr/sensord/pose_service.cpp b/services/vr/sensord/pose_service.cpp index 2c4fc30bd1..7534732ec2 100644 --- a/services/vr/sensord/pose_service.cpp +++ b/services/vr/sensord/pose_service.cpp @@ -65,6 +65,9 @@ static constexpr char kPoseRingBufferName[] = "PoseService:RingBuffer"; static constexpr int kDatasetIdLength = 36; static constexpr char kDatasetIdChars[] = "0123456789abcdef-"; +static constexpr int kLatencyWindowSize = 100; +static constexpr double kLatencyWindowMass = 0.5; + // These are the flags used by BufferProducer::CreatePersistentUncachedBlob, // plus PRIVATE_ADSP_HEAP to allow access from the DSP. static constexpr int kPoseRingBufferFlags = @@ -111,7 +114,8 @@ PoseService::PoseService(SensorThread* sensor_thread) vsync_count_(0), photon_timestamp_(0), // Will be updated by external service, but start with a non-zero value: - display_period_ns_(16000000) { + display_period_ns_(16000000), + sensor_latency_(kLatencyWindowSize, kLatencyWindowMass) { last_known_pose_ = { .orientation = {1.0f, 0.0f, 0.0f, 0.0f}, .translation = {0.0f, 0.0f, 0.0f, 0.0f}, @@ -463,10 +467,13 @@ void PoseService::UpdatePoseMode() { start_from_head_rotation * Vector3d(0.0, kDefaultNeckVerticalOffset, -kDefaultNeckHorizontalOffset); - // IMU driver gives timestamps on its own clock, but we need monotonic - // clock. Subtract 5ms to account for estimated IMU sample latency. - WriteAsyncPoses(position, start_from_head_rotation, - pose_state.timestamp_ns + 5000000); + // Update the current latency model. + sensor_latency_.AddLatency(GetSystemClockNs() - pose_state.timestamp_ns); + + // Update the timestamp with the expected latency. + WriteAsyncPoses( + position, start_from_head_rotation, + pose_state.timestamp_ns + sensor_latency_.CurrentLatencyEstimate()); break; } default: @@ -476,8 +483,8 @@ void PoseService::UpdatePoseMode() { } } -int PoseService::HandleMessage(pdx::Message& msg) { - int ret = 0; +pdx::Status<void> PoseService::HandleMessage(pdx::Message& msg) { + pdx::Status<void> ret; const pdx::MessageInfo& info = msg.GetInfo(); switch (info.op) { case DVR_POSE_NOTIFY_VSYNC: { @@ -495,21 +502,13 @@ int PoseService::HandleMessage(pdx::Message& msg) { {.iov_base = &right_eye_photon_offset_ns_, .iov_len = sizeof(right_eye_photon_offset_ns_)}, }; - constexpr int expected_size = - sizeof(vsync_count_) + sizeof(photon_timestamp_) + - sizeof(display_period_ns_) + sizeof(right_eye_photon_offset_ns_); - ret = msg.ReadVector(data, sizeof(data) / sizeof(data[0])); - if (ret < expected_size) { - ALOGI("error: msg.Read read too little (%d < %d)", ret, expected_size); - REPLY_ERROR(msg, EIO, error); - } - - if (!enable_external_pose_) { + ret = msg.ReadVectorAll(data); + if (ret && !enable_external_pose_) { mapped_pose_buffer_->vsync_count = vsync_count_; } // TODO(jbates, eieio): make this async, no need to reply. - REPLY_SUCCESS(msg, 0, error); + REPLY_MESSAGE(msg, ret, error); } case DVR_POSE_POLL: { ATRACE_NAME("pose_poll"); @@ -535,61 +534,43 @@ int PoseService::HandleMessage(pdx::Message& msg) { Btrace("Pose polled"); - ret = msg.Write(&client_state, sizeof(client_state)); - const int expected_size = sizeof(client_state); - if (ret < expected_size) { - ALOGI("error: msg.Write wrote too little (%d < %d)", ret, - expected_size); - REPLY_ERROR(msg, EIO, error); - } - REPLY_SUCCESS(msg, 0, error); + ret = msg.WriteAll(&client_state, sizeof(client_state)); + REPLY_MESSAGE(msg, ret, error); } case DVR_POSE_FREEZE: { { std::lock_guard<std::mutex> guard(mutex_); DvrPoseState frozen_state; - const int expected_size = sizeof(frozen_state); - ret = msg.Read(&frozen_state, expected_size); - if (ret < expected_size) { - ALOGI("error: msg.Read read too little (%d < %d)", ret, - expected_size); - REPLY_ERROR(msg, EIO, error); + ret = msg.ReadAll(&frozen_state, sizeof(frozen_state)); + if (!ret) { + REPLY_ERROR(msg, ret.error(), error); } frozen_state_ = frozen_state; } SetPoseMode(DVR_POSE_MODE_MOCK_FROZEN); - REPLY_SUCCESS(msg, 0, error); + REPLY_MESSAGE(msg, ret, error); } case DVR_POSE_SET_MODE: { int mode; { std::lock_guard<std::mutex> guard(mutex_); - const int expected_size = sizeof(mode); - ret = msg.Read(&mode, expected_size); - if (ret < expected_size) { - ALOGI("error: msg.Read read too little (%d < %d)", ret, - expected_size); - REPLY_ERROR(msg, EIO, error); + ret = msg.ReadAll(&mode, sizeof(mode)); + if (!ret) { + REPLY_ERROR(msg, ret.error(), error); } if (mode < 0 || mode >= DVR_POSE_MODE_COUNT) { REPLY_ERROR(msg, EINVAL, error); } } SetPoseMode(DvrPoseMode(mode)); - REPLY_SUCCESS(msg, 0, error); + REPLY_MESSAGE(msg, ret, error); } case DVR_POSE_GET_MODE: { std::lock_guard<std::mutex> guard(mutex_); int mode = pose_mode_; - ret = msg.Write(&mode, sizeof(mode)); - const int expected_size = sizeof(mode); - if (ret < expected_size) { - ALOGI("error: msg.Write wrote too little (%d < %d)", ret, - expected_size); - REPLY_ERROR(msg, EIO, error); - } - REPLY_SUCCESS(msg, 0, error); + ret = msg.WriteAll(&mode, sizeof(mode)); + REPLY_MESSAGE(msg, ret, error); } case DVR_POSE_GET_RING_BUFFER: { std::lock_guard<std::mutex> guard(mutex_); diff --git a/services/vr/sensord/pose_service.h b/services/vr/sensord/pose_service.h index 4df503672b..7b7adecb83 100644 --- a/services/vr/sensord/pose_service.h +++ b/services/vr/sensord/pose_service.h @@ -11,8 +11,9 @@ #include <dvr/pose_client.h> #include <pdx/service.h> #include <private/dvr/buffer_hub_client.h> -#include <private/dvr/pose_client_internal.h> #include <private/dvr/dvr_pose_predictor.h> +#include <private/dvr/latency_model.h> +#include <private/dvr/pose_client_internal.h> #include <private/dvr/ring_buffer.h> #include "sensor_fusion.h" @@ -27,7 +28,7 @@ class PoseService : public pdx::ServiceBase<PoseService> { ~PoseService() override; bool IsInitialized() const override; - int HandleMessage(pdx::Message& msg) override; + pdx::Status<void> HandleMessage(pdx::Message& msg) override; std::string DumpState(size_t max_length) override; // Handle events from the sensor HAL. @@ -132,6 +133,9 @@ class PoseService : public pdx::ServiceBase<PoseService> { int64_t display_period_ns_; int64_t right_eye_photon_offset_ns_ = 0; + // To model the measurement - arrival latency. + LatencyModel sensor_latency_; + // Type for controlling pose orientation calculation. OrientationType device_orientation_type_; diff --git a/services/vr/sensord/sensor_service.cpp b/services/vr/sensord/sensor_service.cpp index 1b809b04a0..a182a262ab 100644 --- a/services/vr/sensord/sensor_service.cpp +++ b/services/vr/sensord/sensor_service.cpp @@ -69,8 +69,8 @@ void SensorService::RemoveSensorClient(SensorClient* client) { client->unset_sensor(); } -int SensorService::HandleMessage(pdx::Message& msg) { - int ret = 0; +pdx::Status<void> SensorService::HandleMessage(pdx::Message& msg) { + pdx::Status<void> ret; const pdx::MessageInfo& info = msg.GetInfo(); switch (info.op) { case DVR_SENSOR_START: { @@ -82,8 +82,7 @@ int SensorService::HandleMessage(pdx::Message& msg) { if (client->has_sensor()) REPLY_ERROR(msg, EINVAL, error); int sensor_type; - if (msg.Read(&sensor_type, sizeof(sensor_type)) < - (ssize_t)sizeof(sensor_type)) + if (!msg.ReadAll(&sensor_type, sizeof(sensor_type))) REPLY_ERROR(msg, EIO, error); // Find the sensor of the requested type. @@ -120,10 +119,8 @@ int SensorService::HandleMessage(pdx::Message& msg) { {.iov_base = out_buffer, .iov_len = num_events * sizeof(sensors_event_t)}, }; - ret = msg.WriteVector(svec, 2); - int expected_size = sizeof(int) + num_events * sizeof(sensors_event_t); - if (ret < expected_size) { - ALOGI("error: msg.WriteVector wrote too little."); + ret = msg.WriteVectorAll(svec, 2); + if (!ret) { REPLY_ERROR(msg, EIO, error); } REPLY_SUCCESS(msg, 0, error); diff --git a/services/vr/sensord/sensor_service.h b/services/vr/sensord/sensor_service.h index c35fadaea9..6ea470b06e 100644 --- a/services/vr/sensord/sensor_service.h +++ b/services/vr/sensord/sensor_service.h @@ -22,7 +22,7 @@ class SensorClient; */ class SensorService : public pdx::ServiceBase<SensorService> { public: - int HandleMessage(pdx::Message& msg) override; + pdx::Status<void> HandleMessage(pdx::Message& msg) override; std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& msg) override; void OnChannelClose(pdx::Message& msg, const std::shared_ptr<pdx::Channel>& chan) override; diff --git a/services/vr/sensord/sensord.rc b/services/vr/sensord/sensord.rc index f8d28fd448..36cd377369 100644 --- a/services/vr/sensord/sensord.rc +++ b/services/vr/sensord/sensord.rc @@ -7,3 +7,5 @@ service sensord /system/bin/sensord user system group system camera sdcard_rw writepid /dev/cpuset/system/tasks + socket pdx/system/vr/sensors/client stream 0666 system system + socket pdx/system/vr/pose/client stream 0666 system system diff --git a/services/vr/vr_window_manager/Android.bp b/services/vr/vr_window_manager/Android.bp index a7a341ca49..0406331a4d 100644 --- a/services/vr/vr_window_manager/Android.bp +++ b/services/vr/vr_window_manager/Android.bp @@ -41,6 +41,7 @@ static_libs = [ "libperformance", "libpdx_default_transport", "libcutils", + "libvr_hwc-binder", "libvr_manager", "libvirtualtouchpadclient", ] diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp index 8aa2fd5554..d142729d23 100644 --- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp +++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp @@ -69,11 +69,10 @@ sp<GraphicBuffer> GetBufferFromHandle(const native_handle_t* handle) { mapper.getLayerCount(handle, &layer_count); // NOTE: Can't re-use |handle| since we don't own it. - sp<GraphicBuffer> buffer = new GraphicBuffer( - width, height, format, layer_count, producer_usage, consumer_usage, - stride, native_handle_clone(handle), true); - // Need to register the cloned buffer otherwise it can't be used later on. - if (mapper.registerBuffer(buffer.get()) != OK) { + sp<GraphicBuffer> buffer = new GraphicBuffer(handle, + GraphicBuffer::CLONE_HANDLE, width, height, format, layer_count, + producer_usage, consumer_usage, stride); + if (buffer->initCheck() != OK) { ALOGE("Failed to register cloned buffer"); return nullptr; } @@ -81,9 +80,35 @@ sp<GraphicBuffer> GetBufferFromHandle(const native_handle_t* handle) { return buffer; } +void GetPrimaryDisplaySize(int32_t* width, int32_t* height) { + *width = 1080; + *height = 1920; + + int error = 0; + auto display_client = DisplayClient::Create(&error); + SystemDisplayMetrics metrics; + + if (error) { + ALOGE("Could not connect to display service : %s(%d)", strerror(error), + error); + return; + } + + error = display_client->GetDisplayMetrics(&metrics); + if (error) { + ALOGE("Could not get display metrics from display service : %s(%d)", + strerror(error), error); + return; + } + + *width = metrics.display_native_width; + *height = metrics.display_native_height; +} + } // namespace -HwcDisplay::HwcDisplay() {} +HwcDisplay::HwcDisplay(int32_t width, int32_t height) + : width_(width), height_(height) {} HwcDisplay::~HwcDisplay() {} @@ -222,7 +247,7 @@ std::vector<Layer> HwcDisplay::UpdateLastFrameAndGetLastFrameLayers() { //////////////////////////////////////////////////////////////////////////////// // VrHwcClient -VrHwc::VrHwc() { displays_[kDefaultDisplayId].reset(new HwcDisplay()); } +VrHwc::VrHwc() {} VrHwc::~VrHwc() {} @@ -235,6 +260,14 @@ void VrHwc::removeClient() { void VrHwc::enableCallback(bool enable) { if (enable && client_ != nullptr) { + { + int32_t width, height; + GetPrimaryDisplaySize(&width, &height); + std::lock_guard<std::mutex> guard(mutex_); + // Create the primary display late to avoid initialization issues between + // VR HWC and SurfaceFlinger. + displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height)); + } client_.promote()->onHotplug(kDefaultDisplayId, IComposerCallback::Connection::CONNECTED); } @@ -246,7 +279,7 @@ Error VrHwc::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, Display* outDisplay) { *format = PixelFormat::RGBA_8888; *outDisplay = display_count_; - displays_[display_count_].reset(new HwcDisplay()); + displays_[display_count_].reset(new HwcDisplay(width, height)); display_count_++; return Error::NONE; } @@ -308,41 +341,20 @@ Error VrHwc::getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) { std::lock_guard<std::mutex> guard(mutex_); - if (!FindDisplay(display)) + auto display_ptr = FindDisplay(display); + if (!display_ptr) { return Error::BAD_DISPLAY; + } if (config != kDefaultConfigId) { return Error::BAD_CONFIG; } - int error = 0; - auto display_client = DisplayClient::Create(&error); - SystemDisplayMetrics metrics; - - if (error) { - ALOGE("Could not connect to display service : %s(%d)", strerror(error), - error); - } else { - error = display_client->GetDisplayMetrics(&metrics); - - if (error) { - ALOGE("Could not get display metrics from display service : %s(%d)", - strerror(error), error); - } - } - - if (error) { - metrics.display_native_width = 1080; - metrics.display_native_height = 1920; - ALOGI("Setting display metrics to default : width=%d height=%d", - metrics.display_native_width, metrics.display_native_height); - } - switch (attribute) { case IComposerClient::Attribute::WIDTH: - *outValue = metrics.display_native_width; + *outValue = display_ptr->width(); break; case IComposerClient::Attribute::HEIGHT: - *outValue = metrics.display_native_height; + *outValue = display_ptr->height(); break; case IComposerClient::Attribute::VSYNC_PERIOD: *outValue = 1000 * 1000 * 1000 / 30; // 30fps @@ -510,6 +522,8 @@ Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer> last_frame_layers; Error status = display_ptr->GetFrame(&frame.layers); frame.display_id = display; + frame.display_width = display_ptr->width(); + frame.display_height = display_ptr->height(); if (status != Error::NONE) return status; diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h index 3c76120f71..bfca9a6993 100644 --- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h +++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h @@ -74,6 +74,8 @@ class ComposerView { // being removed, or left false in the case of a normal frame. The upper // layer tracks display IDs and will handle new ones showing up. bool removed = false; + int32_t display_width; + int32_t display_height; std::vector<ComposerLayer> layers; }; @@ -107,9 +109,12 @@ struct HwcLayer { class HwcDisplay { public: - HwcDisplay(); + HwcDisplay(int32_t width, int32_t height); ~HwcDisplay(); + int32_t width() const { return width_; } + int32_t height() const { return height_; } + HwcLayer* CreateLayer(); bool DestroyLayer(Layer id); HwcLayer* GetLayer(Layer id); @@ -138,6 +143,9 @@ class HwcDisplay { // Layer ID generator. uint64_t layer_ids_ = 1; + int32_t width_; + int32_t height_; + HwcDisplay(const HwcDisplay&) = delete; void operator=(const HwcDisplay&) = delete; }; diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp index 311e27fd6e..52984b70d3 100644 --- a/services/vr/vr_window_manager/display_view.cpp +++ b/services/vr/vr_window_manager/display_view.cpp @@ -168,8 +168,7 @@ void DisplayView::SetPrograms(ShaderProgram* program, void DisplayView::DrawEye(EyeType /* eye */, const mat4& perspective, const mat4& eye_matrix, const mat4& head_matrix, - const vec2& size, float fade_value) { - size_ = size; + float fade_value) { scale_ = GetScalingMatrix(size_.x(), size_.y()); DrawOverlays(perspective, eye_matrix, head_matrix, fade_value); @@ -204,6 +203,7 @@ void DisplayView::OnDrawFrame(SurfaceFlingerView* surface_flinger_view, base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame, bool debug_mode, bool is_vr_active, bool* showing) { + size_ = vec2(frame->display_width(), frame->display_height()); uint32_t app = current_vr_app_; ViewMode visibility = CalculateVisibilityFromLayerConfig(*frame.get(), &app); diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h index aaf4677467..ad624c6e8c 100644 --- a/services/vr/vr_window_manager/display_view.h +++ b/services/vr/vr_window_manager/display_view.h @@ -29,7 +29,7 @@ class DisplayView { void OnDrawFrame(SurfaceFlingerView* surface_flinger_view, bool debug_mode); void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix, - const mat4& head_matrix, const vec2& size, float fade_value); + const mat4& head_matrix, float fade_value); void Recenter(const mat4& initial); @@ -43,6 +43,7 @@ class DisplayView { const vec2& hit_location() const { return hit_location_in_window_coord_; } uint32_t id() const { return id_; } int touchpad_id() const { return touchpad_id_; } + vec2 size() const { return size_; } void set_2dmode(bool mode) { use_2dmode_ = mode; } void set_always_2d(bool mode) { always_2d_ = mode; } diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp index 2d2a85ce77..43f504276a 100644 --- a/services/vr/vr_window_manager/hwc_callback.cpp +++ b/services/vr/vr_window_manager/hwc_callback.cpp @@ -38,30 +38,39 @@ HwcCallback::HwcCallback(Client* client) : client_(client) { HwcCallback::~HwcCallback() { } -base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& display_frame) { - auto& frame = display_frame.layers; - std::vector<HwcLayer> hwc_frame(frame.size()); - - for (size_t i = 0; i < frame.size(); ++i) { +binder::Status HwcCallback::onNewFrame( + const ParcelableComposerFrame& parcelable_frame, + ParcelableUniqueFd* fence) { + ComposerView::Frame frame = parcelable_frame.frame(); + std::vector<HwcLayer> hwc_frame(frame.layers.size()); + for (size_t i = 0; i < frame.layers.size(); ++i) { + const ComposerView::ComposerLayer& layer = frame.layers[i]; hwc_frame[i] = HwcLayer{ - .fence = frame[i].fence, - .buffer = frame[i].buffer, - .crop = frame[i].crop, - .display_frame = frame[i].display_frame, - .blending = static_cast<int32_t>(frame[i].blend_mode), - .appid = frame[i].app_id, - .type = static_cast<HwcLayer::LayerType>(frame[i].type), - .alpha = frame[i].alpha, + .fence = layer.fence, + .buffer = layer.buffer, + .crop = layer.crop, + .display_frame = layer.display_frame, + .blending = static_cast<int32_t>(layer.blend_mode), + .appid = layer.app_id, + .type = static_cast<HwcLayer::LayerType>(layer.type), + .alpha = layer.alpha, }; } - return client_->OnFrame(std::make_unique<Frame>( - std::move(hwc_frame), display_frame.display_id, display_frame.removed)); + fence->set_fence(client_->OnFrame(std::make_unique<Frame>( + std::move(hwc_frame), frame.display_id, frame.removed, + frame.display_width, frame.display_height))); + return binder::Status::ok(); } HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, - bool removed) - : display_id_(display_id), removed_(removed), layers_(std::move(layers)) {} + bool removed, int32_t display_width, + int32_t display_height) + : display_id_(display_id), + removed_(removed), + display_width_(display_width), + display_height_(display_height), + layers_(std::move(layers)) {} HwcCallback::FrameStatus HwcCallback::Frame::Finish() { if (status_ == FrameStatus::kUnfinished) diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h index b8aa51b1a9..f1f91a1381 100644 --- a/services/vr/vr_window_manager/hwc_callback.h +++ b/services/vr/vr_window_manager/hwc_callback.h @@ -1,14 +1,16 @@ #ifndef VR_WINDOW_MANAGER_HWC_CALLBACK_H_ #define VR_WINDOW_MANAGER_HWC_CALLBACK_H_ +#include <android/dvr/BnVrComposerCallback.h> +#include <android-base/unique_fd.h> + #include <deque> #include <functional> #include <mutex> #include <vector> -#include <android-base/unique_fd.h> -#include <impl/vr_composer_view.h> -#include <impl/vr_hwc.h> +#include "impl/vr_composer_view.h" +#include "impl/vr_hwc.h" namespace android { @@ -20,7 +22,7 @@ namespace dvr { using Recti = ComposerView::ComposerLayer::Recti; using Rectf = ComposerView::ComposerLayer::Rectf; -class HwcCallback : public VrComposerView::Callback { +class HwcCallback : public BnVrComposerCallback { public: struct HwcLayer { enum LayerType : uint32_t { @@ -81,16 +83,21 @@ class HwcCallback : public VrComposerView::Callback { class Frame { public: - Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed); + Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed, + int32_t display_width, int32_t display_height); FrameStatus Finish(); const std::vector<HwcLayer>& layers() const { return layers_; } uint32_t display_id() const { return display_id_; } bool removed() const { return removed_; } + int32_t display_width() const { return display_width_; } + int32_t display_height() const { return display_height_; } private: uint32_t display_id_; bool removed_; + int32_t display_width_; + int32_t display_height_; std::vector<HwcLayer> layers_; FrameStatus status_ = FrameStatus::kUnfinished; }; @@ -105,7 +112,8 @@ class HwcCallback : public VrComposerView::Callback { ~HwcCallback() override; private: - base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override; + binder::Status onNewFrame(const ParcelableComposerFrame& frame, + ParcelableUniqueFd* fence) override; Client *client_; diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp index 3aae228c8b..850f604e5d 100644 --- a/services/vr/vr_window_manager/shell_view.cpp +++ b/services/vr/vr_window_manager/shell_view.cpp @@ -194,8 +194,11 @@ void ShellView::dumpInternal(String8& result) { result.append("[displays]\n"); result.appendFormat("count = %zu\n", displays_.size()); - for (size_t i = 0; i < displays_.size(); ++i) - result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id()); + for (size_t i = 0; i < displays_.size(); ++i) { + result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id()); + result.appendFormat(" size=%fx%f\n", + displays_[i]->size().x(), displays_[i]->size().y()); + } result.append("\n"); } @@ -327,12 +330,9 @@ void ShellView::DrawEye(EyeType eye, const mat4& perspective, should_recenter_ = false; } - size_ = vec2(surface_flinger_view_->width(), surface_flinger_view_->height()); - for (auto& display : displays_) { if (display->visible()) { - display->DrawEye(eye, perspective, eye_matrix, head_matrix, size_, - fade_value_); + display->DrawEye(eye, perspective, eye_matrix, head_matrix, fade_value_); } } @@ -481,9 +481,10 @@ void ShellView::Touch() { return; const vec2& hit_location = active_display_->hit_location(); + const vec2 size = active_display_->size(); - float x = hit_location.x() / size_.x(); - float y = hit_location.y() / size_.y(); + float x = hit_location.x() / size.x(); + float y = hit_location.y() / size.y(); // Device is portrait, but in landscape when in VR. // Rotate touch input appropriately. diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h index 8548dc16b3..be2ae583a0 100644 --- a/services/vr/vr_window_manager/shell_view.h +++ b/services/vr/vr_window_manager/shell_view.h @@ -83,7 +83,6 @@ class ShellView : public Application, bool is_touching_ = false; int touchpad_buttons_ = 0; - vec2 size_; // Used to center the scene when the shell becomes visible. bool should_recenter_ = true; diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp index 7ecc542b9a..aef23a1d7b 100644 --- a/services/vr/vr_window_manager/surface_flinger_view.cpp +++ b/services/vr/vr_window_manager/surface_flinger_view.cpp @@ -1,7 +1,8 @@ #include "surface_flinger_view.h" +#include <android/dvr/IVrComposer.h> +#include <binder/IServiceManager.h> #include <impl/vr_composer_view.h> -#include <private/dvr/display_client.h> #include <private/dvr/native_buffer.h> #include "hwc_callback.h" @@ -15,52 +16,23 @@ SurfaceFlingerView::SurfaceFlingerView() {} SurfaceFlingerView::~SurfaceFlingerView() {} bool SurfaceFlingerView::Initialize(HwcCallback::Client *client) { - const char vr_hwcomposer_name[] = "vr"; - vr_hwcomposer_ = HIDL_FETCH_IComposer(vr_hwcomposer_name); - if (!vr_hwcomposer_.get()) { - ALOGE("Failed to get vr_hwcomposer"); - return false; - } + sp<IServiceManager> sm(defaultServiceManager()); + vr_composer_ = interface_cast<IVrComposer>( + sm->getService(IVrComposer::SERVICE_NAME())); - if (vr_hwcomposer_->isRemote()) { - ALOGE("vr_hwcomposer service is remote"); + String8 service_name(IVrComposer::SERVICE_NAME().string()); + if (!vr_composer_.get()) { + ALOGE("Faild to connect to %s", service_name.c_str()); return false; } - const android::status_t vr_hwcomposer_status = - vr_hwcomposer_->registerAsService(vr_hwcomposer_name); - if (vr_hwcomposer_status != OK) { - ALOGE("Failed to register vr_hwcomposer service"); + composer_callback_ = new HwcCallback(client); + binder::Status status = vr_composer_->registerObserver(composer_callback_); + if (!status.isOk()) { + ALOGE("Failed to register observer with %s", service_name.c_str()); return false; } - vr_composer_view_ = - std::make_unique<VrComposerView>(std::make_unique<HwcCallback>(client)); - vr_composer_view_->Initialize(GetComposerViewFromIComposer( - vr_hwcomposer_.get())); - - int error = 0; - auto display_client = DisplayClient::Create(&error); - SystemDisplayMetrics metrics; - - if (error) { - ALOGE("Could not connect to display service : %s(%d)", strerror(error), error); - } else { - error = display_client->GetDisplayMetrics(&metrics); - - if (error) { - ALOGE("Could not get display metrics from display service : %s(%d)", strerror(error), error); - } - } - - if (error) { - metrics.display_native_height = 1920; - metrics.display_native_width = 1080; - ALOGI("Setting display metrics to default : width=%d height=%d", metrics.display_native_height, metrics.display_native_width); - } - - width_ = metrics.display_native_width; - height_ = metrics.display_native_height; return true; } diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h index 737029973a..1bea38d9d2 100644 --- a/services/vr/vr_window_manager/surface_flinger_view.h +++ b/services/vr/vr_window_manager/surface_flinger_view.h @@ -3,14 +3,13 @@ #include <memory> -#include <impl/vr_composer_view.h> - #include "hwc_callback.h" namespace android { namespace dvr { class IDisplay; +class IVrComposer; class Texture; struct TextureLayer { @@ -26,9 +25,6 @@ class SurfaceFlingerView { SurfaceFlingerView(); ~SurfaceFlingerView(); - int width() const { return width_; } - int height() const { return height_; } - bool Initialize(HwcCallback::Client *client); bool GetTextures(const HwcCallback::Frame& layers, @@ -37,10 +33,8 @@ class SurfaceFlingerView { bool skip_first_layer) const; private: - sp<IComposer> vr_hwcomposer_; - std::unique_ptr<VrComposerView> vr_composer_view_; - int width_ = 0; - int height_ = 0; + sp<IVrComposer> vr_composer_; + sp<HwcCallback> composer_callback_; SurfaceFlingerView(const SurfaceFlingerView&) = delete; void operator=(const SurfaceFlingerView&) = delete; diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api index 86dd0016ff..a19fcf1c56 100644 --- a/vulkan/api/vulkan.api +++ b/vulkan/api/vulkan.api @@ -28,7 +28,7 @@ import platform "platform.api" // API version (major.minor.patch) define VERSION_MAJOR 1 define VERSION_MINOR 0 -define VERSION_PATCH 43 +define VERSION_PATCH 46 // API limits define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 @@ -93,7 +93,7 @@ define NULL_HANDLE 0 @extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer" // 12 -@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 5 +@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 6 @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report" // 13 @@ -250,7 +250,7 @@ define NULL_HANDLE 0 // 85 @extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1 -@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_NAME "VK_KHR_incremental_present" +@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" // 86 @extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 @@ -309,8 +309,8 @@ define NULL_HANDLE 0 @extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" // 105 -@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 1 -@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_COUNTER_EXTENSION_NAME "VK_EXT_swapchain_colorspace" +@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 2 +@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" // 106 @extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_SPEC_VERSION 1 @@ -1195,19 +1195,20 @@ enum VkPresentModeKHR { enum VkColorSpaceKHR { VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0x00000000, - //@extension("VK_EXT_swapchain_colorspace") - VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104001, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104002, - VK_COLOR_SPACE_SCRGB_LINEAR_EXT = 1000104003, - VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT = 1000104004, - VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104005, - VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104006, - VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104007, - VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104008, - VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104009, - VK_COLOR_SPACE_BT2020_NONLINEAR_EXT = 1000104010, + //@extension("VK_EXT_swapchain_colorspace") // 105 + VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, + VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003, + VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, + VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, + VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, + VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, + VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, + VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, + VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010, VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, + VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, } @extension("VK_EXT_debug_report") // 12 @@ -1245,6 +1246,9 @@ enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, + + //extension("VK_KHR_descriptor_update_template") // 86 + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000, } @extension("VK_EXT_debug_report") // 12 @@ -3735,7 +3739,7 @@ class VkViSurfaceCreateInfoNN { @extension("VK_KHX_device_group_creation") // 71 class VkPhysicalDeviceGroupPropertiesKHX { VkStructureType sType - const void* pNext + void* pNext u32 physicalDeviceCount VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE_KHX] physicalDevices VkBool32 subsetAllocation @@ -4223,7 +4227,7 @@ class VkPipelineViewportSwizzleStateCreateInfoNV { @extension("VK_EXT_discard_rectangles") // 100 class VkPhysicalDeviceDiscardRectanglePropertiesEXT { VkStructureType sType - const void* pNext + void* pNext u32 maxDiscardRectangles } diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h index 4b3b8bf984..67eba86646 100644 --- a/vulkan/include/vulkan/vulkan.h +++ b/vulkan/include/vulkan/vulkan.h @@ -43,7 +43,7 @@ extern "C" { #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) // Version of this file -#define VK_HEADER_VERSION 43 +#define VK_HEADER_VERSION 46 #define VK_NULL_HANDLE 0 @@ -4011,6 +4011,30 @@ VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR( const VkWriteDescriptorSet* pDescriptorWrites); #endif +#define VK_KHR_incremental_present 1 +#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1 +#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" + +typedef struct VkRectLayerKHR { + VkOffset2D offset; + VkExtent2D extent; + uint32_t layer; +} VkRectLayerKHR; + +typedef struct VkPresentRegionKHR { + uint32_t rectangleCount; + const VkRectLayerKHR* pRectangles; +} VkPresentRegionKHR; + +typedef struct VkPresentRegionsKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentRegionKHR* pRegions; +} VkPresentRegionsKHR; + + + #define VK_KHR_descriptor_update_template 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplateKHR) @@ -4086,7 +4110,7 @@ VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( #define VK_EXT_debug_report 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 5 +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 6 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" #define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT @@ -4125,6 +4149,7 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000, VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), @@ -4781,7 +4806,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN( typedef struct VkPhysicalDeviceGroupPropertiesKHX { VkStructureType sType; - const void* pNext; + void* pNext; uint32_t physicalDeviceCount; VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE_KHX]; VkBool32 subsetAllocation; @@ -4906,7 +4931,7 @@ typedef struct VkExportMemoryAllocateInfoKHX { -#ifdef VK_USE_PLATFORM_WIN32_KHR +#ifdef VK_USE_PLATFORM_WIN32_KHX #define VK_KHX_external_memory_win32 1 #define VK_KHX_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 #define VK_KHX_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHX_external_memory_win32" @@ -4949,7 +4974,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHX( HANDLE handle, VkMemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties); #endif -#endif /* VK_USE_PLATFORM_WIN32_KHR */ +#endif /* VK_USE_PLATFORM_WIN32_KHX */ #define VK_KHX_external_memory_fd 1 #define VK_KHX_EXTERNAL_MEMORY_FD_SPEC_VERSION 1 @@ -5139,28 +5164,6 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHX( int* pFd); #endif -#define VK_KHR_incremental_present 1 -#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1 -#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" - -typedef struct VkRectLayerKHR { - VkOffset2D offset; - VkExtent2D extent; - uint32_t layer; -} VkRectLayerKHR; - -typedef struct VkPresentRegionKHR { - uint32_t rectangleCount; - const VkRectLayerKHR* pRectangles; -} VkPresentRegionKHR; - -typedef struct VkPresentRegionsKHR { - VkStructureType sType; - const void* pNext; - uint32_t swapchainCount; - const VkPresentRegionKHR* pRegions; -} VkPresentRegionsKHR; - #define VK_NVX_device_generated_commands 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) @@ -5705,7 +5708,7 @@ typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT { VkStructureType sType; - const void* pNext; + void* pNext; uint32_t maxDiscardRectangles; } VkPhysicalDeviceDiscardRectanglePropertiesEXT; @@ -5730,9 +5733,10 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT( #endif #define VK_EXT_swapchain_colorspace 1 -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 1 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2 #define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" + #define VK_EXT_hdr_metadata 1 #define VK_EXT_HDR_METADATA_SPEC_VERSION 1 #define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 5574da2165..3b785e671d 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -183,7 +183,9 @@ struct Swapchain { : surface(surface_), num_images(num_images_), mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR), - frame_timestamps_enabled(false) { + frame_timestamps_enabled(false), + shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || + present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { ANativeWindow* window = surface.window.get(); int64_t rdur; native_window_get_refresh_cycle_duration( @@ -197,6 +199,7 @@ struct Swapchain { bool mailbox_mode; bool frame_timestamps_enabled; uint64_t refresh_duration; + bool shared; struct Image { Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {} @@ -927,6 +930,25 @@ VkResult CreateSwapchainKHR(VkDevice device, return VK_ERROR_SURFACE_LOST_KHR; } + VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0; + if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || + create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { + swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; + err = native_window_set_shared_buffer_mode(surface.window.get(), true); + if (err != 0) { + ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + } + + if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { + err = native_window_set_auto_refresh(surface.window.get(), true); + if (err != 0) { + ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + } + int query_value; err = surface.window->query(surface.window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, @@ -941,7 +963,13 @@ VkResult CreateSwapchainKHR(VkDevice device, uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value); uint32_t num_images = (create_info->minImageCount - 1) + min_undequeued_buffers; - err = native_window_set_buffer_count(surface.window.get(), num_images); + + // Lower layer insists that we have at least two buffers. This is wasteful + // and we'd like to relax it in the shared case, but not all the pieces are + // in place for that to work yet. Note we only lie to the lower layer-- we + // don't want to give the app back a swapchain with extra images (which they + // can't actually use!). + err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images)); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? @@ -950,48 +978,12 @@ VkResult CreateSwapchainKHR(VkDevice device, return VK_ERROR_SURFACE_LOST_KHR; } - VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0; - if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || - create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { - swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; - - err = native_window_set_shared_buffer_mode(surface.window.get(), true); - if (err != 0) { - ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - } - - if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { - err = native_window_set_auto_refresh(surface.window.get(), true); - if (err != 0) { - ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - } - int gralloc_usage = 0; if (dispatch.GetSwapchainGrallocUsage2ANDROID) { uint64_t consumer_usage, producer_usage; - if (GetData(device).driver_version == 256587285) { - // HACK workaround for loader/driver mismatch during transition to - // vkGetSwapchainGrallocUsage2ANDROID. - typedef VkResult(VKAPI_PTR * - PFN_vkGetSwapchainGrallocUsage2ANDROID_HACK)( - VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, - uint64_t * grallocConsumerUsage, - uint64_t * grallocProducerUsage); - auto get_swapchain_gralloc_usage = - reinterpret_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID_HACK>( - dispatch.GetSwapchainGrallocUsage2ANDROID); - result = get_swapchain_gralloc_usage( - device, create_info->imageFormat, create_info->imageUsage, - &consumer_usage, &producer_usage); - } else { - result = dispatch.GetSwapchainGrallocUsage2ANDROID( - device, create_info->imageFormat, create_info->imageUsage, - swapchain_image_usage, &consumer_usage, &producer_usage); - } + result = dispatch.GetSwapchainGrallocUsage2ANDROID( + device, create_info->imageFormat, create_info->imageUsage, + swapchain_image_usage, &consumer_usage, &producer_usage); if (result != VK_SUCCESS) { ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result); return VK_ERROR_SURFACE_LOST_KHR; @@ -1106,17 +1098,19 @@ VkResult CreateSwapchainKHR(VkDevice device, // // TODO(jessehall): The error path here is the same as DestroySwapchain, // but not the non-error path. Should refactor/unify. - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - if (img.dequeued) { - surface.window->cancelBuffer(surface.window.get(), img.buffer.get(), - img.dequeue_fence); - img.dequeue_fence = -1; - img.dequeued = false; - } - if (result != VK_SUCCESS) { - if (img.image) - dispatch.DestroyImage(device, img.image, nullptr); + if (!swapchain->shared) { + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + if (img.dequeued) { + surface.window->cancelBuffer(surface.window.get(), img.buffer.get(), + img.dequeue_fence); + img.dequeue_fence = -1; + img.dequeued = false; + } + if (result != VK_SUCCESS) { + if (img.image) + dispatch.DestroyImage(device, img.image, nullptr); + } } } @@ -1200,6 +1194,16 @@ VkResult AcquireNextImageKHR(VkDevice device, timeout != UINT64_MAX, "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented"); + if (swapchain.shared) { + // In shared mode, we keep the buffer dequeued all the time, so we don't + // want to dequeue a buffer here. Instead, just ask the driver to ensure + // the semaphore and fence passed to us will be signalled. + *image_index = 0; + result = GetData(device).driver.AcquireImageANDROID( + device, swapchain.images[*image_index].image, -1, semaphore, vk_fence); + return result; + } + ANativeWindowBuffer* buffer; int fence_fd; err = window->dequeueBuffer(window, &buffer, &fence_fd); @@ -1420,6 +1424,7 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { static_cast<int64_t>(time->desiredPresentTime)); } } + err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error if (err != 0) { @@ -1434,6 +1439,30 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { img.dequeue_fence = -1; } img.dequeued = false; + + // If the swapchain is in shared mode, immediately dequeue the + // buffer so it can be presented again without an intervening + // call to AcquireNextImageKHR. We expect to get the same buffer + // back from every call to dequeueBuffer in this mode. + if (swapchain.shared && swapchain_result == VK_SUCCESS) { + ANativeWindowBuffer* buffer; + int fence_fd; + err = window->dequeueBuffer(window, &buffer, &fence_fd); + if (err != 0) { + ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); + swapchain_result = WorstPresentResult(swapchain_result, + VK_ERROR_SURFACE_LOST_KHR); + } + else if (img.buffer != buffer) { + ALOGE("got wrong image back for shared swapchain"); + swapchain_result = WorstPresentResult(swapchain_result, + VK_ERROR_SURFACE_LOST_KHR); + } + else { + img.dequeue_fence = fence_fd; + img.dequeued = true; + } + } } if (swapchain_result != VK_SUCCESS) { ReleaseSwapchainImage(device, window, fence, img); |