diff options
260 files changed, 7400 insertions, 2413 deletions
diff --git a/Android.bp b/Android.bp index cd05b21dde..de9ea86f1d 100644 --- a/Android.bp +++ b/Android.bp @@ -8,8 +8,15 @@ ndk_headers { subdirs = [ "cmds/*", + "headers", "libs/*", "opengl", "services/*", "vulkan", ] + +cc_library_headers { + name: "libandroid_sensor_headers", + vendor: true, + export_include_dirs: ["include_sensor"], +} diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 2d9a98c7a2..a48dab97cb 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -124,6 +124,7 @@ static const TracingCategory k_categories[] = { { OPT, "events/sched/sched_waking/enable" }, { OPT, "events/sched/sched_blocked_reason/enable" }, { OPT, "events/sched/sched_cpu_hotplug/enable" }, + { OPT, "events/cgroup/enable" }, } }, { "irq", "IRQ Events", 0, { { REQ, "events/irq/enable" }, @@ -480,8 +481,8 @@ static bool setClock() newClock = "global"; } - size_t begin = clockStr.find("[") + 1; - size_t end = clockStr.find("]"); + size_t begin = clockStr.find('[') + 1; + size_t end = clockStr.find(']'); if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) { return true; } @@ -542,7 +543,7 @@ static void pokeHalServices() auto listRet = sm->list([&](const auto &interfaces) { for (size_t i = 0; i < interfaces.size(); i++) { string fqInstanceName = interfaces[i]; - string::size_type n = fqInstanceName.find("/"); + string::size_type n = fqInstanceName.find('/'); if (n == std::string::npos || interfaces[i].size() == n+1) continue; hidl_string fqInterfaceName = fqInstanceName.substr(0, n); diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 526fd19e30..3ea1d56771 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -25,6 +25,8 @@ on post-fs chown root shell /sys/kernel/tracing/events/sched/sched_blocked_reason/enable chown root shell /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable chown root shell /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable + chown root shell /sys/kernel/debug/tracing/events/cgroup/enable + chown root shell /sys/kernel/tracing/events/cgroup/enable chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable chown root shell /sys/kernel/tracing/events/power/cpu_frequency/enable chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable @@ -77,6 +79,8 @@ on post-fs chmod 0664 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable chmod 0664 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable + chmod 0664 /sys/kernel/debug/tracing/events/cgroup/enable + chmod 0664 /sys/kernel/tracing/events/cgroup/enable chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency/enable chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp index 7e05d72eae..014c99593c 100644 --- a/cmds/cmd/cmd.cpp +++ b/cmds/cmd/cmd.cpp @@ -35,12 +35,11 @@ #include <fcntl.h> #include <sys/time.h> #include <errno.h> +#include <memory> #include "selinux/selinux.h" #include "selinux/android.h" -#include <UniquePtr.h> - #define DEBUG 0 using namespace android; @@ -55,7 +54,7 @@ struct SecurityContext_Delete { freecon(p); } }; -typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext; +typedef std::unique_ptr<char[], SecurityContext_Delete> Unique_SecurityContext; class MyShellCallback : public BnShellCallback { diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp new file mode 100644 index 0000000000..f908cbfe28 --- /dev/null +++ b/cmds/dumpstate/Android.bp @@ -0,0 +1,130 @@ +// +// 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. + +cc_defaults { + name: "dumpstate_defaults", + cflags: [ + "-Wall", + "-Werror", + "-Wno-missing-field-initializers", + "-Wno-unused-variable", + "-Wunused-parameter", + ], +} + +cc_library_headers { + name: "dumpstate_headers", + vendor_available: true, + export_include_dirs: ["."], + header_libs: [ + "libbase_headers", + "libutils_headers", + ], + export_header_lib_headers: [ + "libbase_headers", + "libutils_headers", + ], +} + +cc_library_shared { + name: "libdumpstateutil", + defaults: ["dumpstate_defaults"], + vendor_available: true, + vndk: { + enabled: true, + }, + header_libs: ["dumpstate_headers"], + export_header_lib_headers: ["dumpstate_headers"], + srcs: [ + "DumpstateInternal.cpp", + "DumpstateUtil.cpp", + ], + shared_libs: [ + "libbase", + "liblog", + ], +} + +cc_library_shared { + name: "libdumpstateaidl", + defaults: ["dumpstate_defaults"], + shared_libs: [ + "libbinder", + "libutils", + ], + aidl: { + local_include_dirs: ["binder"], + export_aidl_headers: true, + }, + srcs: [ + "binder/android/os/IDumpstate.aidl", + "binder/android/os/IDumpstateListener.aidl", + "binder/android/os/IDumpstateToken.aidl", + ], +} + +cc_binary { + name: "dumpstate", + defaults: ["dumpstate_defaults"], + header_libs: ["dumpstate_headers"], + shared_libs: [ + "android.hardware.dumpstate@1.0", + "libziparchive", + "libbase", + "libbinder", + "libcrypto", + "libcutils", + "libdebuggerd_client", + "libdumpstateaidl", + "libdumpstateutil", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + srcs: [ + "DumpstateInternal.cpp", + "DumpstateService.cpp", + "utils.cpp", + "dumpstate.cpp", + ], + init_rc: ["dumpstate.rc"], +} + +cc_test { + name: "dumpstate_test", + defaults: ["dumpstate_defaults"], + header_libs: ["dumpstate_headers"], + shared_libs: [ + "libziparchive", + "libbase", + "libbinder", + "libcutils", + "libdebuggerd_client", + "libdumpstateaidl", + "libdumpstateutil", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + srcs: [ + "DumpstateInternal.cpp", + "DumpstateService.cpp", + "utils.cpp", + "tests/dumpstate_test.cpp", + ], + static_libs: ["libgmock"], +} diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk index a1b6a51699..a96033309c 100644 --- a/cmds/dumpstate/Android.mk +++ b/cmds/dumpstate/Android.mk @@ -1,137 +1,5 @@ LOCAL_PATH:= $(call my-dir) -# ================# -# Common settings # -# ================# -# ZipArchive support, the order matters here to get all symbols. -COMMON_ZIP_LIBRARIES := libziparchive libz libcrypto - -# TODO: ideally the tests should depend on a shared dumpstate library, but currently libdumpstate -# is used to define the device-specific HAL library. Instead, both dumpstate and dumpstate_test -# shares a lot of common settings -COMMON_LOCAL_CFLAGS := \ - -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter -COMMON_SRC_FILES := \ - DumpstateInternal.cpp \ - utils.cpp -COMMON_SHARED_LIBRARIES := \ - android.hardware.dumpstate@1.0 \ - libhidlbase \ - libhidltransport \ - libbase \ - libbinder \ - libcutils \ - libdebuggerd_client \ - libdumpstateaidl \ - libdumpstateutil \ - liblog \ - libselinux \ - libutils \ - $(COMMON_ZIP_LIBRARIES) - -# ====================# -# libdumpstateutil # -# ====================# -include $(CLEAR_VARS) - -LOCAL_MODULE := libdumpstateutil - -LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS) -LOCAL_C_INCLUDES := $(LOCAL_PATH) -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) -LOCAL_SRC_FILES := \ - DumpstateInternal.cpp \ - DumpstateUtil.cpp -LOCAL_SHARED_LIBRARIES := \ - libbase \ - liblog \ - -include $(BUILD_SHARED_LIBRARY) - -# ====================# -# libdumpstateheaders # -# ====================# -# TODO: this module is necessary so the device-specific libdumpstate implementations do not -# need to add any other dependency (like libbase). Should go away once dumpstate HAL changes. -include $(CLEAR_VARS) - -LOCAL_EXPORT_C_INCLUDE_DIRS = $(LOCAL_PATH) -LOCAL_MODULE := libdumpstateheaders -LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ - $(COMMON_SHARED_LIBRARIES) -LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \ - $(COMMON_STATIC_LIBRARIES) -# Soong requires that whats is on LOCAL_EXPORTED_ is also on LOCAL_ -LOCAL_SHARED_LIBRARIES := $(LOCAL_EXPORT_SHARED_LIBRARY_HEADERS) -LOCAL_STATIC_LIBRARIES := $(LOCAL_EXPORT_STATIC_LIBRARY_HEADERS) - -include $(BUILD_STATIC_LIBRARY) - -# ================ # -# libdumpstateaidl # -# =================# -include $(CLEAR_VARS) - -LOCAL_MODULE := libdumpstateaidl - -LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS) - -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - libutils -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/binder -LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder -LOCAL_C_INCLUDES := $(LOCAL_PATH)/binder -LOCAL_SRC_FILES := \ - binder/android/os/IDumpstate.aidl \ - binder/android/os/IDumpstateListener.aidl \ - binder/android/os/IDumpstateToken.aidl - -include $(BUILD_SHARED_LIBRARY) - -# ==========# -# dumpstate # -# ==========# -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \ - DumpstateService.cpp \ - dumpstate.cpp - -LOCAL_MODULE := dumpstate - -LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES) - -LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES) - -LOCAL_CFLAGS += $(COMMON_LOCAL_CFLAGS) - -LOCAL_INIT_RC := dumpstate.rc - -include $(BUILD_EXECUTABLE) - -# ===============# -# dumpstate_test # -# ===============# -include $(CLEAR_VARS) - -LOCAL_MODULE := dumpstate_test - -LOCAL_MODULE_TAGS := tests - -LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS) - -LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \ - DumpstateService.cpp \ - tests/dumpstate_test.cpp - -LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES) \ - libgmock - -LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES) - -include $(BUILD_NATIVE_TEST) - # =======================# # dumpstate_test_fixture # # =======================# @@ -141,7 +9,8 @@ LOCAL_MODULE := dumpstate_test_fixture LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS) +LOCAL_CFLAGS := \ + -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp index 03432772b2..f0b6203578 100644 --- a/cmds/dumpstate/DumpstateInternal.cpp +++ b/cmds/dumpstate/DumpstateInternal.cpp @@ -18,6 +18,8 @@ #include "DumpstateInternal.h" +#include <grp.h> +#include <pwd.h> #include <stdint.h> #include <stdio.h> #include <string.h> @@ -25,14 +27,14 @@ #include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> +#include <unistd.h> #include <cstdint> #include <string> #include <vector> #include <android-base/file.h> -#include <cutils/log.h> -#include <private/android_filesystem_config.h> +#include <log/log.h> uint64_t Nanotime() { timespec ts; @@ -42,7 +44,17 @@ uint64_t Nanotime() { // Switches to non-root user and group. bool DropRootUser() { - if (getgid() == AID_SHELL && getuid() == AID_SHELL) { + struct group* grp = getgrnam("shell"); + gid_t shell_gid = grp != nullptr ? grp->gr_gid : 0; + struct passwd* pwd = getpwnam("shell"); + uid_t shell_uid = pwd != nullptr ? pwd->pw_uid : 0; + + if (!shell_gid || !shell_uid) { + MYLOGE("Unable to get AID_SHELL: %s\n", strerror(errno)); + return false; + } + + if (getgid() == shell_gid && getuid() == shell_uid) { MYLOGD("drop_root_user(): already running as Shell\n"); return true; } @@ -52,17 +64,28 @@ bool DropRootUser() { return false; } - gid_t groups[] = {AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, AID_MOUNT, - AID_INET, AID_NET_BW_STATS, AID_READPROC, AID_BLUETOOTH}; - if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) { + static const std::vector<std::string> group_names{ + "log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats", "readproc", "bluetooth"}; + std::vector<gid_t> groups(group_names.size(), 0); + for (size_t i = 0; i < group_names.size(); ++i) { + grp = getgrnam(group_names[i].c_str()); + groups[i] = grp != nullptr ? grp->gr_gid : 0; + if (groups[i] == 0) { + MYLOGE("Unable to get required gid '%s': %s\n", group_names[i].c_str(), + strerror(errno)); + return false; + } + } + + if (setgroups(groups.size(), groups.data()) != 0) { MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); return false; } - if (setgid(AID_SHELL) != 0) { + if (setgid(shell_gid) != 0) { MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno)); return false; } - if (setuid(AID_SHELL) != 0) { + if (setuid(shell_uid) != 0) { MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno)); return false; } diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index 26702c456d..e866b8b652 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -30,7 +30,7 @@ #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> -#include <cutils/log.h> +#include <log/log.h> #include "DumpstateInternal.h" diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 4161bd79d9..9e77e8fbcb 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -126,8 +126,7 @@ static const std::string ZIP_ROOT_DIR = "FS"; static const std::string kDumpstateBoardPath = "/bugreports/"; static const std::string kDumpstateBoardFiles[] = { "dumpstate_board.txt", - // TODO: rename to dumpstate_board.bin once vendors can handle it - "modem_log_all.tar" + "dumpstate_board.bin" }; static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles); @@ -692,7 +691,7 @@ bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) { std::string valid_name = entry_name; // Rename extension if necessary. - size_t idx = entry_name.rfind("."); + size_t idx = entry_name.rfind('.'); if (idx != std::string::npos) { std::string extension = entry_name.substr(idx); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); @@ -930,8 +929,10 @@ static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_ "VM TRACES AT LAST ANR", add_to_zip); if (anr_data->size() > 1) { + // NOTE: Historical ANRs are always added as separate entries in the + // bugreport zip file. AddDumps(anr_data->begin() + 1, anr_data->end(), - "HISTORICAL ANR", add_to_zip); + "HISTORICAL ANR", true /* add_to_zip */); } } else { printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str()); @@ -1431,7 +1432,7 @@ bool Dumpstate::FinishZipFile() { return true; } -static std::string SHA256_file_hash(std::string filepath) { +static std::string SHA256_file_hash(const std::string& filepath) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC | O_NOFOLLOW))); if (fd == -1) { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index f02303b851..7757c1e445 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -26,10 +26,11 @@ #include <vector> #include <android-base/macros.h> +#include <android/os/IDumpstateListener.h> +#include <utils/StrongPointer.h> #include <ziparchive/zip_writer.h> #include "DumpstateUtil.h" -#include "android/os/BnDumpstate.h" // Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to // std::vector<std::string> @@ -49,6 +50,8 @@ class ProgressTest; } // namespace os } // namespace android +class ZipWriter; + // TODO: remove once moved to HAL #ifdef __cplusplus extern "C" { diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index f0e7200069..32277499a6 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -16,6 +16,7 @@ #include <algorithm> #include <chrono> +#include <iomanip> #include <thread> #include <android-base/file.h> @@ -176,7 +177,7 @@ int Dumpsys::main(int argc, char* const argv[]) { } for (size_t i = 0; i < N; i++) { - String16 service_name = std::move(services[i]); + const String16& service_name = std::move(services[i]); if (IsSkipped(skippedServices, service_name)) continue; sp<IBinder> service = sm_->checkService(service_name); @@ -282,7 +283,14 @@ int Dumpsys::main(int argc, char* const argv[]) { std::chrono::duration<double> elapsed_seconds = std::chrono::steady_clock::now() - start; aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str() - << "was the duration of dumpsys " << service_name << endl; + << "was the duration of dumpsys " << service_name; + + using std::chrono::system_clock; + const auto finish = system_clock::to_time_t(system_clock::now()); + std::tm finish_tm; + localtime_r(&finish, &finish_tm); + aout << ", ending at: " << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S") + << endl; } } else { aerr << "Can't find service: " << service_name << endl; diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 66beb6d4e0..5ca2b578a6 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -95,7 +95,7 @@ MATCHER_P(AndroidElementsAre, expected, "") { } int i = 0; std::ostringstream actual_stream, expected_stream; - for (String16 actual : arg) { + for (const String16& actual : arg) { std::string actual_str = String8(actual).c_str(); std::string expected_str = expected[i]; actual_stream << "'" << actual_str << "' "; diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp index e293948caa..ea0cd9e4e2 100644 --- a/cmds/installd/CacheTracker.cpp +++ b/cmds/installd/CacheTracker.cpp @@ -60,7 +60,7 @@ void CacheTracker::loadStats() { ATRACE_BEGIN("loadStats tree"); cacheUsed = 0; - for (auto path : mDataPaths) { + for (const auto& path : mDataPaths) { auto cachePath = read_path_inode(path, "cache", kXattrInodeCache); auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache); calculate_tree_size(cachePath, &cacheUsed); @@ -148,6 +148,7 @@ void CacheTracker::loadItemsFrom(const std::string& path) { } // Bubble up modified time to parent + CHECK(p != nullptr); switch (p->fts_info) { case FTS_DP: case FTS_DEFAULT: @@ -169,7 +170,7 @@ void CacheTracker::loadItems() { items.clear(); ATRACE_BEGIN("loadItems"); - for (auto path : mDataPaths) { + for (const auto& path : mDataPaths) { loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache)); loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache)); } diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index e3021d8905..af7455a519 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -311,6 +311,7 @@ static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std return -1; } +#if APPLY_HARD_QUOTAS if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) { auto path = create_data_path(uuid ? uuid->c_str() : nullptr); struct statvfs stat; @@ -320,7 +321,8 @@ static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std } dq.dqb_valid = QIF_LIMITS; - dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE; + dq.dqb_bhardlimit = + (((static_cast<uint64_t>(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) { @@ -334,6 +336,10 @@ static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std // Hard quota already set; assume it's reasonable return 0; } +#else + // Hard quotas disabled + return 0; +#endif } binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid, @@ -1343,7 +1349,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); - for (auto packageName : packageNames) { + for (const auto& packageName : packageNames) { CHECK_ARGUMENT_PACKAGE_NAME(packageName); } // NOTE: Locking is relaxed on this method, since it's limited to @@ -1382,7 +1388,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri } ATRACE_BEGIN("obb"); - for (auto packageName : packageNames) { + for (const auto& packageName : packageNames) { auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str()); calculate_tree_size(obbCodePath, &extStats.codeSize); } @@ -1390,7 +1396,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) { ATRACE_BEGIN("code"); - for (auto codePath : codePaths) { + for (const auto& codePath : codePaths) { calculate_tree_size(codePath, &stats.codeSize, -1, multiuser_get_shared_gid(0, appId)); } @@ -1401,7 +1407,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri ATRACE_END(); } else { ATRACE_BEGIN("code"); - for (auto codePath : codePaths) { + for (const auto& codePath : codePaths) { calculate_tree_size(codePath, &stats.codeSize); } ATRACE_END(); @@ -1641,6 +1647,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: int64_t videoSize = 0; int64_t imageSize = 0; int64_t appSize = 0; + int64_t obbSize = 0; auto device = findQuotaDeviceForUuid(uuid); if (device.empty()) { @@ -1688,6 +1695,13 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: #endif imageSize = dq.dqb_curspace; } + if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB, + reinterpret_cast<char*>(&dq)) == 0) { +#if MEASURE_DEBUG + LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace; +#endif + obbSize = dq.dqb_curspace; + } ATRACE_END(); ATRACE_BEGIN("apps"); @@ -1744,6 +1758,11 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: } fts_close(fts); ATRACE_END(); + + ATRACE_BEGIN("obb"); + auto obbPath = create_data_media_obb_path(uuid_, ""); + calculate_tree_size(obbPath, &obbSize); + ATRACE_END(); } std::vector<int64_t> ret; @@ -1752,6 +1771,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: ret.push_back(videoSize); ret.push_back(imageSize); ret.push_back(appSize); + ret.push_back(obbSize); #if MEASURE_DEBUG LOG(DEBUG) << "Final result " << toString(ret); #endif @@ -1811,8 +1831,8 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t const std::unique_ptr<std::string>& packageName, const std::string& instructionSet, int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags, const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid, - const std::unique_ptr<std::string>& sharedLibraries, - const std::unique_ptr<std::string>& seInfo) { + const std::unique_ptr<std::string>& classLoaderContext, + const std::unique_ptr<std::string>& seInfo, bool downgrade) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); if (packageName && *packageName != "*") { @@ -1826,10 +1846,11 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t const char* oat_dir = outputPath ? outputPath->c_str() : nullptr; const char* compiler_filter = compilerFilter.c_str(); const char* volume_uuid = uuid ? uuid->c_str() : nullptr; - const char* shared_libraries = sharedLibraries ? sharedLibraries->c_str() : nullptr; + const char* class_loader_context = classLoaderContext ? classLoaderContext->c_str() : nullptr; const char* se_info = seInfo ? seInfo->c_str() : nullptr; int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded, - oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries, se_info); + oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info, + downgrade); return res ? error(res, "Failed to dexopt") : ok(); } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 5756b8275a..c8db3df5b6 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -83,8 +83,8 @@ public: const std::unique_ptr<std::string>& packageName, const std::string& instructionSet, int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags, const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid, - const std::unique_ptr<std::string>& sharedLibraries, - const std::unique_ptr<std::string>& seInfo); + const std::unique_ptr<std::string>& classLoaderContext, + const std::unique_ptr<std::string>& seInfo, bool downgrade); binder::Status rmdex(const std::string& codePath, const std::string& instructionSet); diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index c8e76b0ae1..452a2b193d 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -51,7 +51,7 @@ interface IInstalld { @nullable @utf8InCpp String outputPath, int dexFlags, @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid, @nullable @utf8InCpp String sharedLibraries, - @nullable @utf8InCpp String seInfo); + @nullable @utf8InCpp String seInfo, boolean downgrade); void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet); diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 615c7cb9c5..8c75ee5739 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -196,7 +196,7 @@ static const char* get_location_from_path(const char* path) { static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd, const char* input_file_name, const char* output_file_name, int swap_fd, const char* instruction_set, const char* compiler_filter, - bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) { + bool debuggable, bool post_bootcomplete, int profile_fd, const char* class_loader_context) { static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { @@ -297,6 +297,12 @@ static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vd char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN]; bool have_dex2oat_image_fd = false; char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN]; + size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX; + char class_loader_context_arg[class_loader_context_size]; + if (class_loader_context != nullptr) { + snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s", + class_loader_context); + } sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name); @@ -393,7 +399,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vd + (have_app_image_format ? 1 : 0) + dex2oat_flags_count + (profile_fd == -1 ? 0 : 1) - + (shared_libraries != nullptr ? 4 : 0) + + (class_loader_context != nullptr ? 1 : 0) + (has_base_dir ? 1 : 0) + (have_dex2oat_large_app_threshold ? 1 : 0)]; int i = 0; @@ -453,15 +459,13 @@ static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vd if (profile_fd != -1) { argv[i++] = profile_arg; } - if (shared_libraries != nullptr) { - argv[i++] = RUNTIME_ARG; - argv[i++] = "-classpath"; - argv[i++] = RUNTIME_ARG; - argv[i++] = shared_libraries; - } if (has_base_dir) { argv[i++] = base_dir; } + if (class_loader_context != nullptr) { + argv[i++] = class_loader_context_arg; + } + // Do not add after dex2oat_flags, they should override others for debugging. argv[i] = NULL; @@ -1139,10 +1143,9 @@ class Dex2oatFileWrapper { // (re)Creates the app image if needed. Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided, bool is_public, int uid, bool is_secondary_dex) { - // Use app images only if it is enabled (by a set image format) and we are compiling - // profile-guided (so the app image doesn't conservatively contain all classes). - // Note that we don't create an image for secondary dex files. - if (is_secondary_dex || !profile_guided) { + + // We don't create an image for secondary dex files. + if (is_secondary_dex) { return Dex2oatFileWrapper(); } @@ -1151,6 +1154,14 @@ Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_g // Happens when the out_oat_path has an unknown extension. return Dex2oatFileWrapper(); } + + // Use app images only if it is enabled (by a set image format) and we are compiling + // profile-guided (so the app image doesn't conservatively contain all classes). + if (!profile_guided) { + // In case there is a stale image, remove it now. Ignore any error. + unlink(image_path.c_str()); + return Dex2oatFileWrapper(); + } char app_image_format[kPropertyValueMax]; bool have_app_image_format = get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; @@ -1365,7 +1376,7 @@ void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) // If this is for a profile guided compilation, profile_was_updated will tell whether or not // the profile has changed. static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& instruction_set, - const std::string& compiler_filter, bool profile_was_updated) { + const std::string& compiler_filter, bool profile_was_updated, bool downgrade) { const char* dexoptanalyzer_bin = is_debug_runtime() ? "/system/bin/dexoptanalyzerd" @@ -1382,9 +1393,13 @@ static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& std::string isa_arg = "--isa=" + instruction_set; std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter; const char* assume_profile_changed = "--assume-profile-changed"; + const char* downgrade_flag = "--downgrade"; // program name, dex file, isa, filter, the final NULL - const char* argv[5 + (profile_was_updated ? 1 : 0)]; + const int argc = 5 + + (profile_was_updated ? 1 : 0) + + (downgrade ? 1 : 0); + const char* argv[argc]; int i = 0; argv[i++] = dexoptanalyzer_bin; argv[i++] = dex_file_arg.c_str(); @@ -1393,6 +1408,9 @@ static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& if (profile_was_updated) { argv[i++] = assume_profile_changed; } + if (downgrade) { + argv[i++] = downgrade_flag; + } argv[i] = NULL; execv(dexoptanalyzer_bin, (char * const *)argv); @@ -1473,7 +1491,7 @@ static bool process_dexoptanalyzer_result(const std::string& dex_path, int resul static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname, int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set, const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out, - std::string* oat_dir_out, std::string* dex_path_out) { + std::string* oat_dir_out, std::string* dex_path_out, bool downgrade) { int storage_flag; if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) { @@ -1542,7 +1560,8 @@ static bool process_secondary_dex_dexopt(const char* original_dex_path, const ch // child -- drop privileges before continuing. drop_capabilities(uid); // Run dexoptanalyzer to get dexopt_needed code. - exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated); + exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated, + downgrade); exit(DEXOPTANALYZER_BIN_EXEC_ERROR); } @@ -1569,7 +1588,8 @@ static bool process_secondary_dex_dexopt(const char* original_dex_path, const ch int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, - const char* volume_uuid, const char* shared_libraries, const char* se_info) { + const char* volume_uuid, const char* class_loader_context, const char* se_info, + bool downgrade) { CHECK(pkgname != nullptr); CHECK(pkgname[0] != 0); if ((dexopt_flags & ~DEXOPT_MASK) != 0) { @@ -1577,7 +1597,12 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins } if (!validate_dex_path_size(dex_path)) { - return false; + return -1; + } + + if (class_loader_context != nullptr && strlen(class_loader_context) > PKG_PATH_MAX) { + LOG(ERROR) << "Class loader context exceeds the allowed size: " << class_loader_context; + return -1; } bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0; @@ -1592,7 +1617,8 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins if (is_secondary_dex) { if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid, instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str, - &dex_real_path)) { + &dex_real_path, + downgrade)) { oat_dir = oat_dir_str.c_str(); dex_path = dex_real_path.c_str(); if (dexopt_needed == NO_DEXOPT_NEEDED) { @@ -1681,7 +1707,7 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins debuggable, boot_complete, reference_profile_fd.get(), - shared_libraries); + class_loader_context); _exit(68); /* only get here on exec failure */ } else { int res = wait_child(pid); @@ -1819,6 +1845,11 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, result = unlink_if_exists(current_profile) && result; result = unlink_if_exists(reference_profile) && result; + // We upgraded once the location of current profile for secondary dex files. + // Check for any previous left-overs and remove them as well. + std::string old_current_profile = dex_path + ".prof"; + result = unlink_if_exists(old_current_profile); + // Try removing the directories as well, they might be empty. result = rmdir_if_empty(oat_isa_dir) && result; result = rmdir_if_empty(oat_dir) && result; diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index d171ee534e..23446da43c 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -63,7 +63,8 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, - const char* volume_uuid, const char* shared_libraries, const char* se_info); + const char* volume_uuid, const char* class_loader_context, const char* se_info, + bool downgrade); } // namespace installd } // namespace android diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 68cb0d7fe5..09e1a00d10 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -178,6 +178,7 @@ private: const char* volume_uuid; const char* shared_libraries; const char* se_info; + bool downgrade; }; bool ReadSystemProperties() { @@ -281,6 +282,13 @@ private: return true; } + bool ParseBool(const char* in) { + if (strcmp(in, "true") == 0) { + return true; + } + return false; + } + bool ParseUInt(const char* in, uint32_t* out) { char* end; long long int result = strtoll(in, &end, 0); @@ -349,6 +357,8 @@ private: switch (version) { case 2: return ReadArgumentsV2(argc, argv, true); + case 3: + return ReadArgumentsV3(argc, argv); default: LOG(ERROR) << "Unsupported version " << version; @@ -427,6 +437,10 @@ private: } } + // Set downgrade to false. It is only relevant when downgrading compiler + // filter, which is not the case during ota. + package_parameters_.downgrade = false; + if (param_index != 11) { LOG(ERROR) << "Not enough parameters"; return false; @@ -435,6 +449,89 @@ private: return true; } + bool ReadArgumentsV3(int argc ATTRIBUTE_UNUSED, char** argv) { + size_t dexopt_index = 3; + + // Check for "dexopt". + if (argv[dexopt_index] == nullptr) { + LOG(ERROR) << "Missing parameters"; + return false; + } + if (std::string("dexopt").compare(argv[dexopt_index]) != 0) { + LOG(ERROR) << "Expected \"dexopt\""; + return false; + } + + size_t param_index = 0; + for (;; ++param_index) { + const char* param = argv[dexopt_index + 1 + param_index]; + if (param == nullptr) { + break; + } + + switch (param_index) { + case 0: + package_parameters_.apk_path = param; + break; + + case 1: + package_parameters_.uid = atoi(param); + break; + + case 2: + package_parameters_.pkgName = param; + break; + + case 3: + package_parameters_.instruction_set = param; + break; + + case 4: + package_parameters_.dexopt_needed = atoi(param); + break; + + case 5: + package_parameters_.oat_dir = param; + break; + + case 6: + package_parameters_.dexopt_flags = atoi(param); + break; + + case 7: + package_parameters_.compiler_filter = param; + break; + + case 8: + package_parameters_.volume_uuid = ParseNull(param); + break; + + case 9: + package_parameters_.shared_libraries = ParseNull(param); + break; + + case 10: + package_parameters_.se_info = ParseNull(param); + break; + + case 11: + package_parameters_.downgrade = ParseBool(param); + break; + + default: + LOG(ERROR) << "Too many arguments, got " << param; + return false; + } + } + + if (param_index != 12) { + LOG(ERROR) << "Not enough parameters"; + return false; + } + + return true; + } + static int ReplaceMask(int input, int old_mask, int new_mask) { return (input & old_mask) != 0 ? new_mask : 0; } @@ -534,6 +631,10 @@ private: // receive from a v1 A side. package_parameters_.se_info = nullptr; + // Set downgrade to false. It is only relevant when downgrading compiler + // filter, which is not the case during ota. + package_parameters_.downgrade = false; + return true; } @@ -753,10 +854,6 @@ private: } static const char* ParseNull(const char* arg) { - // b/38186355. Revert soon. - if (strcmp(arg, "!null") == 0) { - return nullptr; - } return (strcmp(arg, "!") == 0) ? nullptr : arg; } @@ -823,7 +920,8 @@ private: package_parameters_.compiler_filter, package_parameters_.volume_uuid, package_parameters_.shared_libraries, - package_parameters_.se_info); + package_parameters_.se_info, + package_parameters_.downgrade); } int RunPreopt() { diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp index aed068c390..2d58515b11 100644 --- a/cmds/installd/tests/installd_cache_test.cpp +++ b/cmds/installd/tests/installd_cache_test.cpp @@ -99,7 +99,7 @@ static int64_t size(const char* path) { static int64_t free() { struct statvfs buf; if (!statvfs("/data/local/tmp", &buf)) { - return buf.f_bavail * buf.f_frsize; + return static_cast<int64_t>(buf.f_bavail) * buf.f_frsize; } else { PLOG(ERROR) << "Failed to statvfs"; return -1; diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index dab32363c7..46ed85fd59 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -38,16 +38,6 @@ #define TEST_PROFILE_DIR "/data/misc/profiles" -#define REALLY_LONG_APP_NAME "com.example." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - -#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" - namespace android { namespace installd { @@ -88,6 +78,14 @@ protected: virtual void TearDown() { free(android_system_dirs.dirs); } + + std::string create_too_long_path(const std::string& seed) { + std::string result = seed; + for (size_t i = seed.size(); i < PKG_PATH_MAX; i++) { + result += "a"; + } + return result; + } }; TEST_F(UtilsTest, IsValidApkPath_BadPrefix) { @@ -388,17 +386,18 @@ TEST_F(UtilsTest, CreateMovePath_Primary) { << "Primary user package directory should be created correctly"; } + TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) { char path[PKG_PATH_MAX]; - - EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0)) + std::string really_long_app_name = create_too_long_path("com.example"); + EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0)) << "Should fail to create move path for primary user"; } TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) { char path[PKG_PATH_MAX]; - - EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0)) + std::string really_long_leaf_name = create_too_long_path("leaf_"); + EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0)) << "Should fail to create move path for primary user"; } @@ -560,7 +559,7 @@ TEST_F(UtilsTest, CreatePrimaryReferenceProfile) { } TEST_F(UtilsTest, CreateSecondaryCurrentProfile) { - EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof", + EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof", create_current_profile_path(/*user*/0, "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } @@ -571,5 +570,88 @@ TEST_F(UtilsTest, CreateSecondaryReferenceProfile) { "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } +static void pass_secondary_dex_validation(const std::string& package_name, + const std::string& dex_path, int uid, int storage_flag) { + EXPECT_TRUE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid, + storage_flag)) + << dex_path << " should be allowed as a valid secondary dex path"; +} + +static void fail_secondary_dex_validation(const std::string& package_name, + const std::string& dex_path, int uid, int storage_flag) { + EXPECT_FALSE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid, + storage_flag)) + << dex_path << " should not be allowed as a valid secondary dex path"; +} + +TEST_F(UtilsTest, ValidateSecondaryDexFilesPath) { + std::string package_name = "com.test.app"; + std::string app_dir_ce_user_0 = "/data/data/" + package_name; + std::string app_dir_ce_user_10 = "/data/user/10/" + package_name; + + std::string app_dir_de_user_0 = "/data/user_de/0/" + package_name; + std::string app_dir_de_user_10 = "/data/user_de/10/" + package_name; + + EXPECT_EQ(app_dir_ce_user_0, + create_data_user_ce_package_path(nullptr, 0, package_name.c_str())); + EXPECT_EQ(app_dir_ce_user_10, + create_data_user_ce_package_path(nullptr, 10, package_name.c_str())); + + EXPECT_EQ(app_dir_de_user_0, + create_data_user_de_package_path(nullptr, 0, package_name.c_str())); + EXPECT_EQ(app_dir_de_user_10, + create_data_user_de_package_path(nullptr, 10, package_name.c_str())); + + uid_t app_uid_for_user_0 = multiuser_get_uid(/*user_id*/0, /*app_id*/ 1234); + uid_t app_uid_for_user_10 = multiuser_get_uid(/*user_id*/10, /*app_id*/ 1234); + + // Standard path for user 0 on CE storage. + pass_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/ce0.dex", app_uid_for_user_0, FLAG_STORAGE_CE); + // Standard path for user 10 on CE storage. + pass_secondary_dex_validation( + package_name, app_dir_ce_user_10 + "/ce10.dex", app_uid_for_user_10, FLAG_STORAGE_CE); + + // Standard path for user 0 on DE storage. + pass_secondary_dex_validation( + package_name, app_dir_de_user_0 + "/de0.dex", app_uid_for_user_0, FLAG_STORAGE_DE); + // Standard path for user 10 on DE storage. + pass_secondary_dex_validation( + package_name, app_dir_de_user_10 + "/de0.dex", app_uid_for_user_10, FLAG_STORAGE_DE); + + // Dex path for user 0 accessed from user 10. + fail_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/path0_from10.dex", + app_uid_for_user_10, FLAG_STORAGE_CE); + + // Dex path for CE storage accessed with DE. + fail_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/ce_from_de.dex", app_uid_for_user_0, FLAG_STORAGE_DE); + + // Dex path for DE storage accessed with CE. + fail_secondary_dex_validation( + package_name, app_dir_de_user_0 + "/de_from_ce.dex", app_uid_for_user_0, FLAG_STORAGE_CE); + + // Location which does not start with '/'. + fail_secondary_dex_validation( + package_name, "without_slash.dex", app_uid_for_user_10, FLAG_STORAGE_DE); + + // The dex file is not in the specified package directory. + fail_secondary_dex_validation( + "another.package", app_dir_ce_user_0 + "/for_another_package.dex", + app_uid_for_user_0, FLAG_STORAGE_DE); + + // The dex path contains indirect directories. + fail_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/1/../foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE); + fail_secondary_dex_validation( + package_name, app_dir_ce_user_0 + "/1/./foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE); + + // Super long path. + std::string too_long = create_too_long_path("too_long_"); + fail_secondary_dex_validation( + package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE); +} + } // namespace installd } // namespace android diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 7c054173b9..d277bd3ad8 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -238,13 +238,38 @@ std::string create_data_dalvik_cache_path() { // Keep profile paths in sync with ActivityThread and LoadedApk. const std::string PROFILE_EXT = ".prof"; +const std::string CURRENT_PROFILE_EXT = ".cur"; const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT; +// Gets the parent directory and the file name for the given secondary dex path. +// Returns true on success, false on failure (if the dex_path does not have the expected +// structure). +static bool get_secondary_dex_location(const std::string& dex_path, + std::string* out_dir_name, std::string* out_file_name) { + size_t dirIndex = dex_path.rfind('/'); + if (dirIndex == std::string::npos) { + return false; + } + if (dirIndex == dex_path.size() - 1) { + return false; + } + *out_dir_name = dex_path.substr(0, dirIndex); + *out_file_name = dex_path.substr(dirIndex + 1); + + return true; +} + std::string create_current_profile_path(userid_t user, const std::string& location, bool is_secondary_dex) { if (is_secondary_dex) { - // Secondary dex profiles are stored next to the dex files using .prof extension. - return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str()); + // Secondary dex current profiles are stored next to the dex files under the oat folder. + std::string dex_dir; + std::string dex_name; + CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name)) + << "Unexpected dir structure for secondary dex " << location; + return StringPrintf("%s/oat/%s%s%s", + dex_dir.c_str(), dex_name.c_str(), CURRENT_PROFILE_EXT.c_str(), + PROFILE_EXT.c_str()); } else { // Profiles for primary apks are under /data/misc/profiles/cur. std::string profile_dir = create_primary_current_profile_package_dir_path(user, location); @@ -255,12 +280,10 @@ std::string create_current_profile_path(userid_t user, const std::string& locati std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) { if (is_secondary_dex) { // Secondary dex reference profiles are stored next to the dex files under the oat folder. - size_t dirIndex = location.rfind('/'); - CHECK(dirIndex != std::string::npos) + std::string dex_dir; + std::string dex_name; + CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name)) << "Unexpected dir structure for secondary dex " << location; - - std::string dex_dir = location.substr(0, dirIndex); - std::string dex_name = location.substr(dirIndex +1); return StringPrintf("%s/oat/%s%s", dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str()); } else { @@ -633,7 +656,7 @@ int copy_dir_files(const char *srcname, int64_t data_disk_free(const std::string& data_path) { struct statvfs sfs; if (statvfs(data_path.c_str(), &sfs) == 0) { - return sfs.f_bavail * sfs.f_frsize; + return static_cast<int64_t>(sfs.f_bavail) * sfs.f_frsize; } else { PLOG(ERROR) << "Couldn't statvfs " << data_path; return -1; @@ -781,21 +804,30 @@ bool validate_secondary_dex_path(const std::string& pkgname, const std::string& const char* volume_uuid, int uid, int storage_flag) { CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE); + // Empty paths are not allowed. + if (dex_path.empty()) { return false; } + // First character should always be '/'. No relative paths. + if (dex_path[0] != '/') { return false; } + // The last character should not be '/'. + if (dex_path[dex_path.size() - 1] == '/') { return false; } + // There should be no '.' after the directory marker. + if (dex_path.find("/.") != std::string::npos) { return false; } + // The path should be at most PKG_PATH_MAX long. + if (dex_path.size() > PKG_PATH_MAX) { return false; } + + // The dex_path should be under the app data directory. std::string app_private_dir = storage_flag == FLAG_STORAGE_CE ? create_data_user_ce_package_path( volume_uuid, multiuser_get_user_id(uid), pkgname.c_str()) : create_data_user_de_package_path( volume_uuid, multiuser_get_user_id(uid), pkgname.c_str()); - dir_rec_t dir; - if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) { - LOG(WARNING) << "Could not get dir rec for " << app_private_dir; + + if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) { return false; } - // Usually secondary dex files have a nested directory structure. - // Pick at most 10 subdirectories when validating (arbitrary value). - // If the secondary dex file is >10 directory nested then validation will - // fail and the file will not be compiled. - return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0; + + // If we got here we have a valid path. + return true; } /** diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 070da84c9e..da3a2933ec 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -36,6 +36,8 @@ #define BYPASS_QUOTA 0 #define BYPASS_SDCARDFS 0 +#define APPLY_HARD_QUOTAS 1 + namespace android { namespace installd { diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 35b63ec5c3..2b5389b8dc 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -505,7 +505,7 @@ status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegion ALOGV("Setting Transparent Region Hint"); Region re = Region(); - for (auto r : trhc.region()) { + for (const auto& r : trhc.region()) { Rect rect = Rect(r.left(), r.top(), r.right(), r.bottom()); re.merge(rect); } diff --git a/data/etc/android.hardware.radio.xml b/data/etc/android.hardware.broadcastradio.xml index f718c47cab..c66951805c 100644 --- a/data/etc/android.hardware.radio.xml +++ b/data/etc/android.hardware.broadcastradio.xml @@ -16,5 +16,5 @@ <!-- This is the standard set of features for a broadcast radio. --> <permissions> - <feature name="android.hardware.radio" /> + <feature name="android.hardware.broadcastradio" /> </permissions> diff --git a/headers/Android.bp b/headers/Android.bp new file mode 100644 index 0000000000..82bc8a15f7 --- /dev/null +++ b/headers/Android.bp @@ -0,0 +1,20 @@ +cc_library_headers { + name: "media_plugin_headers", + vendor_available: true, + export_include_dirs: [ + "media_plugin", + "media_plugin/media/openmax", + ], + header_libs: [ + "libstagefright_headers", + "libcutils_headers", + "libutils_headers", + "libstagefright_foundation_headers", + ], + export_header_lib_headers: [ + "libstagefright_headers", + "libcutils_headers", + "libutils_headers", + "libstagefright_foundation_headers", + ], +} diff --git a/include/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h index 67f4511e65..67f4511e65 100644 --- a/include/media/cas/CasAPI.h +++ b/headers/media_plugin/media/cas/CasAPI.h diff --git a/include/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h index 0a519525e0..0a519525e0 100644 --- a/include/media/cas/DescramblerAPI.h +++ b/headers/media_plugin/media/cas/DescramblerAPI.h diff --git a/include/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h index 985d919220..985d919220 100644 --- a/include/media/drm/DrmAPI.h +++ b/headers/media_plugin/media/drm/DrmAPI.h diff --git a/include/media/editor/II420ColorConverter.h b/headers/media_plugin/media/editor/II420ColorConverter.h index 33af61ff9a..33af61ff9a 100644 --- a/include/media/editor/II420ColorConverter.h +++ b/headers/media_plugin/media/editor/II420ColorConverter.h diff --git a/include/media/hardware/CryptoAPI.h b/headers/media_plugin/media/hardware/CryptoAPI.h index 0e86aacc6f..0e86aacc6f 100644 --- a/include/media/hardware/CryptoAPI.h +++ b/headers/media_plugin/media/hardware/CryptoAPI.h diff --git a/include/media/hardware/HDCPAPI.h b/headers/media_plugin/media/hardware/HDCPAPI.h index 7797bb2ab4..7797bb2ab4 100644 --- a/include/media/hardware/HDCPAPI.h +++ b/headers/media_plugin/media/hardware/HDCPAPI.h diff --git a/include/media/hardware/HardwareAPI.h b/headers/media_plugin/media/hardware/HardwareAPI.h index 6c1ba3de00..6c1ba3de00 100644 --- a/include/media/hardware/HardwareAPI.h +++ b/headers/media_plugin/media/hardware/HardwareAPI.h diff --git a/include/media/hardware/MetadataBufferType.h b/headers/media_plugin/media/hardware/MetadataBufferType.h index 4f6d5e2f26..4f6d5e2f26 100644 --- a/include/media/hardware/MetadataBufferType.h +++ b/headers/media_plugin/media/hardware/MetadataBufferType.h diff --git a/include/media/hardware/OMXPluginBase.h b/headers/media_plugin/media/hardware/OMXPluginBase.h index 7bf414739b..7bf414739b 100644 --- a/include/media/hardware/OMXPluginBase.h +++ b/headers/media_plugin/media/hardware/OMXPluginBase.h diff --git a/include/media/hardware/VideoAPI.h b/headers/media_plugin/media/hardware/VideoAPI.h index a09087698c..a09087698c 100644 --- a/include/media/hardware/VideoAPI.h +++ b/headers/media_plugin/media/hardware/VideoAPI.h diff --git a/include/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h index 56d7cc81ce..56d7cc81ce 100644 --- a/include/media/openmax/OMX_AsString.h +++ b/headers/media_plugin/media/openmax/OMX_AsString.h diff --git a/include/media/openmax/OMX_Audio.h b/headers/media_plugin/media/openmax/OMX_Audio.h index 9c0296bf55..9c0296bf55 100644 --- a/include/media/openmax/OMX_Audio.h +++ b/headers/media_plugin/media/openmax/OMX_Audio.h diff --git a/include/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h index 05c223212e..05c223212e 100644 --- a/include/media/openmax/OMX_AudioExt.h +++ b/headers/media_plugin/media/openmax/OMX_AudioExt.h diff --git a/include/media/openmax/OMX_Component.h b/headers/media_plugin/media/openmax/OMX_Component.h index 0dc2c76972..0dc2c76972 100644 --- a/include/media/openmax/OMX_Component.h +++ b/headers/media_plugin/media/openmax/OMX_Component.h diff --git a/include/media/openmax/OMX_ContentPipe.h b/headers/media_plugin/media/openmax/OMX_ContentPipe.h index 0224c8a2ee..0224c8a2ee 100644 --- a/include/media/openmax/OMX_ContentPipe.h +++ b/headers/media_plugin/media/openmax/OMX_ContentPipe.h diff --git a/include/media/openmax/OMX_Core.h b/headers/media_plugin/media/openmax/OMX_Core.h index bb974b3f88..bb974b3f88 100644 --- a/include/media/openmax/OMX_Core.h +++ b/headers/media_plugin/media/openmax/OMX_Core.h diff --git a/include/media/openmax/OMX_IVCommon.h b/headers/media_plugin/media/openmax/OMX_IVCommon.h index f9b6f4b0fd..f9b6f4b0fd 100644 --- a/include/media/openmax/OMX_IVCommon.h +++ b/headers/media_plugin/media/openmax/OMX_IVCommon.h diff --git a/include/media/openmax/OMX_Image.h b/headers/media_plugin/media/openmax/OMX_Image.h index 23a0209f5d..23a0209f5d 100644 --- a/include/media/openmax/OMX_Image.h +++ b/headers/media_plugin/media/openmax/OMX_Image.h diff --git a/include/media/openmax/OMX_Index.h b/headers/media_plugin/media/openmax/OMX_Index.h index 5be1355a96..5be1355a96 100644 --- a/include/media/openmax/OMX_Index.h +++ b/headers/media_plugin/media/openmax/OMX_Index.h diff --git a/include/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h index 5a029d0a4b..5a029d0a4b 100644 --- a/include/media/openmax/OMX_IndexExt.h +++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h diff --git a/include/media/openmax/OMX_Other.h b/headers/media_plugin/media/openmax/OMX_Other.h index 6072ef62c8..6072ef62c8 100644 --- a/include/media/openmax/OMX_Other.h +++ b/headers/media_plugin/media/openmax/OMX_Other.h diff --git a/include/media/openmax/OMX_Types.h b/headers/media_plugin/media/openmax/OMX_Types.h index 515e002213..515e002213 100644 --- a/include/media/openmax/OMX_Types.h +++ b/headers/media_plugin/media/openmax/OMX_Types.h diff --git a/include/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h index 76efac9b3e..76efac9b3e 100644 --- a/include/media/openmax/OMX_Video.h +++ b/headers/media_plugin/media/openmax/OMX_Video.h diff --git a/include/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h index 128dd2d1da..1a5ad176e2 100644 --- a/include/media/openmax/OMX_VideoExt.h +++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h @@ -58,6 +58,12 @@ typedef struct OMX_NALSTREAMFORMATTYPE{ OMX_NALUFORMATSTYPE eNaluFormat; } OMX_NALSTREAMFORMATTYPE; +/** AVC additional profiles */ +typedef enum OMX_VIDEO_AVCPROFILETYPEEXT { + OMX_VIDEO_AVCProfileConstrainedBaseline = 0x10000, /**< Constrained baseline profile */ + OMX_VIDEO_AVCProfileConstrainedHigh = 0x80000, /**< Constrained high profile */ +} OMX_VIDEO_AVCPROFILETYPEEXT; + /** VP8 profiles */ typedef enum OMX_VIDEO_VP8PROFILETYPE { OMX_VIDEO_VP8ProfileMain = 0x01, @@ -164,20 +170,20 @@ typedef enum OMX_VIDEO_VP9PROFILETYPE { /** VP9 levels */ typedef enum OMX_VIDEO_VP9LEVELTYPE { - OMX_VIDEO_VP9Level1 = 0x0, - OMX_VIDEO_VP9Level11 = 0x1, - OMX_VIDEO_VP9Level2 = 0x2, - OMX_VIDEO_VP9Level21 = 0x4, - OMX_VIDEO_VP9Level3 = 0x8, - OMX_VIDEO_VP9Level31 = 0x10, - OMX_VIDEO_VP9Level4 = 0x20, - OMX_VIDEO_VP9Level41 = 0x40, - OMX_VIDEO_VP9Level5 = 0x80, - OMX_VIDEO_VP9Level51 = 0x100, - OMX_VIDEO_VP9Level52 = 0x200, - OMX_VIDEO_VP9Level6 = 0x400, - OMX_VIDEO_VP9Level61 = 0x800, - OMX_VIDEO_VP9Level62 = 0x1000, + OMX_VIDEO_VP9Level1 = 0x1, + OMX_VIDEO_VP9Level11 = 0x2, + OMX_VIDEO_VP9Level2 = 0x4, + OMX_VIDEO_VP9Level21 = 0x8, + OMX_VIDEO_VP9Level3 = 0x10, + OMX_VIDEO_VP9Level31 = 0x20, + OMX_VIDEO_VP9Level4 = 0x40, + OMX_VIDEO_VP9Level41 = 0x80, + OMX_VIDEO_VP9Level5 = 0x100, + OMX_VIDEO_VP9Level51 = 0x200, + OMX_VIDEO_VP9Level52 = 0x400, + OMX_VIDEO_VP9Level6 = 0x800, + OMX_VIDEO_VP9Level61 = 0x1000, + OMX_VIDEO_VP9Level62 = 0x2000, OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF, OMX_VIDEO_VP9LevelMax = 0x7FFFFFFF } OMX_VIDEO_VP9LEVELTYPE; @@ -290,6 +296,8 @@ typedef enum OMX_VIDEO_DOLBYVISIONPROFILETYPE { OMX_VIDEO_DolbyVisionProfileDvheStn = 0x20, OMX_VIDEO_DolbyVisionProfileDvheDth = 0x40, OMX_VIDEO_DolbyVisionProfileDvheDtb = 0x80, + OMX_VIDEO_DolbyVisionProfileDvheSt = 0x100, + OMX_VIDEO_DolbyVisionProfileDvavSe = 0x200, OMX_VIDEO_DolbyVisionProfileMax = 0x7FFFFFFF } OMX_VIDEO_DOLBYVISIONPROFILETYPE; diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h new file mode 100644 index 0000000000..85ac78f9b1 --- /dev/null +++ b/include/android/sharedmem_jni.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup Memory + * @{ + */ + +/** + * @file sharedmem_jni.h + */ + +#ifndef ANDROID_SHARED_MEMORY_JNI_H +#define ANDROID_SHARED_MEMORY_JNI_H + +#include <jni.h> +#include <android/sharedmem.h> +#include <stddef.h> + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +/** + * Structures and functions for a shared memory buffer that can be shared across process. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if __ANDROID_API__ >= __ANDROID_API_O_MR1__ + +/** + * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file + * descriptor has all the same properties & capabilities as the FD returned from + * ASharedMemory_create(), however the protection flags will be the same as those of the + * android.os.SharedMemory object. + * + * Use close() to release the shared memory region. + * + * \param env The JNIEnv* pointer + * \param sharedMemory The Java android.os.SharedMemory object + * \return file descriptor that denotes the shared memory; -1 if the shared memory object is + * already closed, if the JNIEnv or jobject is NULL, or if there are too many open file + * descriptors (errno=EMFILE) + */ +int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory); + +#endif + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_SHARED_MEMORY_JNI_H + +/** @} */ diff --git a/include/batteryservice b/include/batteryservice new file mode 120000 index 0000000000..2178c32092 --- /dev/null +++ b/include/batteryservice @@ -0,0 +1 @@ +../services/batteryservice/include/batteryservice/
\ No newline at end of file diff --git a/include/media b/include/media new file mode 120000 index 0000000000..3e7da1c11f --- /dev/null +++ b/include/media @@ -0,0 +1 @@ +../headers/media_plugin/media
\ No newline at end of file diff --git a/include_sensor/android/looper.h b/include_sensor/android/looper.h new file mode 120000 index 0000000000..0cf51b88b5 --- /dev/null +++ b/include_sensor/android/looper.h @@ -0,0 +1 @@ +../../include/android/looper.h
\ No newline at end of file diff --git a/include_sensor/android/sensor.h b/include_sensor/android/sensor.h new file mode 120000 index 0000000000..0626f4f171 --- /dev/null +++ b/include_sensor/android/sensor.h @@ -0,0 +1 @@ +../../include/android/sensor.h
\ No newline at end of file diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 09fd0cb482..83b8021735 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -69,8 +69,13 @@ cc_library { "TextOutput.cpp", "IpPrefix.cpp", "Value.cpp", + "aidl/android/content/pm/IPackageManagerNative.aidl", ], + aidl: { + export_aidl_headers: true, + }, + cflags: [ "-Wall", "-Wextra", diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl new file mode 100644 index 0000000000..6b7254cbb3 --- /dev/null +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -0,0 +1,41 @@ +/* +** +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm; + +/** + * Parallel implementation of certain {@link PackageManager} APIs that need to + * be exposed to native code. + * <p>These APIs are a parallel definition to the APIs in PackageManager, so, + * they can technically diverge. However, it's good practice to keep these + * APIs in sync with each other. + * <p>Because these APIs are exposed to native code, it's possible they will + * be exposed to privileged components [such as UID 0]. Care should be taken + * to avoid exposing potential security holes for methods where permission + * checks are bypassed based upon UID alone. + * + * @hide + */ +interface IPackageManagerNative { + /** + * Returns a set of names for the given UIDs. + * IMPORTANT: Unlike the Java version of this API, unknown UIDs are + * not represented by 'null's. Instead, they are represented by empty + * strings. + */ + @utf8InCpp String[] getNamesForUids(in int[] uids); +} diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 4558fe87c6..21debc1a83 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -20,6 +20,9 @@ cc_library_headers { cc_library_shared { name: "libgui", vendor_available: true, + vndk: { + enabled: true, + }, clang: true, cppflags: [ @@ -93,6 +96,7 @@ cc_library_shared { "IProducerListener.cpp", "ISurfaceComposer.cpp", "ISurfaceComposerClient.cpp", + "LayerDebugInfo.cpp", "LayerState.cpp", "OccupancyTracker.cpp", "StreamSplitter.cpp", diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index d9d50dbeb4..da4295609b 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -19,6 +19,8 @@ //#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <utils/Log.h> +#include <inttypes.h> + #include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> @@ -31,13 +33,13 @@ namespace android { BufferItemConsumer::BufferItemConsumer( - const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage, + const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, int bufferCount, bool controlledByApp) : ConsumerBase(consumer, controlledByApp) { status_t err = mConsumer->setConsumerUsageBits(consumerUsage); LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set consumer usage bits to %#x", consumerUsage); + "Failed to set consumer usage bits to %#" PRIx64, consumerUsage); if (bufferCount != DEFAULT_MAX_BUFFERS) { err = mConsumer->setMaxAcquiredBufferCount(bufferCount); LOG_ALWAYS_FATAL_IF(err != OK, diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 3d94a029e5..c5cab2d730 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -347,10 +347,10 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, return NO_ERROR; } -status_t BufferQueueProducer::dequeueBuffer(int *outSlot, - sp<android::Fence> *outFence, uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage, - FrameEventHistoryDelta* outTimestamps) { +status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence, + uint32_t width, uint32_t height, PixelFormat format, + uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) { ATRACE_CALL(); { // Autolock scope Mutex::Autolock lock(mCore->mMutex); @@ -558,6 +558,9 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, mSlots[*outSlot].mFrameNumber, mSlots[*outSlot].mGraphicBuffer->handle, returnFlags); + if (outBufferAge) { + *outBufferAge = mCore->mBufferAge; + } addAndGetFrameTimestamps(nullptr, outTimestamps); return returnFlags; @@ -761,7 +764,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, &transform, &acquireFence, &stickyTransform, &getFrameTimestamps); - Region surfaceDamage = input.getSurfaceDamage(); + const Region& surfaceDamage = input.getSurfaceDamage(); if (acquireFence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); @@ -1099,6 +1102,7 @@ int BufferQueueProducer::query(int what, int *outValue) { value = (mCore->mQueue.size() > 1); break; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: + // deprecated; higher 32 bits are truncated value = static_cast<int32_t>(mCore->mConsumerUsageBits); break; case NATIVE_WINDOW_DEFAULT_DATASPACE: @@ -1544,4 +1548,12 @@ status_t BufferQueueProducer::getUniqueId(uint64_t* outId) const { return NO_ERROR; } +status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const { + BQ_LOGV("getConsumerUsage"); + + Mutex::Autolock lock(mCore->mMutex); + *outUsage = mCore->mConsumerUsageBits; + return NO_ERROR; +} + } // namespace android diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 34c9d7805a..14d9937142 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -43,7 +43,7 @@ #include <utils/String8.h> #include <utils/Trace.h> -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define CROP_EXT_STR "EGL_ANDROID_image_crop" #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" #define EGL_PROTECTED_CONTENT_EXT 0x32C0 @@ -1115,7 +1115,7 @@ status_t GLConsumer::setDefaultBufferDataSpace( return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); } -status_t GLConsumer::setConsumerUsageBits(uint32_t usage) { +status_t GLConsumer::setConsumerUsageBits(uint64_t usage) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!"); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 1b0fe06810..71e22cedf0 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -62,7 +62,8 @@ enum { SET_DEQUEUE_TIMEOUT, GET_LAST_QUEUED_BUFFER, GET_FRAME_TIMESTAMPS, - GET_UNIQUE_ID + GET_UNIQUE_ID, + GET_CONSUMER_USAGE, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -124,9 +125,9 @@ public: return result; } - virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width, - uint32_t height, PixelFormat format, uint64_t usage, - FrameEventHistoryDelta* outTimestamps) { + virtual status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height, + PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) { Parcel data, reply; bool getFrameTimestamps = (outTimestamps != nullptr); @@ -149,6 +150,17 @@ public: fence->clear(); return result; } + if (outBufferAge) { + result = reply.readUint64(outBufferAge); + } else { + // Read the value even if outBufferAge is nullptr: + uint64_t bufferAge; + result = reply.readUint64(&bufferAge); + } + if (result != NO_ERROR) { + ALOGE("IGBP::dequeueBuffer failed to read buffer age: %d", result); + return result; + } if (getFrameTimestamps) { result = reply.read(*outTimestamps); if (result != NO_ERROR) { @@ -493,6 +505,25 @@ public: } return actualResult; } + + virtual status_t getConsumerUsage(uint64_t* outUsage) const { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + status_t result = remote()->transact(GET_CONSUMER_USAGE, data, &reply); + if (result != NO_ERROR) { + ALOGE("getConsumerUsage failed to transact: %d", result); + } + status_t actualResult = NO_ERROR; + result = reply.readInt32(&actualResult); + if (result != NO_ERROR) { + return result; + } + result = reply.readUint64(outUsage); + if (result != NO_ERROR) { + return result; + } + return actualResult; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -516,11 +547,10 @@ public: return mBase->setAsyncMode(async); } - status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, - PixelFormat format, uint64_t usage, - FrameEventHistoryDelta* outTimestamps) override { - return mBase->dequeueBuffer( - slot, fence, w, h, format, usage, outTimestamps); + status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format, + uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) override { + return mBase->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps); } status_t detachBuffer(int slot) override { @@ -612,6 +642,10 @@ public: status_t getUniqueId(uint64_t* outId) const override { return mBase->getUniqueId(outId); } + + status_t getConsumerUsage(uint64_t* outUsage) const override { + return mBase->getConsumerUsage(outUsage); + } }; IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer, @@ -655,16 +689,18 @@ status_t BnGraphicBufferProducer::onTransact( uint32_t height = data.readUint32(); PixelFormat format = static_cast<PixelFormat>(data.readInt32()); uint64_t usage = data.readUint64(); + uint64_t bufferAge = 0; bool getTimestamps = data.readBool(); int buf = 0; sp<Fence> fence = Fence::NO_FENCE; FrameEventHistoryDelta frameTimestamps; - int result = dequeueBuffer(&buf, &fence, width, height, format, - usage, getTimestamps ? &frameTimestamps : nullptr); + int result = dequeueBuffer(&buf, &fence, width, height, format, usage, &bufferAge, + getTimestamps ? &frameTimestamps : nullptr); reply->writeInt32(buf); reply->write(*fence); + reply->writeUint64(bufferAge); if (getTimestamps) { reply->write(frameTimestamps); } @@ -877,6 +913,20 @@ status_t BnGraphicBufferProducer::onTransact( } return NO_ERROR; } + case GET_CONSUMER_USAGE: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + uint64_t outUsage = 0; + status_t actualResult = getConsumerUsage(&outUsage); + status_t result = reply->writeInt32(actualResult); + if (result != NO_ERROR) { + return result; + } + result = reply->writeUint64(outUsage); + if (result != NO_ERROR) { + return result; + } + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0a0d112af6..8e7f814313 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -28,6 +28,7 @@ #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> +#include <gui/LayerDebugInfo.h> #include <private/gui/LayerState.h> @@ -469,6 +470,36 @@ public: return result; } + virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const + { + if (!outLayers) { + return UNEXPECTED_NULL; + } + + Parcel data, reply; + + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + return err; + } + + err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply); + if (err != NO_ERROR) { + return err; + } + + int32_t result = 0; + err = reply.readInt32(&result); + if (err != NO_ERROR) { + return err; + } + if (result != NO_ERROR) { + return result; + } + + outLayers->clear(); + return reply.readParcelableVector(outLayers); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -763,6 +794,17 @@ status_t BnSurfaceComposer::onTransact( } return injectVSync(when); } + case GET_LAYER_DEBUG_INFO: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + std::vector<LayerDebugInfo> outLayers; + status_t result = getLayerDebugInfo(&outLayers); + reply->writeInt32(result); + if (result == NO_ERROR) + { + result = reply->writeParcelableVector(outLayers); + } + return result; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp new file mode 100644 index 0000000000..57ddde075a --- /dev/null +++ b/libs/gui/LayerDebugInfo.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/LayerDebugInfo.h> + +#include <ui/DebugUtils.h> + +#include <binder/Parcel.h> + +#include <utils/String8.h> + +using namespace android; + +#define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false) + +namespace android { + +status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { + RETURN_ON_ERROR(parcel->writeCString(mName.c_str())); + RETURN_ON_ERROR(parcel->writeCString(mParentName.c_str())); + RETURN_ON_ERROR(parcel->writeCString(mType.c_str())); + RETURN_ON_ERROR(parcel->write(mTransparentRegion)); + RETURN_ON_ERROR(parcel->write(mVisibleRegion)); + RETURN_ON_ERROR(parcel->write(mSurfaceDamageRegion)); + RETURN_ON_ERROR(parcel->writeUint32(mLayerStack)); + RETURN_ON_ERROR(parcel->writeFloat(mX)); + RETURN_ON_ERROR(parcel->writeFloat(mY)); + RETURN_ON_ERROR(parcel->writeUint32(mZ)); + RETURN_ON_ERROR(parcel->writeInt32(mWidth)); + RETURN_ON_ERROR(parcel->writeInt32(mHeight)); + RETURN_ON_ERROR(parcel->write(mCrop)); + RETURN_ON_ERROR(parcel->write(mFinalCrop)); + RETURN_ON_ERROR(parcel->writeFloat(mAlpha)); + RETURN_ON_ERROR(parcel->writeUint32(mFlags)); + RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat)); + RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace))); + for (size_t index = 0; index < 4; index++) { + RETURN_ON_ERROR(parcel->writeFloat(mMatrix[index / 2][index % 2])); + } + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferWidth)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferHeight)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferStride)); + RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferFormat)); + RETURN_ON_ERROR(parcel->writeInt32(mNumQueuedFrames)); + RETURN_ON_ERROR(parcel->writeBool(mRefreshPending)); + RETURN_ON_ERROR(parcel->writeBool(mIsOpaque)); + RETURN_ON_ERROR(parcel->writeBool(mContentDirty)); + return NO_ERROR; +} + +status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) { + mName = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + mParentName = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + mType = parcel->readCString(); + RETURN_ON_ERROR(parcel->errorCheck()); + RETURN_ON_ERROR(parcel->read(mTransparentRegion)); + RETURN_ON_ERROR(parcel->read(mVisibleRegion)); + RETURN_ON_ERROR(parcel->read(mSurfaceDamageRegion)); + RETURN_ON_ERROR(parcel->readUint32(&mLayerStack)); + RETURN_ON_ERROR(parcel->readFloat(&mX)); + RETURN_ON_ERROR(parcel->readFloat(&mY)); + RETURN_ON_ERROR(parcel->readUint32(&mZ)); + RETURN_ON_ERROR(parcel->readInt32(&mWidth)); + RETURN_ON_ERROR(parcel->readInt32(&mHeight)); + RETURN_ON_ERROR(parcel->read(mCrop)); + RETURN_ON_ERROR(parcel->read(mFinalCrop)); + RETURN_ON_ERROR(parcel->readFloat(&mAlpha)); + RETURN_ON_ERROR(parcel->readUint32(&mFlags)); + RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat)); + // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways? + mDataSpace = static_cast<android_dataspace>(parcel->readUint32()); + RETURN_ON_ERROR(parcel->errorCheck()); + for (size_t index = 0; index < 4; index++) { + RETURN_ON_ERROR(parcel->readFloat(&mMatrix[index / 2][index % 2])); + } + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferWidth)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferHeight)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferStride)); + RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferFormat)); + RETURN_ON_ERROR(parcel->readInt32(&mNumQueuedFrames)); + RETURN_ON_ERROR(parcel->readBool(&mRefreshPending)); + RETURN_ON_ERROR(parcel->readBool(&mIsOpaque)); + RETURN_ON_ERROR(parcel->readBool(&mContentDirty)); + return NO_ERROR; +} + +std::string to_string(const LayerDebugInfo& info) { + String8 result; + + result.appendFormat("+ %s (%s)\n", info.mType.c_str(), info.mName.c_str()); + info.mTransparentRegion.dump(result, "TransparentRegion"); + info.mVisibleRegion.dump(result, "VisibleRegion"); + info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion"); + + result.appendFormat(" layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ", + info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY), + info.mWidth, info.mHeight); + + result.appendFormat("crop=%s, finalCrop=%s, ", + to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str()); + result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty); + result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str()); + result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str()); + result.appendFormat("alpha=%.3f, flags=0x%08x, ", + static_cast<double>(info.mAlpha), info.mFlags); + result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]", + static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]), + static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1])); + result.append("\n"); + result.appendFormat(" parent=%s\n", info.mParentName.c_str()); + result.appendFormat(" activeBuffer=[%4ux%4u:%4u,%s],", + info.mActiveBufferWidth, info.mActiveBufferHeight, + info.mActiveBufferStride, + decodePixelFormat(info.mActiveBufferFormat).c_str()); + result.appendFormat(" queued-frames=%d, mRefreshPending=%d", + info.mNumQueuedFrames, info.mRefreshPending); + result.append("\n"); + return std::string(result.c_str()); +} + +} // android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 409a3cb076..5b1c599a13 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -44,21 +44,19 @@ namespace android { -Surface::Surface( - const sp<IGraphicBufferProducer>& bufferProducer, - bool controlledByApp) - : mGraphicBufferProducer(bufferProducer), - mCrop(Rect::EMPTY_RECT), - mGenerationNumber(0), - mSharedBufferMode(false), - mAutoRefresh(false), - mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT), - mSharedBufferHasBeenQueued(false), - mQueriedSupportedTimestamps(false), - mFrameTimestampsSupportsPresent(false), - mEnableFrameTimestamps(false), - mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) -{ +Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) + : mGraphicBufferProducer(bufferProducer), + mCrop(Rect::EMPTY_RECT), + mBufferAge(0), + mGenerationNumber(0), + mSharedBufferMode(false), + mAutoRefresh(false), + mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT), + mSharedBufferHasBeenQueued(false), + mQueriedSupportedTimestamps(false), + mFrameTimestampsSupportsPresent(false), + mEnableFrameTimestamps(false), + mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = hook_setSwapInterval; ANativeWindow::dequeueBuffer = hook_dequeueBuffer; @@ -506,9 +504,10 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { nsecs_t startTime = systemTime(); FrameEventHistoryDelta frameTimestamps; - status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, - reqWidth, reqHeight, reqFormat, reqUsage, - enableFrameTimestamps ? &frameTimestamps : nullptr); + status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight, + reqFormat, reqUsage, &mBufferAge, + enableFrameTimestamps ? &frameTimestamps + : nullptr); mLastDequeueDuration = systemTime() - startTime; if (result < 0) { @@ -845,6 +844,14 @@ int Surface::query(int what, int* value) const { } return err; } + case NATIVE_WINDOW_BUFFER_AGE: { + if (mBufferAge > INT32_MAX) { + *value = 0; + } else { + *value = static_cast<int32_t>(mBufferAge); + } + return NO_ERROR; + } case NATIVE_WINDOW_LAST_DEQUEUE_DURATION: { int64_t durationUs = mLastDequeueDuration / 1000; *value = durationUs > std::numeric_limits<int>::max() ? @@ -967,6 +974,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_USAGE64: res = dispatchSetUsage64(args); break; + case NATIVE_WINDOW_GET_CONSUMER_USAGE64: + res = dispatchGetConsumerUsage64(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1145,6 +1155,11 @@ int Surface::dispatchGetHdrSupport(va_list args) { return getHdrSupport(outSupport); } +int Surface::dispatchGetConsumerUsage64(va_list args) { + uint64_t* usage = va_arg(args, uint64_t*); + return getConsumerUsage(usage); +} + int Surface::connect(int api) { static sp<IProducerListener> listener = new DummyProducerListener(); return connect(api, listener); @@ -1714,6 +1729,11 @@ status_t Surface::getUniqueId(uint64_t* outId) const { return mGraphicBufferProducer->getUniqueId(outId); } +int Surface::getConsumerUsage(uint64_t* outUsage) const { + Mutex::Autolock lock(mMutex); + return mGraphicBufferProducer->getConsumerUsage(outUsage); +} + nsecs_t Surface::getLastDequeueStartTime() const { Mutex::Autolock lock(mMutex); return mLastDequeueStartTime; diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp index 187b211be8..afa15c5cda 100644 --- a/libs/gui/SyncFeatures.cpp +++ b/libs/gui/SyncFeatures.cpp @@ -27,7 +27,7 @@ #include <private/gui/SyncFeatures.h> -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp index 7c0552e0dc..3b89291dc8 100644 --- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp +++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp @@ -21,6 +21,8 @@ #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> #include <gui/bufferqueue/1.0/B2HProducerListener.h> +#include <system/window.h> + namespace android { namespace hardware { namespace graphics { @@ -989,10 +991,10 @@ status_t H2BGraphicBufferProducer::setAsyncMode(bool async) { } // FIXME: usage bits truncated -- needs a 64-bits usage version -status_t H2BGraphicBufferProducer::dequeueBuffer( - int* slot, sp<Fence>* fence, - uint32_t w, uint32_t h, ::android::PixelFormat format, - uint64_t usage, FrameEventHistoryDelta* outTimestamps) { +status_t H2BGraphicBufferProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, + uint32_t h, ::android::PixelFormat format, + uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) { *fence = new Fence(); status_t fnStatus; status_t transStatus = toStatusT(mBase->dequeueBuffer( @@ -1016,6 +1018,10 @@ status_t H2BGraphicBufferProducer::dequeueBuffer( fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus; } })); + if (outBufferAge) { + // Since the HAL version doesn't return the buffer age, set it to 0: + *outBufferAge = 0; + } return transStatus == NO_ERROR ? fnStatus : transStatus; } @@ -1228,6 +1234,18 @@ status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const { return transStatus == NO_ERROR ? fnStatus : transStatus; } +status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t* outUsage) const { + ALOGW("getConsumerUsage is not fully supported"); + int result; + status_t transStatus = toStatusT(mBase->query( + NATIVE_WINDOW_CONSUMER_USAGE_BITS, + [&result, outUsage] (int32_t tResult, int32_t tValue) { + result = static_cast<int>(tResult); + *outUsage = static_cast<uint64_t>(tValue); + })); + return transStatus == NO_ERROR ? result : static_cast<int>(transStatus); +} + } // namespace utils } // namespace V1_0 } // namespace bufferqueue diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index 217fe6ad81..d9c57757f5 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -52,7 +52,7 @@ class BufferItemConsumer: public ConsumerBase // controlledByApp tells whether this consumer is controlled by the // application. BufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, - uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, + uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, bool controlledByApp = false); ~BufferItemConsumer() override; diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 0f8917aa6d..5c7ffb416d 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -80,9 +80,10 @@ public: // // In both cases, the producer will need to call requestBuffer to get a // GraphicBuffer handle for the returned slot. - virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence, - uint32_t width, uint32_t height, PixelFormat format, - uint64_t usage, FrameEventHistoryDelta* outTimestamps) override; + virtual status_t dequeueBuffer(int* outSlot, sp<Fence>* outFence, uint32_t width, + uint32_t height, PixelFormat format, uint64_t usage, + uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) override; // See IGraphicBufferProducer::detachBuffer virtual status_t detachBuffer(int slot); @@ -182,6 +183,9 @@ public: // See IGraphicBufferProducer::getUniqueId virtual status_t getUniqueId(uint64_t* outId) const override; + // See IGraphicBufferProducer::getConsumerUsage + virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp<IBinder>& who); diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 2cf6162fd8..75f2ccaaea 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -210,7 +210,7 @@ public: // so the refactoring can proceed smoothly status_t setDefaultBufferFormat(PixelFormat defaultFormat); status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); - status_t setConsumerUsageBits(uint32_t usage); + status_t setConsumerUsageBits(uint64_t usage); status_t setTransformHint(uint32_t hint); status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); @@ -386,7 +386,7 @@ private: // BufferQueue instance; these will be OR:d with any additional flags passed // from the GLConsumer user. In particular, GLConsumer will always // consume buffers as hardware textures. - static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; + static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; // mCurrentTextureImage is the EglImage/buffer of the current texture. It's // possible that this buffer is not associated with any buffer slot, so we diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 6d16e7426c..039dc0d657 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -194,9 +194,9 @@ public: // // All other negative values are an unknown error returned downstream // from the graphics allocator (typically errno). - virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, - uint32_t h, PixelFormat format, uint64_t usage, - FrameEventHistoryDelta* outTimestamps) = 0; + virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, + PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) = 0; // detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be @@ -593,6 +593,12 @@ public: // Returns a unique id for this BufferQueue virtual status_t getUniqueId(uint64_t* outId) const = 0; + + // Returns the consumer usage flags for this BufferQueue. This returns the + // full 64-bit usage flags, rather than the truncated 32-bit usage flags + // returned by querying the now deprecated + // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. + virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index f80ba000b4..b2267426a8 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -39,6 +39,7 @@ struct ComposerState; struct DisplayState; struct DisplayInfo; struct DisplayStatInfo; +class LayerDebugInfo; class HdrCapabilities; class IDisplayEventConnection; class IGraphicBufferProducer; @@ -195,6 +196,12 @@ public: virtual status_t enableVSyncInjections(bool enable) = 0; virtual status_t injectVSync(nsecs_t when) = 0; + + /* Gets the list of active layers in Z order for debugging purposes + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0; }; // ---------------------------------------------------------------------------- @@ -229,6 +236,7 @@ public: SET_ACTIVE_COLOR_MODE, ENABLE_VSYNC_INJECTIONS, INJECT_VSYNC, + GET_LAYER_DEBUG_INFO, CREATE_SCOPED_CONNECTION }; diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h new file mode 100644 index 0000000000..8453e043ef --- /dev/null +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <binder/Parcelable.h> + +#include <ui/PixelFormat.h> +#include <ui/Region.h> + +#include <string> + +namespace android { + +/* Class for transporting debug info from SurfaceFlinger to authorized + * recipients. The class is intended to be a data container. There are + * no getters or setters. + */ +class LayerDebugInfo : public Parcelable { +public: + LayerDebugInfo() = default; + LayerDebugInfo(const LayerDebugInfo&) = default; + virtual ~LayerDebugInfo() = default; + + virtual status_t writeToParcel(Parcel* parcel) const; + virtual status_t readFromParcel(const Parcel* parcel); + + std::string mName = std::string("NOT FILLED"); + std::string mParentName = std::string("NOT FILLED"); + std::string mType = std::string("NOT FILLED"); + Region mTransparentRegion = Region::INVALID_REGION; + Region mVisibleRegion = Region::INVALID_REGION; + Region mSurfaceDamageRegion = Region::INVALID_REGION; + uint32_t mLayerStack = 0; + float mX = 0.f; + float mY = 0.f; + uint32_t mZ = 0 ; + int32_t mWidth = -1; + int32_t mHeight = -1; + Rect mCrop = Rect::INVALID_RECT; + Rect mFinalCrop = Rect::INVALID_RECT; + float mAlpha = 0.f; + uint32_t mFlags = 0; + PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; + android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + // Row-major transform matrix (SurfaceControl::setMatrix()) + float mMatrix[2][2] = {{0.f, 0.f}, {0.f, 0.f}}; + int32_t mActiveBufferWidth = -1; + int32_t mActiveBufferHeight = -1; + int32_t mActiveBufferStride = 0; + PixelFormat mActiveBufferFormat = PIXEL_FORMAT_NONE; + int32_t mNumQueuedFrames = -1; + bool mRefreshPending = false; + bool mIsOpaque = false; + bool mContentDirty = false; +}; + +std::string to_string(const LayerDebugInfo& info); + +} // namespace android diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0f7e12a228..55dd6bf067 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -159,6 +159,7 @@ public: status_t getHdrSupport(bool* supported); status_t getUniqueId(uint64_t* outId) const; + status_t getConsumerUsage(uint64_t* outUsage) const; // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call nsecs_t getLastDequeueStartTime() const; @@ -223,6 +224,7 @@ private: int dispatchGetFrameTimestamps(va_list args); int dispatchGetWideColorSupport(va_list args); int dispatchGetHdrSupport(va_list args); + int dispatchGetConsumerUsage64(va_list args); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); @@ -403,6 +405,10 @@ protected: // (the change since the previous frame) passed in by the producer. Region mDirtyRegion; + // mBufferAge tracks the age of the contents of the most recently dequeued + // buffer as the number of frames that have elapsed since it was last queued + uint64_t mBufferAge; + // Stores the current generation number. See setGenerationNumber and // IGraphicBufferProducer::setGenerationNumber for more information. uint32_t mGenerationNumber; diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 8bb705cf77..c15209d32c 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -90,6 +90,16 @@ public: status_t setFlags(uint32_t flags, uint32_t mask); status_t setTransparentRegionHint(const Region& transparent); status_t setAlpha(float alpha=1.0f); + + // Experimentarily it appears that the matrix transforms the + // on-screen rectangle and it's contents before the position is + // applied. + // + // TODO: Test with other combinations to find approximate transformation rules. + // + // For example: + // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives + // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y)) status_t setMatrix(float dsdx, float dtdx, float dtdy, float dsdy); status_t setCrop(const Rect& crop); status_t setFinalCrop(const Rect& crop); diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h index c3a9d443ec..74850b4879 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h @@ -64,9 +64,9 @@ struct H2BGraphicBufferProducer : public ::android::H2BConverter< status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override; status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override; status_t setAsyncMode(bool async) override; - status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, - uint32_t h, ::android::PixelFormat format, uint64_t usage, - FrameEventHistoryDelta* outTimestamps) override; + status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, + ::android::PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) override; status_t detachBuffer(int slot) override; status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override; @@ -94,6 +94,7 @@ struct H2BGraphicBufferProducer : public ::android::H2BConverter< sp<Fence>* outFence, float outTransformMatrix[16]) override; void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override; status_t getUniqueId(uint64_t* outId) const override; + status_t getConsumerUsage(uint64_t* outUsage) const override; }; } // namespace utils diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index d64e530488..b87cbbdec8 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -76,8 +76,8 @@ class BufferItemConsumerTest : public ::testing::Test { int slot; sp<Fence> outFence; - status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth, - kHeight, 0, 0, nullptr); + status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth, kHeight, 0, 0, + nullptr, nullptr); ASSERT_GE(ret, 0); ALOGV("dequeueBuffer: slot=%d", slot); diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 4220aafa07..9a208593ab 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -144,8 +144,8 @@ TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; @@ -188,16 +188,16 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); } ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); @@ -239,8 +239,8 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3)); for (int i = 0; i < 3; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); @@ -275,8 +275,8 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { BufferItem item; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); @@ -285,8 +285,8 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); @@ -335,8 +335,8 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); ASSERT_EQ(OK, mProducer->detachBuffer(slot)); @@ -384,8 +384,8 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), @@ -420,8 +420,8 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { EGL_NO_SYNC_KHR, Fence::NO_FENCE)); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataOut; @@ -443,8 +443,8 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; @@ -492,22 +492,24 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) { sp<GraphicBuffer> buffer; // This should return an error since it would require an allocation ASSERT_EQ(OK, mProducer->allowAllocation(false)); - ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, - 0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + ASSERT_EQ(WOULD_BLOCK, + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); // This should succeed, now that we've lifted the prohibition ASSERT_EQ(OK, mProducer->allowAllocation(true)); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); // Release the previous buffer back to the BufferQueue mProducer->cancelBuffer(slot, fence); // This should fail since we're requesting a different size ASSERT_EQ(OK, mProducer->allowAllocation(false)); - ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, - WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + ASSERT_EQ(WOULD_BLOCK, + mProducer->dequeueBuffer(&slot, &fence, WIDTH * 2, HEIGHT * 2, 0, + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr)); } TEST_F(BufferQueueTest, TestGenerationNumbers) { @@ -524,7 +526,7 @@ TEST_F(BufferQueueTest, TestGenerationNumbers) { int slot; sp<Fence> fence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); sp<GraphicBuffer> buffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); @@ -567,7 +569,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithoutAutoRefresh) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr)); + mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Queue the buffer @@ -581,8 +583,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithoutAutoRefresh) { // always the same one and because async mode gets enabled. int slot; for (int i = 0; i < 5; i++) { - ASSERT_EQ(OK, mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } @@ -619,7 +620,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithAutoRefresh) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr)); + mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Queue the buffer @@ -646,8 +647,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithAutoRefresh) { // always return the same one. int slot; for (int i = 0; i < 5; i++) { - ASSERT_EQ(OK, mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } @@ -686,7 +686,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeUsingAlreadyDequeuedBuffer) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr)); + mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Enable shared buffer mode @@ -703,8 +703,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeUsingAlreadyDequeuedBuffer) { // always the same one and because async mode gets enabled. int slot; for (int i = 0; i < 5; i++) { - ASSERT_EQ(OK, mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } @@ -739,8 +738,7 @@ TEST_F(BufferQueueTest, TestTimeouts) { for (int i = 0; i < 5; ++i) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence = Fence::NO_FENCE; - auto result = mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr); + auto result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr); if (i < 2) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); @@ -767,8 +765,7 @@ TEST_F(BufferQueueTest, TestTimeouts) { for (int i = 0; i < 2; ++i) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence = Fence::NO_FENCE; - ASSERT_EQ(OK, mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); IGraphicBufferProducer::QueueBufferInput input(0ull, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT, @@ -779,8 +776,7 @@ TEST_F(BufferQueueTest, TestTimeouts) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence = Fence::NO_FENCE; auto startTime = systemTime(); - ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_GE(systemTime() - startTime, TIMEOUT); // We're technically attaching the same buffer multiple times (since we @@ -801,7 +797,7 @@ TEST_F(BufferQueueTest, CanAttachWhileDisallowingAllocation) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> sourceFence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0, nullptr)); + mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0, nullptr, nullptr)); sp<GraphicBuffer> buffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); ASSERT_EQ(OK, mProducer->detachBuffer(slot)); @@ -824,7 +820,7 @@ TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); sp<GraphicBuffer> firstBuffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &firstBuffer)); @@ -836,7 +832,7 @@ TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) { // Dequeue a second buffer slot = BufferQueue::INVALID_BUFFER_SLOT; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); sp<GraphicBuffer> secondBuffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &secondBuffer)); @@ -887,8 +883,8 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { int slots[3] = {}; mProducer->setMaxDequeuedBufferCount(3); for (size_t i = 0; i < 3; ++i) { - status_t result = mProducer->dequeueBuffer(&slots[i], &fence, - 0, 0, 0, 0, nullptr); + status_t result = + mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer)); } @@ -901,8 +897,7 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { // The first segment is a two-buffer segment, so we only put one buffer into // the queue at a time for (size_t i = 0; i < 5; ++i) { - ASSERT_EQ(OK, mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, @@ -917,17 +912,16 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { // two-buffer segment, but then at the end, we put two buffers in the queue // at the same time before draining it. for (size_t i = 0; i < 5; ++i) { - ASSERT_EQ(OK, mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); std::this_thread::sleep_for(16ms); } - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, @@ -942,11 +936,10 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { // The third segment is a triple-buffer segment, so the queue is switching // between one buffer and two buffers deep. - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); for (size_t i = 0; i < 5; ++i) { - ASSERT_EQ(OK, mProducer->dequeueBuffer( - &slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, @@ -1026,8 +1019,8 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { int slots[4] = {}; mProducer->setMaxDequeuedBufferCount(4); for (size_t i = 0; i < 4; ++i) { - status_t result = mProducer->dequeueBuffer(&slots[i], &fence, - 0, 0, 0, 0, nullptr); + status_t result = + mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer)); } @@ -1038,14 +1031,14 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { // Get buffers in all states: dequeued, filled, acquired, free // Fill 3 buffers - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); // Dequeue 1 buffer - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); // Acquire and free 1 buffer ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); @@ -1104,8 +1097,8 @@ TEST_F(BufferQueueTest, TestBufferReplacedInQueueBuffer) { int slots[2] = {}; ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(2)); for (size_t i = 0; i < 2; ++i) { - status_t result = mProducer->dequeueBuffer(&slots[i], &fence, - 0, 0, 0, 0, nullptr); + status_t result = + mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer)); } @@ -1115,10 +1108,10 @@ TEST_F(BufferQueueTest, TestBufferReplacedInQueueBuffer) { // Fill 2 buffers without consumer consuming them. Verify that all // queued buffer returns proper bufferReplaced flag - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(false, output.bufferReplaced); - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(true, output.bufferReplaced); } @@ -1140,8 +1133,7 @@ TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) { NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); // Dequeue, request, and queue one buffer - status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, - nullptr); + status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); @@ -1156,7 +1148,7 @@ TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) { EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); // Dequeue and queue the buffer again - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); // Acquire and release the buffer again. Upon acquiring, the buffer handle @@ -1168,7 +1160,7 @@ TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) { EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); // Dequeue and queue the buffer again - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); // Disconnect the producer end. This should clear all of the slots and mark diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index bcfc91c3f5..dd23bd4cb2 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -194,7 +194,8 @@ protected: }; status_t dequeueBuffer(uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) { - return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage, nullptr); + return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage, + nullptr, nullptr); } void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence, @@ -206,9 +207,12 @@ protected: ASSERT_NO_FATAL_FAILURE(ConnectProducer()); - ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH, - DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr))); + + ASSERT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH, DEFAULT_HEIGHT, + DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, + nullptr, nullptr))); EXPECT_LE(0, *slot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, *slot); @@ -343,11 +347,11 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - - ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS, nullptr))); + ASSERT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, nullptr, nullptr))); EXPECT_LE(0, dequeuedSlot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot); @@ -403,10 +407,11 @@ TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS, nullptr))); + ASSERT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, nullptr, nullptr))); // Slot was enqueued without requesting a buffer { @@ -472,10 +477,11 @@ TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS, nullptr))); + ASSERT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, nullptr, nullptr))); // No return code, but at least test that it doesn't blow up... // TODO: add a return code @@ -519,12 +525,11 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; for (int i = 0; i < maxBuffers; ++i) { - - EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - DEFAULT_WIDTH, DEFAULT_HEIGHT, - DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS, nullptr))) + EXPECT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, nullptr, nullptr))) << "iteration: " << i << ", slot: " << dequeuedSlot; } @@ -557,11 +562,11 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; for (int i = 0; i < 2; i++) { - ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - DEFAULT_WIDTH, DEFAULT_HEIGHT, - DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS, nullptr))) + ASSERT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, nullptr, nullptr))) << "slot: " << dequeuedSlot; } @@ -593,10 +598,11 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { // Should now be able to queue/dequeue as many buffers as we want without // blocking for (int i = 0; i < 5; ++i) { - ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS, nullptr))) + ASSERT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, nullptr, nullptr))) << "slot : " << dequeuedSlot; ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer)); ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output)); @@ -610,10 +616,11 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS, nullptr))) + ASSERT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, nullptr, nullptr))) << "slot: " << dequeuedSlot; } @@ -630,8 +637,9 @@ TEST_F(IGraphicBufferProducerTest, int slot = -1; sp<Fence> fence; - ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, - DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr)); + ASSERT_EQ(NO_INIT, + mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)); } TEST_F(IGraphicBufferProducerTest, @@ -649,10 +657,11 @@ TEST_F(IGraphicBufferProducerTest, int slot = -1; sp<Fence> fence; - ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & - (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, - DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, - nullptr))); + ASSERT_EQ(OK, + ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, DEFAULT_HEIGHT, + DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, + nullptr, nullptr))); EXPECT_LE(0, slot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, slot); diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp index 6bc3ccf53d..bb6b8a59fe 100644 --- a/libs/gui/tests/Malicious.cpp +++ b/libs/gui/tests/Malicious.cpp @@ -38,8 +38,10 @@ public: } status_t setAsyncMode(bool async) override { return mProducer->setAsyncMode(async); } status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format, - uint64_t usage, FrameEventHistoryDelta* outTimestamps) override { - return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outTimestamps); + uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) override { + return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, + outTimestamps); } status_t detachBuffer(int slot) override { return mProducer->detachBuffer(slot); } status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override { @@ -90,6 +92,9 @@ public: } void getFrameTimestamps(FrameEventHistoryDelta*) override {} status_t getUniqueId(uint64_t* outId) const override { return mProducer->getUniqueId(outId); } + status_t getConsumerUsage(uint64_t* outUsage) const override { + return mProducer->getConsumerUsage(outUsage); + } protected: sp<IGraphicBufferProducer> mProducer; @@ -105,10 +110,10 @@ public: // Override dequeueBuffer, optionally corrupting the returned slot number status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage, + PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) override { EXPECT_EQ(BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(buf, fence, width, height, format, usage, + mProducer->dequeueBuffer(buf, fence, width, height, format, usage, outBufferAge, outTimestamps)); EXPECT_EQ(mExpectedSlot, *buf); if (mMaliciousValue != 0) { diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp index e2f494898e..ad6e051684 100644 --- a/libs/gui/tests/StreamSplitter_test.cpp +++ b/libs/gui/tests/StreamSplitter_test.cpp @@ -82,8 +82,8 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; @@ -116,8 +116,8 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { // This should succeed even with allocation disabled since it will have // received the buffer back from the output BufferQueue ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); } TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { @@ -154,8 +154,8 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; @@ -191,8 +191,8 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { // This should succeed even with allocation disabled since it will have // received the buffer back from the output BufferQueues ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); } TEST_F(StreamSplitterTest, OutputAbandonment) { @@ -218,8 +218,8 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); // Abandon the output @@ -231,8 +231,9 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); // Input should be abandoned - ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); + ASSERT_EQ(NO_INIT, + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr)); } } // namespace android diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index bd598e419e..d5b2f004ed 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -28,7 +28,7 @@ #include <utils/Log.h> #include <utils/Thread.h> -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define CROP_EXT_STR "EGL_ANDROID_image_crop" namespace android { diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e18af17bde..45e95a593b 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -539,6 +539,9 @@ public: return NO_ERROR; } status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; } + status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override { + return NO_ERROR; + } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 92944191c7..2f399765a0 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -34,6 +34,7 @@ cc_library { clang: true, shared_libs: [ + "libbase", "liblog", "libcutils", ], diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 7f6b1576cf..62acea360e 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -23,13 +23,14 @@ // Log debug messages about the progress of the algorithm itself. #define DEBUG_STRATEGY 0 -#include <math.h> +#include <inttypes.h> #include <limits.h> +#include <math.h> +#include <android-base/stringprintf.h> #include <cutils/properties.h> #include <input/VelocityTracker.h> #include <utils/BitSet.h> -#include <utils/String8.h> #include <utils/Timers.h> namespace android { @@ -46,8 +47,7 @@ static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS; static float vectorDot(const float* a, const float* b, uint32_t m) { float r = 0; - while (m) { - m--; + for (size_t i = 0; i < m; i++) { r += *(a++) * *(b++); } return r; @@ -55,8 +55,7 @@ static float vectorDot(const float* a, const float* b, uint32_t m) { static float vectorNorm(const float* a, uint32_t m) { float r = 0; - while (m) { - m--; + for (size_t i = 0; i < m; i++) { float t = *(a++); r += t * t; } @@ -64,36 +63,36 @@ static float vectorNorm(const float* a, uint32_t m) { } #if DEBUG_STRATEGY || DEBUG_VELOCITY -static String8 vectorToString(const float* a, uint32_t m) { - String8 str; - str.append("["); - while (m--) { - str.appendFormat(" %f", *(a++)); - if (m) { - str.append(","); +static std::string vectorToString(const float* a, uint32_t m) { + std::string str; + str += "["; + for (size_t i = 0; i < m; i++) { + if (i) { + str += ","; } + str += android::base::StringPrintf(" %f", *(a++)); } - str.append(" ]"); + str += " ]"; return str; } -static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { - String8 str; - str.append("["); +static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { + std::string str; + str = "["; for (size_t i = 0; i < m; i++) { if (i) { - str.append(","); + str += ","; } - str.append(" ["); + str += " ["; for (size_t j = 0; j < n; j++) { if (j) { - str.append(","); + str += ","; } - str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]); + str += android::base::StringPrintf(" %f", a[rowMajor ? i * n + j : j * m + i]); } - str.append(" ]"); + str += " ]"; } - str.append(" ]"); + str += " ]"; return str; } #endif @@ -244,7 +243,7 @@ void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Posi mStrategy->addMovement(eventTime, idBits, positions); #if DEBUG_VELOCITY - ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d", + ALOGD("VelocityTracker: addMovement eventTime=%" PRId64 ", idBits=0x%08x, activePointerId=%d", eventTime, idBits.value, mActivePointerId); for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) { uint32_t id = iterBits.firstMarkedBit(); @@ -256,8 +255,8 @@ void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Posi "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)", id, positions[index].x, positions[index].y, int(estimator.degree), - vectorToString(estimator.xCoeff, estimator.degree + 1).string(), - vectorToString(estimator.yCoeff, estimator.degree + 1).string(), + vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(), + vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(), estimator.confidence); } #endif @@ -443,8 +442,8 @@ static bool solveLeastSquares(const float* x, const float* y, const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) { #if DEBUG_STRATEGY ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), - vectorToString(x, m).string(), vectorToString(y, m).string(), - vectorToString(w, m).string()); + vectorToString(x, m).c_str(), vectorToString(y, m).c_str(), + vectorToString(w, m).c_str()); #endif // Expand the X vector to a matrix A, pre-multiplied by the weights. @@ -456,7 +455,7 @@ static bool solveLeastSquares(const float* x, const float* y, } } #if DEBUG_STRATEGY - ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string()); + ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str()); #endif // Apply the Gram-Schmidt process to A to obtain its QR decomposition. @@ -491,8 +490,8 @@ static bool solveLeastSquares(const float* x, const float* y, } } #if DEBUG_STRATEGY - ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string()); - ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string()); + ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str()); + ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str()); // calculate QR, if we factored A correctly then QR should equal A float qr[n][m]; @@ -504,7 +503,7 @@ static bool solveLeastSquares(const float* x, const float* y, } } } - ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string()); + ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str()); #endif // Solve R B = Qt W Y to find B. This is easy because R is upper triangular. @@ -522,7 +521,7 @@ static bool solveLeastSquares(const float* x, const float* y, outB[i] /= r[i][i]; } #if DEBUG_STRATEGY - ALOGD(" - b=%s", vectorToString(outB, n).string()); + ALOGD(" - b=%s", vectorToString(outB, n).c_str()); #endif // Calculate the coefficient of determination as 1 - (SSerr / SStot) where @@ -557,6 +556,46 @@ static bool solveLeastSquares(const float* x, const float* y, return true; } +/* + * Optimized unweighted second-order least squares fit. About 2x speed improvement compared to + * the default implementation + */ +static float solveUnweightedLeastSquaresDeg2(const float* x, const float* y, size_t count) { + float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0; + + for (size_t i = 0; i < count; i++) { + float xi = x[i]; + float yi = y[i]; + float xi2 = xi*xi; + float xi3 = xi2*xi; + float xi4 = xi3*xi; + float xi2yi = xi2*yi; + float xiyi = xi*yi; + + sxi += xi; + sxi2 += xi2; + sxiyi += xiyi; + sxi2yi += xi2yi; + syi += yi; + sxi3 += xi3; + sxi4 += xi4; + } + + float Sxx = sxi2 - sxi*sxi / count; + float Sxy = sxiyi - sxi*syi / count; + float Sxx2 = sxi3 - sxi*sxi2 / count; + float Sx2y = sxi2yi - sxi2*syi / count; + float Sx2x2 = sxi4 - sxi2*sxi2 / count; + + float numerator = Sxy*Sx2x2 - Sx2y*Sxx2; + float denominator = Sxx*Sx2x2 - Sxx2*Sxx2; + if (denominator == 0) { + ALOGW("division by 0 when computing velocity, Sxx=%f, Sx2x2=%f, Sxx2=%f", Sxx, Sx2x2, Sxx2); + return 0; + } + return numerator/denominator; +} + bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const { outEstimator->clear(); @@ -598,6 +637,19 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, degree = m - 1; } if (degree >= 1) { + if (degree == 2 && mWeighting == WEIGHTING_NONE) { // optimize unweighted, degree=2 fit + outEstimator->time = newestMovement.eventTime; + outEstimator->degree = 2; + outEstimator->confidence = 1; + outEstimator->xCoeff[0] = 0; // only slope is calculated, set rest of coefficients = 0 + outEstimator->yCoeff[0] = 0; + outEstimator->xCoeff[1] = solveUnweightedLeastSquaresDeg2(time, x, m); + outEstimator->yCoeff[1] = solveUnweightedLeastSquaresDeg2(time, y, m); + outEstimator->xCoeff[2] = 0; + outEstimator->yCoeff[2] = 0; + return true; + } + float xdet, ydet; uint32_t n = degree + 1; if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet) @@ -608,8 +660,8 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, #if DEBUG_STRATEGY ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", int(outEstimator->degree), - vectorToString(outEstimator->xCoeff, n).string(), - vectorToString(outEstimator->yCoeff, n).string(), + vectorToString(outEstimator->xCoeff, n).c_str(), + vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence); #endif return true; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 3df97a1b4a..64908049d6 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -115,7 +115,7 @@ enum { * The consumer gralloc usage bits currently set by the consumer. * The values are defined in hardware/libhardware/include/gralloc.h. */ - NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, + NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, /* deprecated */ /** * Transformation that will by applied to buffers by the hwcomposer. @@ -224,6 +224,7 @@ enum { NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, NATIVE_WINDOW_GET_HDR_SUPPORT = 29, NATIVE_WINDOW_SET_USAGE64 = 30, + NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, // clang-format on }; @@ -900,13 +901,18 @@ static inline int native_window_get_frame_timestamps( static inline int native_window_get_wide_color_support( struct ANativeWindow* window, bool* outSupport) { - return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT, - outSupport); + return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT, + outSupport); } static inline int native_window_get_hdr_support(struct ANativeWindow* window, bool* outSupport) { - return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport); + return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport); +} + +static inline int native_window_get_consumer_usage(struct ANativeWindow* window, + uint64_t* outUsage) { + return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage); } __END_DECLS diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 6630d9060a..cabe94ef78 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -15,6 +15,9 @@ cc_library_shared { name: "libui", vendor_available: true, + vndk: { + enabled: true, + }, clang: true, cppflags: [ diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index d5676cc2b8..2d72944665 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -16,10 +16,13 @@ #include <ui/DebugUtils.h> #include <ui/PixelFormat.h> +#include <ui/Rect.h> #include <android-base/stringprintf.h> #include <string> +using android::base::StringPrintf; + std::string decodeStandard(android_dataspace dataspace) { const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK); switch (dataspaceSelect) { @@ -187,7 +190,7 @@ std::string decodeRange(android_dataspace dataspace) { std::string dataspaceDetails(android_dataspace dataspace) { if (dataspace == 0) { - return "Default (0)"; + return "Default"; } return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(), decodeTransfer(dataspace).c_str(), @@ -262,3 +265,7 @@ std::string decodePixelFormat(android::PixelFormat format) { return android::base::StringPrintf("Unknown %#08x", format); } } + +std::string to_string(const android::Rect& rect) { + return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom); +} diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp index 39adc5e929..755e60c82e 100644 --- a/libs/ui/HdrCapabilities.cpp +++ b/libs/ui/HdrCapabilities.cpp @@ -76,7 +76,7 @@ status_t HdrCapabilities::unflatten(void const* buffer, size_t size) { mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]); mMinLuminance = reinterpret_cast<float const&>(buf[2]); if (itemCount) { - mSupportedHdrTypes.reserve(itemCount); + mSupportedHdrTypes.resize(itemCount); for (size_t i = 0; i < itemCount; ++i) { mSupportedHdrTypes[i] = buf[4 + i]; } diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h index 30f4a59fe0..dad9446b3a 100644 --- a/libs/ui/include/ui/DebugUtils.h +++ b/libs/ui/include/ui/DebugUtils.h @@ -21,9 +21,14 @@ #include <string> +namespace android { +class Rect; +} + std::string decodeStandard(android_dataspace dataspace); std::string decodeTransfer(android_dataspace dataspace); std::string decodeRange(android_dataspace dataspace); std::string dataspaceDetails(android_dataspace dataspace); std::string decodeColorMode(android_color_mode colormode); std::string decodePixelFormat(android::PixelFormat format); +std::string to_string(const android::Rect& rect); diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index bfb9a55e93..f9f87ff1b8 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp @@ -417,6 +417,28 @@ void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) { on_buffer_removed_ = callback; } +pdx::Status<void> BufferHubQueue::FreeAllBuffers() { + // Clear all available buffers. + available_buffers_.Clear(); + + pdx::Status<void> last_error; // No error. + // Clear all buffers this producer queue is tracking. + for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { + if (buffers_[slot] != nullptr) { + auto status = RemoveBuffer(slot); + if (!status) { + ALOGE( + "ProducerQueue::FreeAllBuffers: Failed to remove buffer at " + "slot=%d.", + slot); + last_error = status.error_status(); + } + } + } + + return last_error; +} + ProducerQueue::ProducerQueue(LocalChannelHandle handle) : BASE(std::move(handle)) { auto status = ImportQueue(); diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp index 0f75a5c3d8..53eed8924a 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp @@ -131,9 +131,9 @@ status_t BufferHubQueueProducer::setAsyncMode(bool async) { status_t BufferHubQueueProducer::dequeueBuffer( int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage, + PixelFormat format, uint64_t usage, uint64_t* /*outBufferAge*/, FrameEventHistoryDelta* /* out_timestamps */) { - ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%llu", width, + ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage); status_t ret; @@ -206,11 +206,11 @@ status_t BufferHubQueueProducer::dequeueBuffer( // It's either in free state (if the buffer has never been used before) or // in queued state (if the buffer has been dequeued and queued back to // BufferHubQueue). - // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's - // model. - LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() && - !buffers_[slot].mBufferState.isQueued()), - "dequeueBuffer: slot %zu is not free or queued.", slot); + LOG_ALWAYS_FATAL_IF( + (!buffers_[slot].mBufferState.isFree() && + !buffers_[slot].mBufferState.isQueued()), + "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot, + buffers_[slot].mBufferState.string()); buffers_[slot].mBufferState.freeQueued(); buffers_[slot].mBufferState.dequeue(); @@ -514,6 +514,7 @@ status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode /*mode*/) { return BAD_VALUE; } + FreeAllBuffers(); connected_api_ = kNoConnectedApi; return NO_ERROR; } @@ -608,6 +609,14 @@ status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const { return NO_ERROR; } +status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const { + ALOGD_IF(TRACE, __FUNCTION__); + + // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS + *out_usage = 0; + return NO_ERROR; +} + status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, PixelFormat format, @@ -647,5 +656,31 @@ status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) { return NO_ERROR; } +status_t BufferHubQueueProducer::FreeAllBuffers() { + for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { + // Reset in memory objects related the the buffer. + buffers_[slot].mGraphicBuffer = nullptr; + buffers_[slot].mBufferState.reset(); + buffers_[slot].mRequestBufferCalled = false; + buffers_[slot].mBufferProducer = nullptr; + buffers_[slot].mFence = Fence::NO_FENCE; + } + + auto status = queue_->FreeAllBuffers(); + if (!status) { + ALOGE( + "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on " + "the queue: %s", + status.GetErrorMessage().c_str()); + } + + if (queue_->capacity() != 0 || queue_->count() != 0) { + LOG_ALWAYS_FATAL( + "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed."); + } + + return NO_ERROR; +} + } // namespace dvr } // namespace android diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index d57c7af882..3e93788521 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h @@ -122,6 +122,10 @@ class BufferHubQueue : public pdx::Client { // to deregister a buffer for epoll and internal bookkeeping. virtual pdx::Status<void> RemoveBuffer(size_t slot); + // Free all buffers that belongs to this queue. Can only be called from + // producer side. + virtual pdx::Status<void> FreeAllBuffers(); + // Dequeue a buffer from the free queue, blocking until one is available. The // timeout argument specifies the number of milliseconds that |Dequeue()| will // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely, @@ -297,6 +301,11 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // Remove producer buffer from the queue. pdx::Status<void> RemoveBuffer(size_t slot) override; + // Free all buffers on this producer queue. + pdx::Status<void> FreeAllBuffers() override { + return BufferHubQueue::FreeAllBuffers(); + } + // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode, // and caller should call Post() once it's done writing to release the buffer // to the consumer side. diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h index 638a56caef..7ed55fb533 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h @@ -43,6 +43,7 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // See |IGraphicBufferProducer::dequeueBuffer| status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, + uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) override; // See |IGraphicBufferProducer::detachBuffer| @@ -111,6 +112,9 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // See |IGraphicBufferProducer::getUniqueId| status_t getUniqueId(uint64_t* out_id) const override; + // See |IGraphicBufferProducer::getConsumerUsage| + status_t getConsumerUsage(uint64_t* out_usage) const override; + private: using LocalHandle = pdx::LocalHandle; @@ -131,6 +135,10 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // Remove a buffer via BufferHubRPC. status_t RemoveBuffer(size_t slot); + // Free all buffers which are owned by the prodcuer. Note that if graphic + // buffers are acquired by the consumer, we can't . + status_t FreeAllBuffers(); + // Concreate implementation backed by BufferHubBuffer. std::shared_ptr<ProducerQueue> queue_; diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp index e0a4052ec2..7581a065b3 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp @@ -570,6 +570,103 @@ TEST_F(BufferHubQueueTest, TestQueueInfo) { EXPECT_EQ(consumer_queue_->is_async(), kIsAsync); } +TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { + constexpr size_t kBufferCount = 2; + +#define CHECK_NO_BUFFER_THEN_ALLOCATE(num_buffers) \ + EXPECT_EQ(consumer_queue_->count(), 0U); \ + EXPECT_EQ(consumer_queue_->capacity(), 0U); \ + EXPECT_EQ(producer_queue_->count(), 0U); \ + EXPECT_EQ(producer_queue_->capacity(), 0U); \ + for (size_t i = 0; i < num_buffers; i++) { \ + AllocateBuffer(); \ + } \ + EXPECT_EQ(producer_queue_->count(), num_buffers); \ + EXPECT_EQ(producer_queue_->capacity(), num_buffers); + + size_t slot; + uint64_t seq; + LocalHandle fence; + pdx::Status<void> status; + pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status; + pdx::Status<std::shared_ptr<BufferProducer>> producer_status; + std::shared_ptr<BufferConsumer> consumer_buffer; + std::shared_ptr<BufferProducer> producer_buffer; + + ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), + UsagePolicy{})); + + // Free all buffers when buffers are avaible for dequeue. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when one buffer is dequeued. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when all buffers are dequeued. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + for (size_t i = 0; i < kBufferCount; i++) { + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + } + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when one buffer is posted. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + producer_buffer = producer_status.take(); + ASSERT_NE(nullptr, producer_buffer); + ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when all buffers are posted. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + for (size_t i = 0; i < kBufferCount; i++) { + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + producer_buffer = producer_status.take(); + ASSERT_NE(nullptr, producer_buffer); + ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + } + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // Free all buffers when all buffers are acquired. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + for (size_t i = 0; i < kBufferCount; i++) { + producer_status = producer_queue_->Dequeue(0, &slot, &fence); + ASSERT_TRUE(producer_status.ok()); + producer_buffer = producer_status.take(); + ASSERT_NE(nullptr, producer_buffer); + ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence); + ASSERT_TRUE(consumer_status.ok()); + } + + status = producer_queue_->FreeAllBuffers(); + EXPECT_TRUE(status.ok()); + + // In addition to FreeAllBuffers() from the queue, it is also required to + // delete all references to the ProducerBuffer (i.e. the PDX client). + producer_buffer = nullptr; + + // Crank consumer queue events to pickup EPOLLHUP events on the queue. + consumer_queue_->HandleQueueEvents(); + + // One last check. + CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); + +#undef CHECK_NO_BUFFER_THEN_ALLOCATE +} + } // namespace } // namespace dvr diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp index c7692d05b0..28cd63af2d 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp @@ -117,9 +117,9 @@ class BufferHubQueueProducerTest : public ::testing::Test { ASSERT_NE(nullptr, outSlot); ASSERT_NE(nullptr, outFence); - int ret = mProducer->dequeueBuffer(outSlot, outFence, kDefaultWidth, - kDefaultHeight, kDefaultFormat, - kTestProducerUsageBits, nullptr); + int ret = mProducer->dequeueBuffer( + outSlot, outFence, kDefaultWidth, kDefaultHeight, kDefaultFormat, + kTestProducerUsageBits, nullptr, nullptr); // BUFFER_NEEDS_REALLOCATION can be either on or off. ASSERT_EQ(0, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & ret); @@ -440,9 +440,10 @@ TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Fails) { 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))) + (mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth, + kDefaultHeight, kDefaultFormat, + kTestProducerUsageBits, + nullptr, nullptr))) << "slot: " << slot; } @@ -458,7 +459,8 @@ TEST_F(BufferHubQueueProducerTest, ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth, kDefaultHeight, kDefaultFormat, - kTestProducerUsageBits, nullptr)); + kTestProducerUsageBits, + nullptr, nullptr)); } TEST_F(BufferHubQueueProducerTest, @@ -506,6 +508,44 @@ TEST_F(BufferHubQueueProducerTest, ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE)); } +TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) { + int slot = -1; + sp<GraphicBuffer> buffer; + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + + EXPECT_NO_FATAL_FAILURE(ConnectProducer()); + + constexpr int maxDequeuedBuffers = 1; + int minUndequeuedBuffers; + EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers)); + EXPECT_EQ(NO_ERROR, mProducer->setAsyncMode(false)); + EXPECT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers)); + + int maxCapacity = maxDequeuedBuffers + minUndequeuedBuffers; + + // Dequeue, request, and queue all buffers. + for (int i = 0; i < maxCapacity; i++) { + EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output)); + } + + // Disconnect then reconnect. + EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); + EXPECT_NO_FATAL_FAILURE(ConnectProducer()); + + // Dequeue, request, and queue all buffers. + for (int i = 0; i < maxCapacity; i++) { + EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); + EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); + EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output)); + } + + EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); +} + } // namespace } // namespace dvr diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp index 018abbb2a7..e4e20f9700 100644 --- a/libs/vr/libdvr/dvr_buffer_queue.cpp +++ b/libs/vr/libdvr/dvr_buffer_queue.cpp @@ -14,6 +14,8 @@ using android::dvr::BufferHubQueueProducer; using android::dvr::BufferProducer; using android::dvr::ConsumerQueue; using android::dvr::ProducerQueue; +using android::dvr::ProducerQueueConfigBuilder; +using android::dvr::UsagePolicy; extern "C" { @@ -156,6 +158,36 @@ int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) { return 0; } +int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format, + uint32_t layer_count, uint64_t usage, + size_t capacity, size_t metadata_size, + DvrWriteBufferQueue** out_write_queue) { + if (!out_write_queue) + return -EINVAL; + + auto config_builder = ProducerQueueConfigBuilder() + .SetDefaultWidth(width) + .SetDefaultHeight(height) + .SetDefaultFormat(format) + .SetMetadataSize(metadata_size); + std::unique_ptr<ProducerQueue> producer_queue = + ProducerQueue::Create(config_builder.Build(), UsagePolicy{}); + if (!producer_queue) { + ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue."); + return -ENOMEM; + } + + auto status = producer_queue->AllocateBuffers(width, height, layer_count, + format, usage, capacity); + if (!status.ok()) { + ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers."); + return -ENOMEM; + } + + *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue)); + return 0; +} + void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) { delete write_queue; } diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index d0dbd8d390..451d037352 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -159,6 +159,12 @@ typedef const struct native_handle* (*DvrBufferGetNativeHandlePtr)( DvrBuffer* buffer); // dvr_buffer_queue.h +typedef int (*DvrWriteBufferQueueCreatePtr)(uint32_t width, uint32_t height, + uint32_t format, + uint32_t layer_count, + uint64_t usage, size_t capacity, + size_t metadata_size, + DvrWriteBufferQueue** queue_out); typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue); typedef ssize_t (*DvrWriteBufferQueueGetCapacityPtr)( DvrWriteBufferQueue* write_queue); diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h index 72e0f674f4..da12c13065 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h +++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h @@ -160,3 +160,6 @@ DVR_V1_API_ENTRY(PoseClientSensorsEnable); // Read buffer queue DVR_V1_API_ENTRY(ReadBufferQueueGetEventFd); + +// Create write buffer queue locally +DVR_V1_API_ENTRY(WriteBufferQueueCreate); diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h index e2127f8e31..b3b41e2373 100644 --- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h +++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h @@ -12,6 +12,36 @@ typedef struct ANativeWindow ANativeWindow; typedef struct DvrWriteBufferQueue DvrWriteBufferQueue; typedef struct DvrReadBufferQueue DvrReadBufferQueue; +// Creates a write buffer queue to be used locally. +// +// Note that this API is mostly for testing purpose. For now there is no +// mechanism to send a DvrWriteBufferQueue cross process. Use +// dvrSurfaceCreateWriteBufferQueue if cross-process buffer transport is +// intended. +// +// @param width The width of the buffers that this queue will produce. +// @param height The height of buffers that this queue will produce. +// @param format The format of the buffers that this queue will produce. This +// must be one of the AHARDWAREBUFFER_FORMAT_XXX enums. +// @param layer_count The number of layers of the buffers that this queue will +// produce. +// @param usage The usage of the buffers that this queue will produce. This +// must a combination of the AHARDWAREBUFFER_USAGE_XXX flags. +// @param capacity The number of buffer that this queue will allocate. Note that +// all buffers will be allocated on create. Currently, the number of buffers +// is the queue cannot be changed after creation though DVR API. However, +// ANativeWindow can choose to reallocate, attach, or detach buffers from +// a DvrWriteBufferQueue through Android platform logic. +// @param metadata_size The size of metadata in bytes. +// @param out_write_queue The pointer of a DvrWriteBufferQueue will be filled +// here if the method call succeeds. The metadata size must match +// the metadata size in dvrWriteBufferPost/dvrReadBufferAcquire. +// @return Zero on success, or negative error code. +int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format, + uint32_t layer_count, uint64_t usage, + size_t capacity, size_t metadata_size, + DvrWriteBufferQueue** out_write_queue); + // Destroy a write buffer queue. // // @param write_queue The DvrWriteBufferQueue of interest. diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp index 16da1d9e54..7520eee70e 100644 --- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp +++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp @@ -1,24 +1,30 @@ +#include <android/log.h> +#include <android/native_window.h> +#include <android-base/unique_fd.h> #include <dvr/dvr_api.h> #include <dvr/dvr_buffer_queue.h> -#include <gui/Surface.h> -#include <private/dvr/buffer_hub_queue_client.h> -#include <base/logging.h> #include <gtest/gtest.h> -#include "../dvr_internal.h" -#include "../dvr_buffer_queue_internal.h" +#include <array> +#include <unordered_map> -namespace android { -namespace dvr { +#ifndef ALOGD +#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#endif + +#ifndef ALOGD_IF +#define ALOGD_IF(cond, ...) \ + ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0) +#endif namespace { static constexpr uint32_t kBufferWidth = 100; static constexpr uint32_t kBufferHeight = 1; static constexpr uint32_t kLayerCount = 1; -static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; -static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY; +static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB; +static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN; static constexpr size_t kQueueCapacity = 3; typedef uint64_t TestMeta; @@ -36,14 +42,6 @@ class DvrBufferQueueTest : public ::testing::Test { } protected: - void SetUp() override { - config_builder_ = ProducerQueueConfigBuilder() - .SetDefaultWidth(kBufferWidth) - .SetDefaultHeight(kBufferHeight) - .SetDefaultFormat(kBufferFormat) - .SetMetadata<TestMeta>(); - } - void TearDown() override { if (write_queue_ != nullptr) { dvrWriteBufferQueueDestroy(write_queue_); @@ -51,19 +49,6 @@ class DvrBufferQueueTest : public ::testing::Test { } } - void CreateWriteBufferQueue() { - write_queue_ = new DvrWriteBufferQueue( - ProducerQueue::Create(config_builder_.Build(), UsagePolicy{})); - ASSERT_NE(nullptr, write_queue_); - } - - void AllocateBuffers(size_t buffer_count) { - auto status = write_queue_->producer_queue()->AllocateBuffers( - kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage, - buffer_count); - ASSERT_TRUE(status.ok()); - } - void HandleBufferAvailable() { buffer_available_count_ += 1; ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_); @@ -75,22 +60,26 @@ class DvrBufferQueueTest : public ::testing::Test { buffer_removed_count_); } - ProducerQueueConfigBuilder config_builder_; DvrWriteBufferQueue* write_queue_{nullptr}; int buffer_available_count_{0}; int buffer_removed_count_{0}; }; TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); dvrWriteBufferQueueDestroy(write_queue_); write_queue_ = nullptr; } TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_); @@ -99,10 +88,13 @@ TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) { } TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue = nullptr; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); @@ -111,11 +103,14 @@ TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) { } TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue1 = nullptr; DvrReadBufferQueue* read_queue2 = nullptr; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue1); @@ -130,8 +125,10 @@ TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) { } TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBuffer* read_buffer = nullptr; DvrWriteBuffer* write_buffer = nullptr; @@ -164,8 +161,10 @@ TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) { } TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); static constexpr int kTimeout = 0; DvrReadBufferQueue* read_queue = nullptr; @@ -173,7 +172,7 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { DvrWriteBuffer* wb = nullptr; int fence_fd = -1; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); @@ -193,7 +192,7 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { ASSERT_TRUE(dvrWriteBufferIsValid(wb)); ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d", wb, fence_fd); - pdx::LocalHandle release_fence(fence_fd); + android::base::unique_fd release_fence(fence_fd); // Post buffer to the read_queue. TestMeta seq = 42U; @@ -215,7 +214,7 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb, fence_fd); - pdx::LocalHandle acquire_fence(fence_fd); + android::base::unique_fd acquire_fence(fence_fd); // Release buffer to the write_queue. ret = dvrReadBufferRelease(rb, -1); @@ -234,40 +233,52 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { } TEST_F(DvrBufferQueueTest, TestGetExternalSurface) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); ANativeWindow* window = nullptr; // The |write_queue_| doesn't have proper metadata (must be // DvrNativeBufferMetadata) configured during creation. - int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window); + ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window); ASSERT_EQ(-EINVAL, ret); ASSERT_EQ(nullptr, window); + dvrWriteBufferQueueDestroy(write_queue_); + write_queue_ = nullptr; // A write queue with DvrNativeBufferMetadata should work fine. - auto config = ProducerQueueConfigBuilder() - .SetMetadata<DvrNativeBufferMetadata>() - .Build(); - std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)> - write_queue( - new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})), - dvrWriteBufferQueueDestroy); - ASSERT_NE(nullptr, write_queue.get()); + ASSERT_EQ(nullptr, write_queue_); + + ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); + ASSERT_EQ(0, ret); + ASSERT_NE(nullptr, write_queue_); - ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window); + ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, window); - sp<Surface> surface = static_cast<Surface*>(window); - ASSERT_TRUE(Surface::isValid(surface)); + // TODO(b/64723700): Remove dependencies of Android platform bits so that we + // can run dvr_buffer_queue-test in DTS. + uint32_t width = ANativeWindow_getWidth(window); + uint32_t height = ANativeWindow_getHeight(window); + uint32_t format = ANativeWindow_getFormat(window); + ASSERT_EQ(kBufferWidth, width); + ASSERT_EQ(kBufferHeight, height); + ASSERT_EQ(kBufferFormat, format); } // Create buffer queue of three buffers and dequeue three buffers out of it. // Before each dequeue operation, we resize the buffer queue and expect the // queue always return buffer with desired dimension. TEST_F(DvrBufferQueueTest, TestResizeBuffer) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); static constexpr int kTimeout = 0; int fence_fd = -1; @@ -281,7 +292,7 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { AHardwareBuffer* ahb3 = nullptr; AHardwareBuffer_Desc buffer_desc; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); @@ -314,7 +325,7 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { ASSERT_EQ(0, ret); ASSERT_TRUE(dvrWriteBufferIsValid(wb1)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1); - pdx::LocalHandle release_fence1(fence_fd); + android::base::unique_fd release_fence1(fence_fd); // Check the buffer dimension. ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1); @@ -341,7 +352,7 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { ASSERT_TRUE(dvrWriteBufferIsValid(wb2)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2, fence_fd); - pdx::LocalHandle release_fence2(fence_fd); + android::base::unique_fd release_fence2(fence_fd); // Check the buffer dimension, should be new width ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2); @@ -367,7 +378,7 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { ASSERT_TRUE(dvrWriteBufferIsValid(wb3)); ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3, fence_fd); - pdx::LocalHandle release_fence3(fence_fd); + android::base::unique_fd release_fence3(fence_fd); // Check the buffer dimension, should be new width ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3); @@ -387,9 +398,10 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) { // Overrides default queue parameters: Empty metadata. - config_builder_.SetMetadata<void>(); - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/1, /*metadata_size=*/0, &write_queue_); + ASSERT_EQ(0, ret); DvrReadBuffer* rb = nullptr; DvrWriteBuffer* wb = nullptr; @@ -416,8 +428,10 @@ TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) { } TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + /*capacity=*/1, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBuffer* rb = nullptr; DvrWriteBuffer* wb = nullptr; @@ -451,11 +465,13 @@ TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) { } TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) { - ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue()); - ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity)); + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); DvrReadBufferQueue* read_queue = nullptr; - int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); + ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); ASSERT_EQ(0, ret); ASSERT_NE(nullptr, read_queue); @@ -464,7 +480,162 @@ TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) { ASSERT_GT(event_fd, 0); } -} // namespace +// Verifies a Dvr{Read,Write}BufferQueue contains the same set of +// Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id, +// the corresponding AHardwareBuffer handle stays the same. +TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) { + int ret = dvrWriteBufferQueueCreate( + kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, + kQueueCapacity, sizeof(TestMeta), &write_queue_); + ASSERT_EQ(0, ret); + + int fence_fd = -1; + DvrReadBufferQueue* read_queue = nullptr; + EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue)); -} // namespace dvr -} // namespace android + // Read buffers. + std::array<DvrReadBuffer*, kQueueCapacity> rbs; + // Write buffers. + std::array<DvrWriteBuffer*, kQueueCapacity> wbs; + // Hardware buffers for Read buffers. + std::unordered_map<int, AHardwareBuffer*> rhbs; + // Hardware buffers for Write buffers. + std::unordered_map<int, AHardwareBuffer*> whbs; + + for (size_t i = 0; i < kQueueCapacity; i++) { + dvrReadBufferCreateEmpty(&rbs[i]); + dvrWriteBufferCreateEmpty(&wbs[i]); + } + + constexpr int kNumTests = 100; + constexpr int kTimeout = 0; + TestMeta seq = 0U; + + // This test runs the following operations many many times. Thus we prefer to + // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output. + std::function<void(size_t i)> Gain = [&](size_t i) { + ASSERT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wbs[i], + &fence_fd)); + ASSERT_LT(fence_fd, 0); // expect invalid fence. + ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i])); + int buffer_id = dvrWriteBufferGetId(wbs[i]); + ASSERT_GT(buffer_id, 0); + + AHardwareBuffer* hb = nullptr; + ASSERT_EQ(0, dvrWriteBufferGetAHardwareBuffer(wbs[i], &hb)); + + auto whb_it = whbs.find(buffer_id); + if (whb_it == whbs.end()) { + // If this is a new buffer id, check that total number of unique + // hardware buffers won't exceed queue capacity. + ASSERT_LT(whbs.size(), kQueueCapacity); + whbs.emplace(buffer_id, hb); + } else { + // If this is a buffer id we have seen before, check that the + // buffer_id maps to the same AHardwareBuffer handle. + ASSERT_EQ(hb, whb_it->second); + } + }; + + std::function<void(size_t i)> Post = [&](size_t i) { + ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i])); + + seq++; + ASSERT_EQ(0, dvrWriteBufferPost(wbs[i], /*fence=*/-1, &seq, sizeof(seq))); + }; + + std::function<void(size_t i)> Acquire = [&](size_t i) { + TestMeta out_seq = 0U; + ASSERT_EQ(0, + dvrReadBufferQueueDequeue(read_queue, kTimeout, rbs[i], &fence_fd, + &out_seq, sizeof(out_seq))); + ASSERT_LT(fence_fd, 0); // expect invalid fence. + ASSERT_TRUE(dvrReadBufferIsValid(rbs[i])); + + int buffer_id = dvrReadBufferGetId(rbs[i]); + ASSERT_GT(buffer_id, 0); + + AHardwareBuffer* hb = nullptr; + ASSERT_EQ(0, dvrReadBufferGetAHardwareBuffer(rbs[i], &hb)); + + auto rhb_it = rhbs.find(buffer_id); + if (rhb_it == rhbs.end()) { + // If this is a new buffer id, check that total number of unique hardware + // buffers won't exceed queue capacity. + ASSERT_LT(rhbs.size(), kQueueCapacity); + rhbs.emplace(buffer_id, hb); + } else { + // If this is a buffer id we have seen before, check that the buffer_id + // maps to the same AHardwareBuffer handle. + ASSERT_EQ(hb, rhb_it->second); + } + }; + + std::function<void(size_t i)> Release = [&](size_t i) { + ASSERT_TRUE(dvrReadBufferIsValid(rbs[i])); + + seq++; + ASSERT_EQ(0, dvrReadBufferRelease(rbs[i], /*fence=*/-1)); + }; + + // Scenario one: + for (int i = 0; i < kNumTests; i++) { + // Gain all write buffers. + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Gain(i)); + } + // Post all write buffers. + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Post(i)); + } + // Acquire all read buffers. + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Acquire(i)); + } + // Release all read buffers. + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Release(i)); + } + } + + // Scenario two: + for (int i = 0; i < kNumTests; i++) { + // Gain and post all write buffers. + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Gain(i)); + ASSERT_NO_FATAL_FAILURE(Post(i)); + } + // Acquire and release all read buffers. + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Acquire(i)); + ASSERT_NO_FATAL_FAILURE(Release(i)); + } + } + + // Scenario three: + for (int i = 0; i < kNumTests; i++) { + // Gain all write buffers then post them in reversed order. + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Gain(i)); + } + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Post(kQueueCapacity - 1 - i)); + } + + // Acquire all write buffers then release them in reversed order. + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Acquire(i)); + } + for (size_t i = 0; i < kQueueCapacity; i++) { + ASSERT_NO_FATAL_FAILURE(Release(kQueueCapacity - 1 - i)); + } + } + + // Clean up all read buffers and write buffers. + for (size_t i = 0; i < kQueueCapacity; i++) { + dvrReadBufferDestroy(rbs[i]); + dvrWriteBufferDestroy(wbs[i]); + } +} + +} // namespace diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp index f55e9942db..8fce140307 100644 --- a/libs/vr/libpdx/Android.bp +++ b/libs/vr/libpdx/Android.bp @@ -5,12 +5,15 @@ cc_library_static { "-Wall", "-Wextra", "-Werror", + "-DLOG_TAG=\"libpdx\"", + "-DTRACE=0", ], export_include_dirs: ["private"], local_include_dirs: ["private"], srcs: [ "client.cpp", "service.cpp", + "service_dispatcher.cpp", "status.cpp", ], } diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp index bfa2d879b5..a01c4d67ec 100644 --- a/libs/vr/libpdx/client.cpp +++ b/libs/vr/libpdx/client.cpp @@ -1,6 +1,5 @@ #include "pdx/client.h" -#define LOG_TAG "ServiceFramework" #include <log/log.h> #include <pdx/trace.h> diff --git a/libs/vr/libpdx/mock_tests.cpp b/libs/vr/libpdx/mock_tests.cpp index 76fd1541a5..4143837cb4 100644 --- a/libs/vr/libpdx/mock_tests.cpp +++ b/libs/vr/libpdx/mock_tests.cpp @@ -3,7 +3,6 @@ #include <pdx/mock_client_channel_factory.h> #include <pdx/mock_message_reader.h> #include <pdx/mock_message_writer.h> -#include <pdx/mock_service_dispatcher.h> #include <pdx/mock_service_endpoint.h> TEST(MockTypes, Instantiation) { @@ -15,6 +14,5 @@ TEST(MockTypes, Instantiation) { android::pdx::MockMessageReader message_reader; android::pdx::MockOutputResourceMapper output_resource_mapper; android::pdx::MockMessageWriter message_writer; - android::pdx::MockServiceDispatcher service_dispatcher; android::pdx::MockEndpoint endpoint; } diff --git a/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h b/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h deleted file mode 100644 index 9b51d30592..0000000000 --- a/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_ -#define ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_ - -#include <gmock/gmock.h> -#include <pdx/service_dispatcher.h> - -namespace android { -namespace pdx { - -class MockServiceDispatcher : public ServiceDispatcher { - public: - MOCK_METHOD1(AddService, int(const std::shared_ptr<Service>& service)); - MOCK_METHOD1(RemoveService, int(const std::shared_ptr<Service>& service)); - MOCK_METHOD0(ReceiveAndDispatch, int()); - MOCK_METHOD1(ReceiveAndDispatch, int(int timeout)); - MOCK_METHOD0(EnterDispatchLoop, int()); - MOCK_METHOD1(SetCanceled, void(bool cancel)); - MOCK_CONST_METHOD0(IsCanceled, bool()); -}; - -} // namespace pdx -} // namespace android - -#endif // ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_ diff --git a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h index e741d4a46b..7f829e70d0 100644 --- a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h +++ b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h @@ -66,6 +66,7 @@ class MockEndpoint : public Endpoint { MOCK_METHOD0(AllocateMessageState, void*()); MOCK_METHOD1(FreeMessageState, void(void* state)); MOCK_METHOD0(Cancel, Status<void>()); + MOCK_CONST_METHOD0(epoll_fd, int()); }; } // namespace pdx diff --git a/libs/vr/libpdx/private/pdx/service_dispatcher.h b/libs/vr/libpdx/private/pdx/service_dispatcher.h index c5e342af0c..bd27000dc9 100644 --- a/libs/vr/libpdx/private/pdx/service_dispatcher.h +++ b/libs/vr/libpdx/private/pdx/service_dispatcher.h @@ -2,6 +2,11 @@ #define ANDROID_PDX_SERVICE_DISPATCHER_H_ #include <memory> +#include <mutex> +#include <unordered_map> +#include <vector> + +#include <pdx/file_handle.h> namespace android { namespace pdx { @@ -15,7 +20,10 @@ class Service; */ class ServiceDispatcher { public: - virtual ~ServiceDispatcher() = default; + // Get a new instance of ServiceDispatcher, or return nullptr if init failed. + static std::unique_ptr<ServiceDispatcher> Create(); + + ~ServiceDispatcher(); /* * Adds a service to the list of services handled by this dispatcher. This @@ -24,7 +32,7 @@ class ServiceDispatcher { * * Returns 0 on success; -EEXIST if the service was already added. */ - virtual int AddService(const std::shared_ptr<Service>& service) = 0; + int AddService(const std::shared_ptr<Service>& service); /* * Removes a service from this dispatcher. This will fail if any threads are @@ -33,7 +41,7 @@ class ServiceDispatcher { * Returns 0 on success; -ENOENT if the service was not previously added; * -EBUSY if there are threads in the dispatcher. */ - virtual int RemoveService(const std::shared_ptr<Service>& service) = 0; + int RemoveService(const std::shared_ptr<Service>& service); /* * Receive and dispatch one set of messages. Multiple threads may enter this @@ -42,14 +50,14 @@ class ServiceDispatcher { * cycle, requiring an external loop. This is useful when other work needs * to be done in the service dispatch loop. */ - virtual int ReceiveAndDispatch() = 0; + int ReceiveAndDispatch(); /* * Same as above with timeout in milliseconds. A negative value means * infinite timeout, while a value of 0 means return immediately if no * messages are available to receive. */ - virtual int ReceiveAndDispatch(int timeout) = 0; + int ReceiveAndDispatch(int timeout); /* * Receive and dispatch messages until canceled. When more than one thread @@ -58,19 +66,39 @@ class ServiceDispatcher { * hands Message instances (via move assignment) over to a queue of threads * (or perhaps one of several) to handle. */ - virtual int EnterDispatchLoop() = 0; + int EnterDispatchLoop(); /* * Sets the canceled state of the dispatcher. When canceled is true, any * threads blocked waiting for messages will return. This method waits until * all dispatch threads have exited the dispatcher. */ - virtual void SetCanceled(bool cancel) = 0; + void SetCanceled(bool cancel); /* * Gets the canceled state of the dispatcher. */ - virtual bool IsCanceled() const = 0; + bool IsCanceled() const; + + private: + ServiceDispatcher(); + + // Internal thread accounting. + int ThreadEnter(); + void ThreadExit(); + + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> canceled_{false}; + + std::vector<std::shared_ptr<Service>> services_; + + int thread_count_ = 0; + LocalHandle event_fd_; + LocalHandle epoll_fd_; + + ServiceDispatcher(const ServiceDispatcher&) = delete; + void operator=(const ServiceDispatcher&) = delete; }; } // namespace pdx diff --git a/libs/vr/libpdx/private/pdx/service_endpoint.h b/libs/vr/libpdx/private/pdx/service_endpoint.h index 28bd6bc454..d58189499c 100644 --- a/libs/vr/libpdx/private/pdx/service_endpoint.h +++ b/libs/vr/libpdx/private/pdx/service_endpoint.h @@ -136,6 +136,10 @@ class Endpoint { // Cancels the endpoint, unblocking any receiver threads waiting for a // message. virtual Status<void> Cancel() = 0; + + // Returns an fd that can be used with epoll() to wait for incoming messages + // from this endpoint. + virtual int epoll_fd() const = 0; }; } // namespace pdx diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp index fab4770b7f..1d3b62ac08 100644 --- a/libs/vr/libpdx/service.cpp +++ b/libs/vr/libpdx/service.cpp @@ -1,4 +1,3 @@ -#define LOG_TAG "ServiceFramework" #include "pdx/service.h" #include <fcntl.h> @@ -10,8 +9,6 @@ #include <pdx/trace.h> -#define TRACE 0 - namespace android { namespace pdx { diff --git a/libs/vr/libpdx_uds/service_dispatcher.cpp b/libs/vr/libpdx/service_dispatcher.cpp index 2c52578d1c..b112fa30eb 100644 --- a/libs/vr/libpdx_uds/service_dispatcher.cpp +++ b/libs/vr/libpdx/service_dispatcher.cpp @@ -1,26 +1,25 @@ -#include "uds/service_dispatcher.h" +#include <pdx/service_dispatcher.h> #include <errno.h> #include <log/log.h> #include <sys/epoll.h> #include <sys/eventfd.h> -#include "pdx/service.h" -#include "uds/service_endpoint.h" +#include <pdx/service.h> +#include <pdx/service_endpoint.h> static const int kMaxEventsPerLoop = 128; namespace android { namespace pdx { -namespace uds { -std::unique_ptr<pdx::ServiceDispatcher> ServiceDispatcher::Create() { +std::unique_ptr<ServiceDispatcher> ServiceDispatcher::Create() { std::unique_ptr<ServiceDispatcher> dispatcher{new ServiceDispatcher()}; if (!dispatcher->epoll_fd_ || !dispatcher->event_fd_) { dispatcher.reset(); } - return std::move(dispatcher); + return dispatcher; } ServiceDispatcher::ServiceDispatcher() { @@ -70,18 +69,14 @@ void ServiceDispatcher::ThreadExit() { } int ServiceDispatcher::AddService(const std::shared_ptr<Service>& service) { - if (service->endpoint()->GetIpcTag() != Endpoint::kIpcTag) - return -EINVAL; - std::lock_guard<std::mutex> autolock(mutex_); - auto* endpoint = static_cast<Endpoint*>(service->endpoint()); epoll_event event; event.events = EPOLLIN; event.data.ptr = service.get(); - if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, endpoint->epoll_fd(), &event) < - 0) { + if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, service->endpoint()->epoll_fd(), + &event) < 0) { ALOGE("Failed to add service to dispatcher because: %s\n", strerror(errno)); return -errno; } @@ -91,9 +86,6 @@ int ServiceDispatcher::AddService(const std::shared_ptr<Service>& service) { } int ServiceDispatcher::RemoveService(const std::shared_ptr<Service>& service) { - if (service->endpoint()->GetIpcTag() != Endpoint::kIpcTag) - return -EINVAL; - std::lock_guard<std::mutex> autolock(mutex_); // It's dangerous to remove a service while other threads may be using it. @@ -101,16 +93,15 @@ int ServiceDispatcher::RemoveService(const std::shared_ptr<Service>& service) { return -EBUSY; epoll_event dummy; // See BUGS in man 2 epoll_ctl. - - auto* endpoint = static_cast<Endpoint*>(service->endpoint()); - if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, endpoint->epoll_fd(), &dummy) < - 0) { + if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, service->endpoint()->epoll_fd(), + &dummy) < 0) { ALOGE("Failed to remove service from dispatcher because: %s\n", strerror(errno)); return -errno; } - services_.remove(service); + services_.erase(std::remove(services_.begin(), services_.end(), service), + services_.end()); return 0; } @@ -139,7 +130,7 @@ int ServiceDispatcher::ReceiveAndDispatch(int timeout) { Service* service = static_cast<Service*>(events[i].data.ptr); ALOGI_IF(TRACE, "Dispatching message: fd=%d\n", - static_cast<Endpoint*>(service->endpoint())->epoll_fd()); + service->endpoint()->epoll_fd()); service->ReceiveAndDispatch(); } } @@ -171,7 +162,7 @@ int ServiceDispatcher::EnterDispatchLoop() { Service* service = static_cast<Service*>(events[i].data.ptr); ALOGI_IF(TRACE, "Dispatching message: fd=%d\n", - static_cast<Endpoint*>(service->endpoint())->epoll_fd()); + service->endpoint()->epoll_fd()); service->ReceiveAndDispatch(); } } @@ -197,6 +188,5 @@ void ServiceDispatcher::SetCanceled(bool cancel) { bool ServiceDispatcher::IsCanceled() const { return canceled_; } -} // namespace uds } // namespace pdx } // namespace android diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp index 8cfa86fa44..0f6511b362 100644 --- a/libs/vr/libpdx_default_transport/Android.bp +++ b/libs/vr/libpdx_default_transport/Android.bp @@ -36,10 +36,10 @@ cc_library_static { } cc_binary { - name: "servicetool", + name: "pdx_tool", defaults: ["pdx_default_transport_compiler_defaults"], srcs: [ - "servicetool.cpp", + "pdx_tool.cpp", ], shared_libs: [ "liblog", diff --git a/libs/vr/libpdx_default_transport/servicetool.cpp b/libs/vr/libpdx_default_transport/pdx_tool.cpp index 60eedb3847..60eedb3847 100644 --- a/libs/vr/libpdx_default_transport/servicetool.cpp +++ b/libs/vr/libpdx_default_transport/pdx_tool.cpp diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h deleted file mode 100644 index 158871c892..0000000000 --- a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_ -#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_ - -#include <servicefs/service_dispatcher.h> - -namespace android { -namespace pdx { -namespace default_transport { - -using ServiceDispatcher = ::android::pdx::servicefs::ServiceDispatcher; - -} // namespace default_transport -} // namespace pdx -} // namespace android - - -#endif // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_ diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h deleted file mode 100644 index 7cb7a80fe7..0000000000 --- a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_ -#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_ - -#include <uds/service_dispatcher.h> - -namespace android { -namespace pdx { -namespace default_transport { - -using ServiceDispatcher = ::android::pdx::uds::ServiceDispatcher; - -} // namespace default_transport -} // namespace pdx -} // namespace android - - -#endif // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_ diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp index 82a5ea7526..d0b7cab34f 100644 --- a/libs/vr/libpdx_uds/Android.bp +++ b/libs/vr/libpdx_uds/Android.bp @@ -16,7 +16,6 @@ cc_library_static { "client_channel_factory.cpp", "client_channel.cpp", "ipc_helper.cpp", - "service_dispatcher.cpp", "service_endpoint.cpp", ], static_libs: [ diff --git a/libs/vr/libpdx_uds/client_channel_tests.cpp b/libs/vr/libpdx_uds/client_channel_tests.cpp index 7c3c68aa31..15600305a1 100644 --- a/libs/vr/libpdx_uds/client_channel_tests.cpp +++ b/libs/vr/libpdx_uds/client_channel_tests.cpp @@ -13,6 +13,7 @@ #include <pdx/client.h> #include <pdx/rpc/remote_method.h> #include <pdx/service.h> +#include <pdx/service_dispatcher.h> #include <uds/client_channel_factory.h> #include <uds/service_endpoint.h> @@ -81,7 +82,7 @@ class TestServiceRunner { auto endpoint = Endpoint::CreateFromSocketFd(LocalHandle{}); endpoint->RegisterNewChannelForTests(std::move(channel_socket)); service_ = TestService::Create(std::move(endpoint)); - dispatcher_ = android::pdx::uds::ServiceDispatcher::Create(); + dispatcher_ = ServiceDispatcher::Create(); dispatcher_->AddService(service_); dispatch_thread_ = std::thread( std::bind(&ServiceDispatcher::EnterDispatchLoop, dispatcher_.get())); diff --git a/libs/vr/libpdx_uds/private/uds/service_dispatcher.h b/libs/vr/libpdx_uds/private/uds/service_dispatcher.h deleted file mode 100644 index 23af4f4403..0000000000 --- a/libs/vr/libpdx_uds/private/uds/service_dispatcher.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_ -#define ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_ - -#include <list> -#include <memory> -#include <mutex> -#include <unordered_map> - -#include <pdx/file_handle.h> -#include <pdx/service_dispatcher.h> - -namespace android { -namespace pdx { -namespace uds { - -class ServiceDispatcher : public pdx::ServiceDispatcher { - public: - // Get a new instance of ServiceDispatcher, or return nullptr if init failed. - static std::unique_ptr<pdx::ServiceDispatcher> Create(); - - ~ServiceDispatcher() override; - int AddService(const std::shared_ptr<Service>& service) override; - int RemoveService(const std::shared_ptr<Service>& service) override; - int ReceiveAndDispatch() override; - int ReceiveAndDispatch(int timeout) override; - int EnterDispatchLoop() override; - void SetCanceled(bool cancel) override; - bool IsCanceled() const override; - - private: - ServiceDispatcher(); - - // Internal thread accounting. - int ThreadEnter(); - void ThreadExit(); - - std::mutex mutex_; - std::condition_variable condition_; - std::atomic<bool> canceled_{false}; - - std::list<std::shared_ptr<Service>> services_; - - int thread_count_ = 0; - LocalHandle event_fd_; - LocalHandle epoll_fd_; - - ServiceDispatcher(const ServiceDispatcher&) = delete; - void operator=(const ServiceDispatcher&) = delete; -}; - -} // namespace uds -} // namespace pdx -} // namespace android - -#endif // ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_ diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h index 368891ce05..a163812702 100644 --- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h +++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h @@ -12,7 +12,6 @@ #include <pdx/service.h> #include <pdx/service_endpoint.h> #include <uds/channel_event_set.h> -#include <uds/service_dispatcher.h> namespace android { namespace pdx { @@ -105,7 +104,7 @@ class Endpoint : public pdx::Endpoint { // socket file descriptor. Status<void> RegisterNewChannelForTests(LocalHandle channel_fd); - int epoll_fd() const { return epoll_fd_.Get(); } + int epoll_fd() const override { return epoll_fd_.Get(); } private: struct ChannelData { diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp index 3109753dc2..3f25776e14 100644 --- a/libs/vr/libpdx_uds/remote_method_tests.cpp +++ b/libs/vr/libpdx_uds/remote_method_tests.cpp @@ -15,9 +15,9 @@ #include <pdx/rpc/remote_method.h> #include <pdx/rpc/serializable.h> #include <pdx/service.h> +#include <pdx/service_dispatcher.h> #include <uds/client_channel.h> #include <uds/client_channel_factory.h> -#include <uds/service_dispatcher.h> #include <uds/service_endpoint.h> using android::pdx::BorrowedHandle; @@ -561,7 +561,7 @@ class RemoteMethodTest : public ::testing::Test { void SetUp() override { // Create a dispatcher to handle messages to services. - dispatcher_ = android::pdx::uds::ServiceDispatcher::Create(); + dispatcher_ = android::pdx::ServiceDispatcher::Create(); ASSERT_NE(nullptr, dispatcher_); // Start the message dispatch loop in a separate thread. diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp index 2943239495..5943b0a1be 100644 --- a/libs/vr/libpdx_uds/service_framework_tests.cpp +++ b/libs/vr/libpdx_uds/service_framework_tests.cpp @@ -16,10 +16,10 @@ #include <pdx/client.h> #include <pdx/file_handle.h> #include <pdx/service.h> +#include <pdx/service_dispatcher.h> #include <private/android_filesystem_config.h> #include <uds/client_channel.h> #include <uds/client_channel_factory.h> -#include <uds/service_dispatcher.h> #include <uds/service_endpoint.h> using android::pdx::BorrowedChannelHandle; @@ -425,7 +425,7 @@ class ServiceFrameworkTest : public ::testing::Test { void SetUp() override { // Create a dispatcher to handle messages to services. - dispatcher_ = android::pdx::uds::ServiceDispatcher::Create(); + dispatcher_ = android::pdx::ServiceDispatcher::Create(); ASSERT_NE(nullptr, dispatcher_); // Start the message dispatch loop in a separate thread. diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 733edc659c..af18e218d5 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -40,10 +40,8 @@ namespace dvr { DisplayService::DisplayService(Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) : BASE("DisplayService", - Endpoint::Create(display::DisplayProtocol::kClientPath)), - hardware_composer_(hidl, request_display_callback), - request_display_callback_(request_display_callback) { - hardware_composer_.Initialize(); + Endpoint::Create(display::DisplayProtocol::kClientPath)) { + hardware_composer_.Initialize(hidl, request_display_callback); } bool DisplayService::IsInitialized() const { @@ -245,18 +243,16 @@ Status<display::SurfaceInfo> DisplayService::OnCreateSurface( surface_status.GetErrorMessage().c_str()); return ErrorStatus(surface_status.error()); } + auto surface = surface_status.take(); + message.SetChannel(surface); - SurfaceType surface_type = surface_status.get()->surface_type(); - display::SurfaceUpdateFlags update_flags = - surface_status.get()->update_flags(); - display::SurfaceInfo surface_info{surface_status.get()->surface_id(), - surface_status.get()->visible(), - surface_status.get()->z_order()}; + // Update the surface with the attributes supplied with the create call. For + // application surfaces this has the side effect of notifying the display + // manager of the new surface. For direct surfaces, this may trigger a mode + // change, depending on the value of the visible attribute. + surface->OnSetAttributes(message, attributes); - message.SetChannel(surface_status.take()); - - SurfaceUpdated(surface_type, update_flags); - return {surface_info}; + return {{surface->surface_id(), surface->visible(), surface->z_order()}}; } void DisplayService::SurfaceUpdated(SurfaceType surface_type, @@ -398,10 +394,6 @@ pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) { return {0}; } -void DisplayService::OnHardwareComposerRefresh() { - hardware_composer_.OnHardwareComposerRefresh(); -} - void DisplayService::SetDisplayConfigurationUpdateNotifier( DisplayConfigurationUpdateNotifier update_notifier) { update_notifier_ = update_notifier; diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 6efe264b09..55e33ab852 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -72,8 +72,6 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { void GrantDisplayOwnership() { hardware_composer_.Enable(); } void SeizeDisplayOwnership() { hardware_composer_.Disable(); } - void OnHardwareComposerRefresh(); - private: friend BASE; friend DisplaySurface; @@ -119,7 +117,6 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { pdx::Status<void> HandleSurfaceMessage(pdx::Message& message); HardwareComposer hardware_composer_; - RequestDisplayCallback request_display_callback_; EpollEventDispatcher dispatcher_; DisplayConfigurationUpdateNotifier update_notifier_; diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp index 0d6a732a8e..685378133e 100644 --- a/libs/vr/libvrflinger/display_surface.cpp +++ b/libs/vr/libvrflinger/display_surface.cpp @@ -26,14 +26,12 @@ namespace dvr { DisplaySurface::DisplaySurface(DisplayService* service, SurfaceType surface_type, int surface_id, - int process_id, int user_id, - const display::SurfaceAttributes& attributes) + int process_id, int user_id) : service_(service), surface_type_(surface_type), surface_id_(surface_id), process_id_(process_id), user_id_(user_id), - attributes_(attributes), update_flags_(display::SurfaceUpdateFlags::NewSurface) {} DisplaySurface::~DisplaySurface() { @@ -301,6 +299,9 @@ Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue( } direct_queue_ = producer->CreateConsumerQueue(); + if (direct_queue_->metadata_size() > 0) { + metadata_.reset(new uint8_t[direct_queue_->metadata_size()]); + } auto status = RegisterQueue(direct_queue_); if (!status) { ALOGE( @@ -345,7 +346,12 @@ void DirectDisplaySurface::DequeueBuffersLocked() { while (true) { LocalHandle acquire_fence; size_t slot; - auto buffer_status = direct_queue_->Dequeue(0, &slot, &acquire_fence); + auto buffer_status = direct_queue_->Dequeue( + 0, &slot, metadata_.get(), + direct_queue_->metadata_size(), &acquire_fence); + ALOGD_IF(TRACE, + "DirectDisplaySurface::DequeueBuffersLocked: Dequeue with metadata_size: %zu", + direct_queue_->metadata_size()); if (!buffer_status) { ALOGD_IF( TRACE > 1 && buffer_status.error() == ETIMEDOUT, @@ -463,8 +469,8 @@ Status<std::shared_ptr<DisplaySurface>> DisplaySurface::Create( if (direct) { const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id); if (trusted) { - return {std::shared_ptr<DisplaySurface>{new DirectDisplaySurface( - service, surface_id, process_id, user_id, attributes)}}; + return {std::shared_ptr<DisplaySurface>{ + new DirectDisplaySurface(service, surface_id, process_id, user_id)}}; } else { ALOGE( "DisplaySurface::Create: Direct surfaces may only be created by " @@ -474,7 +480,7 @@ Status<std::shared_ptr<DisplaySurface>> DisplaySurface::Create( } } else { return {std::shared_ptr<DisplaySurface>{new ApplicationDisplaySurface( - service, surface_id, process_id, user_id, attributes)}}; + service, surface_id, process_id, user_id)}}; } } diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h index 5cbee57bf9..c8b1a078f7 100644 --- a/libs/vr/libvrflinger/display_surface.h +++ b/libs/vr/libvrflinger/display_surface.h @@ -53,8 +53,7 @@ class DisplaySurface : public pdx::Channel { protected: DisplaySurface(DisplayService* service, SurfaceType surface_type, - int surface_id, int process_id, int user_id, - const display::SurfaceAttributes& attributes); + int surface_id, int process_id, int user_id); // Utility to retrieve a shared pointer to this channel as the desired derived // type. @@ -119,10 +118,9 @@ class DisplaySurface : public pdx::Channel { class ApplicationDisplaySurface : public DisplaySurface { public: ApplicationDisplaySurface(DisplayService* service, int surface_id, - int process_id, int user_id, - const display::SurfaceAttributes& attributes) + int process_id, int user_id) : DisplaySurface(service, SurfaceType::Application, surface_id, - process_id, user_id, attributes) {} + process_id, user_id) {} std::shared_ptr<ConsumerQueue> GetQueue(int32_t queue_id); std::vector<int32_t> GetQueueIds() const override; @@ -140,11 +138,11 @@ class ApplicationDisplaySurface : public DisplaySurface { class DirectDisplaySurface : public DisplaySurface { public: DirectDisplaySurface(DisplayService* service, int surface_id, int process_id, - int user_id, - const display::SurfaceAttributes& attributes) + int user_id) : DisplaySurface(service, SurfaceType::Direct, surface_id, process_id, - user_id, attributes), - acquired_buffers_(kMaxPostedBuffers) {} + user_id), + acquired_buffers_(kMaxPostedBuffers), + metadata_(nullptr) {} std::vector<int32_t> GetQueueIds() const override; bool IsBufferAvailable(); bool IsBufferPosted(); @@ -179,6 +177,9 @@ class DirectDisplaySurface : public DisplaySurface { RingBuffer<AcquiredBuffer> acquired_buffers_; std::shared_ptr<ConsumerQueue> direct_queue_; + + // Stores metadata when it dequeue buffers from consumer queue. + std::unique_ptr<uint8_t[]> metadata_; }; } // namespace dvr diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index def9b7da33..f9a5dcd987 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -28,6 +28,8 @@ #include <private/dvr/clock_ns.h> #include <private/dvr/ion_buffer.h> +using android::hardware::Return; +using android::hardware::Void; using android::pdx::LocalHandle; using android::pdx::rpc::EmptyVariant; using android::pdx::rpc::IfAnyOf; @@ -42,9 +44,6 @@ namespace { const char kBacklightBrightnessSysFile[] = "/sys/class/leds/lcd-backlight/brightness"; -const char kPrimaryDisplayVSyncEventFile[] = - "/sys/class/graphics/fb0/vsync_event"; - const char kPrimaryDisplayWaitPPEventFile[] = "/sys/class/graphics/fb0/wait_pp"; const char kDvrPerformanceProperty[] = "sys.dvr.performance"; @@ -86,22 +85,11 @@ bool SetThreadPolicy(const std::string& scheduler_class, } // anonymous namespace -// Layer static data. -Hwc2::Composer* Layer::hwc2_hidl_; -const HWCDisplayMetrics* Layer::display_metrics_; - // HardwareComposer static data; constexpr size_t HardwareComposer::kMaxHardwareLayers; HardwareComposer::HardwareComposer() - : HardwareComposer(nullptr, RequestDisplayCallback()) {} - -HardwareComposer::HardwareComposer( - Hwc2::Composer* hwc2_hidl, RequestDisplayCallback request_display_callback) - : initialized_(false), - hwc2_hidl_(hwc2_hidl), - request_display_callback_(request_display_callback), - callbacks_(new ComposerCallback) {} + : initialized_(false), request_display_callback_(nullptr) {} HardwareComposer::~HardwareComposer(void) { UpdatePostThreadState(PostThreadState::Quit, true); @@ -109,16 +97,19 @@ HardwareComposer::~HardwareComposer(void) { post_thread_.join(); } -bool HardwareComposer::Initialize() { +bool HardwareComposer::Initialize( + Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) { if (initialized_) { ALOGE("HardwareComposer::Initialize: already initialized."); return false; } + request_display_callback_ = request_display_callback; + HWC::Error error = HWC::Error::None; Hwc2::Config config; - error = hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); + error = hidl->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); if (error != HWC::Error::None) { ALOGE("HardwareComposer: Failed to get current display config : %d", @@ -126,8 +117,8 @@ bool HardwareComposer::Initialize() { return false; } - error = - GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_); + error = GetDisplayMetrics(hidl, HWC_DISPLAY_PRIMARY, config, + &native_display_metrics_); if (error != HWC::Error::None) { ALOGE( @@ -149,9 +140,6 @@ bool HardwareComposer::Initialize() { display_transform_ = HWC_TRANSFORM_NONE; display_metrics_ = native_display_metrics_; - // Pass hwc instance and metrics to setup globals for Layer. - Layer::InitializeGlobals(hwc2_hidl_, &native_display_metrics_); - post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); LOG_ALWAYS_FATAL_IF( !post_thread_event_fd_, @@ -210,15 +198,11 @@ void HardwareComposer::UpdatePostThreadState(PostThreadStateType state, } void HardwareComposer::OnPostThreadResumed() { - hwc2_hidl_->resetCommands(); + hidl_.reset(new Hwc2::Composer("default")); + hidl_callback_ = new ComposerCallback; + hidl_->registerCallback(hidl_callback_); - // HIDL HWC seems to have an internal race condition. If we submit a frame too - // soon after turning on VSync we don't get any VSync signals. Give poor HWC - // implementations a chance to enable VSync before we continue. - EnableVsync(false); - std::this_thread::sleep_for(100ms); EnableVsync(true); - std::this_thread::sleep_for(100ms); // TODO(skiazyk): We need to do something about accessing this directly, // supposedly there is a backlight service on the way. @@ -240,9 +224,12 @@ void HardwareComposer::OnPostThreadPaused() { } active_layer_count_ = 0; - EnableVsync(false); + if (hidl_) { + EnableVsync(false); + } - hwc2_hidl_->resetCommands(); + hidl_callback_ = nullptr; + hidl_.reset(nullptr); // Trigger target-specific performance mode change. property_set(kDvrPerformanceProperty, "idle"); @@ -252,21 +239,21 @@ HWC::Error HardwareComposer::Validate(hwc2_display_t display) { uint32_t num_types; uint32_t num_requests; HWC::Error error = - hwc2_hidl_->validateDisplay(display, &num_types, &num_requests); + hidl_->validateDisplay(display, &num_types, &num_requests); if (error == HWC2_ERROR_HAS_CHANGES) { // TODO(skiazyk): We might need to inspect the requested changes first, but // so far it seems like we shouldn't ever hit a bad state. // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_, // display); - error = hwc2_hidl_->acceptDisplayChanges(display); + error = hidl_->acceptDisplayChanges(display); } return error; } -int32_t HardwareComposer::EnableVsync(bool enabled) { - return (int32_t)hwc2_hidl_->setVsyncEnabled( +HWC::Error HardwareComposer::EnableVsync(bool enabled) { + return hidl_->setVsyncEnabled( HWC_DISPLAY_PRIMARY, (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE : HWC2_VSYNC_DISABLE)); @@ -274,7 +261,7 @@ int32_t HardwareComposer::EnableVsync(bool enabled) { HWC::Error HardwareComposer::Present(hwc2_display_t display) { int32_t present_fence; - HWC::Error error = hwc2_hidl_->presentDisplay(display, &present_fence); + HWC::Error error = hidl_->presentDisplay(display, &present_fence); // According to the documentation, this fence is signaled at the time of // vsync/DMA for physical displays. @@ -288,20 +275,21 @@ HWC::Error HardwareComposer::Present(hwc2_display_t display) { return error; } -HWC::Error HardwareComposer::GetDisplayAttribute(hwc2_display_t display, +HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* hidl, + hwc2_display_t display, hwc2_config_t config, hwc2_attribute_t attribute, int32_t* out_value) const { - return hwc2_hidl_->getDisplayAttribute( + return hidl->getDisplayAttribute( display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value); } HWC::Error HardwareComposer::GetDisplayMetrics( - hwc2_display_t display, hwc2_config_t config, + Hwc2::Composer* hidl, hwc2_display_t display, hwc2_config_t config, HWCDisplayMetrics* out_metrics) const { HWC::Error error; - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_WIDTH, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_WIDTH, &out_metrics->width); if (error != HWC::Error::None) { ALOGE( @@ -310,7 +298,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_HEIGHT, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_HEIGHT, &out_metrics->height); if (error != HWC::Error::None) { ALOGE( @@ -319,7 +307,8 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_VSYNC_PERIOD, + error = GetDisplayAttribute(hidl, display, config, + HWC2_ATTRIBUTE_VSYNC_PERIOD, &out_metrics->vsync_period_ns); if (error != HWC::Error::None) { ALOGE( @@ -328,7 +317,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_X, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_X, &out_metrics->dpi.x); if (error != HWC::Error::None) { ALOGE( @@ -337,7 +326,7 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return error; } - error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_Y, + error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_Y, &out_metrics->dpi.y); if (error != HWC::Error::None) { ALOGE( @@ -374,7 +363,7 @@ std::string HardwareComposer::Dump() { if (post_thread_resumed_) { stream << "Hardware Composer Debug Info:" << std::endl; - stream << hwc2_hidl_->dumpDebugInfo(); + stream << hidl_->dumpDebugInfo(); } return stream.str(); @@ -408,7 +397,7 @@ void HardwareComposer::PostLayers() { } const bool is_frame_pending = IsFramePendingInDriver(); - const bool is_fence_pending = retire_fence_fds_.size() > + const bool is_fence_pending = static_cast<int32_t>(retire_fence_fds_.size()) > post_thread_config_.allowed_pending_fence_count; if (is_fence_pending || is_frame_pending) { @@ -446,8 +435,8 @@ void HardwareComposer::PostLayers() { std::vector<Hwc2::Layer> out_layers; std::vector<int> out_fences; - error = hwc2_hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, - &out_fences); + error = hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, + &out_fences); ALOGE_IF(error != HWC::Error::None, "HardwareComposer::PostLayers: Failed to get release fences: %s", error.to_string().c_str()); @@ -546,7 +535,7 @@ void HardwareComposer::UpdateConfigBuffer() { } int HardwareComposer::PostThreadPollInterruptible( - const pdx::LocalHandle& event_fd, int requested_events) { + const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms) { pollfd pfd[2] = { { .fd = event_fd.Get(), @@ -561,7 +550,7 @@ int HardwareComposer::PostThreadPollInterruptible( }; int ret, error; do { - ret = poll(pfd, 2, -1); + ret = poll(pfd, 2, timeout_ms); error = errno; ALOGW_IF(ret < 0, "HardwareComposer::PostThreadPollInterruptible: Error during " @@ -571,6 +560,8 @@ int HardwareComposer::PostThreadPollInterruptible( if (ret < 0) { return -error; + } else if (ret == 0) { + return -ETIMEDOUT; } else if (pfd[0].revents != 0) { return 0; } else if (pfd[1].revents != 0) { @@ -623,114 +614,17 @@ int HardwareComposer::ReadWaitPPState() { } } -// Reads the timestamp of the last vsync from the display driver. -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. -int HardwareComposer::ReadVSyncTimestamp(int64_t* timestamp) { - const int event_fd = primary_display_vsync_event_fd_.Get(); - int ret, error; - - // The driver returns data in the form "VSYNC=<timestamp ns>". - std::array<char, 32> data; - data.fill('\0'); - - // Seek back to the beginning of the event file. - ret = lseek(event_fd, 0, SEEK_SET); - if (ret < 0) { - error = errno; - ALOGE( - "HardwareComposer::ReadVSyncTimestamp: Failed to seek vsync event fd: " - "%s", - strerror(error)); - return -error; - } - - // Read the vsync event timestamp. - ret = read(event_fd, data.data(), data.size()); - if (ret < 0) { - error = errno; - ALOGE_IF( - error != EAGAIN, - "HardwareComposer::ReadVSyncTimestamp: Error while reading timestamp: " - "%s", - strerror(error)); - return -error; - } - - ret = sscanf(data.data(), "VSYNC=%" PRIu64, - reinterpret_cast<uint64_t*>(timestamp)); - if (ret < 0) { - error = errno; - ALOGE( - "HardwareComposer::ReadVSyncTimestamp: Error while parsing timestamp: " - "%s", - strerror(error)); - return -error; - } - - return 0; -} - -// Blocks until the next vsync event is signaled by the display driver. -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. -int HardwareComposer::BlockUntilVSync() { - // Vsync is signaled by POLLPRI on the fb vsync node. - return PostThreadPollInterruptible(primary_display_vsync_event_fd_, POLLPRI); -} - // Waits for the next vsync and returns the timestamp of the vsync event. If // vsync already passed since the last call, returns the latest vsync timestamp -// instead of blocking. This method updates the last_vsync_timeout_ in the -// process. -// -// TODO(eieio): This is pretty driver specific, this should be moved to a -// separate class eventually. +// instead of blocking. int HardwareComposer::WaitForVSync(int64_t* timestamp) { - int error; - - // Get the current timestamp and decide what to do. - while (true) { - int64_t current_vsync_timestamp; - error = ReadVSyncTimestamp(¤t_vsync_timestamp); - if (error < 0 && error != -EAGAIN) - return error; - - if (error == -EAGAIN) { - // Vsync was turned off, wait for the next vsync event. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) - return error; - - // Try again to get the timestamp for this new vsync interval. - continue; - } - - // Check that we advanced to a later vsync interval. - if (TimestampGT(current_vsync_timestamp, last_vsync_timestamp_)) { - *timestamp = last_vsync_timestamp_ = current_vsync_timestamp; - return 0; - } - - // See how close we are to the next expected vsync. If we're within 1ms, - // sleep for 1ms and try again. - const int64_t ns_per_frame = display_metrics_.vsync_period_ns; - const int64_t threshold_ns = 1000000; // 1ms - - const int64_t next_vsync_est = last_vsync_timestamp_ + ns_per_frame; - const int64_t distance_to_vsync_est = next_vsync_est - GetSystemClockNs(); - - if (distance_to_vsync_est > threshold_ns) { - // Wait for vsync event notification. - error = BlockUntilVSync(); - if (error < 0 || error == kPostThreadInterrupted) - return error; - } else { - // Sleep for a short time (1 millisecond) before retrying. - error = SleepUntil(GetSystemClockNs() + threshold_ns); - if (error < 0 || error == kPostThreadInterrupted) - return error; - } + int error = PostThreadPollInterruptible( + hidl_callback_->GetVsyncEventFd(), POLLIN, /*timeout_ms*/ 1000); + if (error == kPostThreadInterrupted || error < 0) { + return error; + } else { + *timestamp = hidl_callback_->GetVsyncTime(); + return 0; } } @@ -749,7 +643,8 @@ int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) { return -error; } - return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN); + return PostThreadPollInterruptible( + vsync_sleep_timer_fd_, POLLIN, /*timeout_ms*/ -1); } void HardwareComposer::PostThread() { @@ -772,15 +667,6 @@ void HardwareComposer::PostThread() { strerror(errno)); #endif // ENABLE_BACKLIGHT_BRIGHTNESS - // Open the vsync event node for the primary display. - // TODO(eieio): Move this into a platform-specific class. - primary_display_vsync_event_fd_ = - LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY); - ALOGE_IF(!primary_display_vsync_event_fd_, - "HardwareComposer: Failed to open vsync event node for primary " - "display: %s", - strerror(errno)); - // Open the wait pingpong status node for the primary display. // TODO(eieio): Move this into a platform-specific class. primary_display_wait_pp_fd_ = @@ -951,7 +837,8 @@ bool HardwareComposer::UpdateLayerConfig() { // The bottom layer is opaque, other layers blend. HWC::BlendMode blending = layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage; - layers_[layer_index].Setup(surfaces[layer_index], blending, + layers_[layer_index].Setup(surfaces[layer_index], native_display_metrics_, + hidl_.get(), blending, display_transform_, HWC::Composition::Device, layer_index); display_surfaces_.push_back(surfaces[layer_index]); @@ -979,50 +866,67 @@ void HardwareComposer::SetVSyncCallback(VSyncCallback callback) { vsync_callback_ = callback; } -void HardwareComposer::HwcRefresh(hwc2_callback_data_t /*data*/, - hwc2_display_t /*display*/) { - // TODO(eieio): implement invalidate callbacks. +void HardwareComposer::SetBacklightBrightness(int brightness) { + if (backlight_brightness_fd_) { + std::array<char, 32> text; + const int length = snprintf(text.data(), text.size(), "%d", brightness); + write(backlight_brightness_fd_.Get(), text.data(), length); + } } -void HardwareComposer::HwcVSync(hwc2_callback_data_t /*data*/, - hwc2_display_t /*display*/, - int64_t /*timestamp*/) { - ATRACE_NAME(__PRETTY_FUNCTION__); - // Intentionally empty. HWC may require a callback to be set to enable vsync - // signals. We bypass this callback thread by monitoring the vsync event - // directly, but signals still need to be enabled. +HardwareComposer::ComposerCallback::ComposerCallback() { + vsync_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + LOG_ALWAYS_FATAL_IF( + !vsync_event_fd_, + "Failed to create vsync event fd : %s", + strerror(errno)); } -void HardwareComposer::HwcHotplug(hwc2_callback_data_t /*callbackData*/, - hwc2_display_t /*display*/, - hwc2_connection_t /*connected*/) { - // TODO(eieio): implement display hotplug callbacks. +Return<void> HardwareComposer::ComposerCallback::onHotplug( + Hwc2::Display /*display*/, + IComposerCallback::Connection /*conn*/) { + return Void(); } -void HardwareComposer::OnHardwareComposerRefresh() { - // TODO(steventhomas): Handle refresh. +Return<void> HardwareComposer::ComposerCallback::onRefresh( + Hwc2::Display /*display*/) { + return hardware::Void(); } -void HardwareComposer::SetBacklightBrightness(int brightness) { - if (backlight_brightness_fd_) { - std::array<char, 32> text; - const int length = snprintf(text.data(), text.size(), "%d", brightness); - write(backlight_brightness_fd_.Get(), text.data(), length); +Return<void> HardwareComposer::ComposerCallback::onVsync( + Hwc2::Display display, int64_t timestamp) { + if (display == HWC_DISPLAY_PRIMARY) { + std::lock_guard<std::mutex> lock(vsync_mutex_); + vsync_time_ = timestamp; + int error = eventfd_write(vsync_event_fd_.Get(), 1); + LOG_ALWAYS_FATAL_IF(error != 0, "Failed writing to vsync event fd"); } + return Void(); +} + +const pdx::LocalHandle& +HardwareComposer::ComposerCallback::GetVsyncEventFd() const { + return vsync_event_fd_; } -void Layer::InitializeGlobals(Hwc2::Composer* hwc2_hidl, - const HWCDisplayMetrics* metrics) { - hwc2_hidl_ = hwc2_hidl; - display_metrics_ = metrics; +int64_t HardwareComposer::ComposerCallback::GetVsyncTime() { + std::lock_guard<std::mutex> lock(vsync_mutex_); + eventfd_t event; + eventfd_read(vsync_event_fd_.Get(), &event); + LOG_ALWAYS_FATAL_IF(vsync_time_ < 0, + "Attempt to read vsync time before vsync event"); + int64_t return_val = vsync_time_; + vsync_time_ = -1; + return return_val; } void Layer::Reset() { - if (hwc2_hidl_ != nullptr && hardware_composer_layer_) { - hwc2_hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); + if (hidl_ != nullptr && hardware_composer_layer_) { + hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); hardware_composer_layer_ = 0; } + hidl_ = nullptr; z_order_ = 0; blending_ = HWC::BlendMode::None; transform_ = HWC::Transform::None; @@ -1034,29 +938,35 @@ void Layer::Reset() { } void Layer::Setup(const std::shared_ptr<DirectDisplaySurface>& surface, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) { + const HWCDisplayMetrics& display_metrics, + Hwc2::Composer* hidl, HWC::BlendMode blending, + HWC::Transform transform, HWC::Composition composition_type, + size_t z_order) { Reset(); + hidl_ = hidl; z_order_ = z_order; blending_ = blending; transform_ = transform; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type; source_ = SourceSurface{surface}; - CommonLayerSetup(); + CommonLayerSetup(display_metrics); } void Layer::Setup(const std::shared_ptr<IonBuffer>& buffer, - HWC::BlendMode blending, HWC::Transform transform, - HWC::Composition composition_type, size_t z_order) { + const HWCDisplayMetrics& display_metrics, + Hwc2::Composer* hidl, HWC::BlendMode blending, + HWC::Transform transform, HWC::Composition composition_type, + size_t z_order) { Reset(); + hidl_ = hidl; z_order_ = z_order; blending_ = blending; transform_ = transform; composition_type_ = HWC::Composition::Invalid; target_composition_type_ = composition_type; source_ = SourceBuffer{buffer}; - CommonLayerSetup(); + CommonLayerSetup(display_metrics); } void Layer::UpdateBuffer(const std::shared_ptr<IonBuffer>& buffer) { @@ -1076,7 +986,7 @@ IonBuffer* Layer::GetBuffer() { return source_.Visit(Visitor{}); } -void Layer::UpdateLayerSettings() { +void Layer::UpdateLayerSettings(const HWCDisplayMetrics& display_metrics) { if (!IsLayerSetup()) { ALOGE( "HardwareComposer::Layer::UpdateLayerSettings: Attempt to update " @@ -1087,7 +997,7 @@ void Layer::UpdateLayerSettings() { HWC::Error error; hwc2_display_t display = HWC_DISPLAY_PRIMARY; - error = hwc2_hidl_->setLayerCompositionType( + error = hidl_->setLayerCompositionType( display, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); ALOGE_IF( @@ -1095,7 +1005,7 @@ void Layer::UpdateLayerSettings() { "Layer::UpdateLayerSettings: Error setting layer composition type: %s", error.to_string().c_str()); - error = hwc2_hidl_->setLayerBlendMode( + error = hidl_->setLayerBlendMode( display, hardware_composer_layer_, blending_.cast<Hwc2::IComposerClient::BlendMode>()); ALOGE_IF(error != HWC::Error::None, @@ -1104,41 +1014,39 @@ void Layer::UpdateLayerSettings() { // TODO(eieio): Use surface attributes or some other mechanism to control // the layer display frame. - error = hwc2_hidl_->setLayerDisplayFrame( + error = hidl_->setLayerDisplayFrame( display, hardware_composer_layer_, - {0, 0, display_metrics_->width, display_metrics_->height}); + {0, 0, display_metrics.width, display_metrics.height}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer display frame: %s", error.to_string().c_str()); - error = hwc2_hidl_->setLayerVisibleRegion( + error = hidl_->setLayerVisibleRegion( display, hardware_composer_layer_, - {{0, 0, display_metrics_->width, display_metrics_->height}}); + {{0, 0, display_metrics.width, display_metrics.height}}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer visible region: %s", error.to_string().c_str()); - error = - hwc2_hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); + error = hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s", error.to_string().c_str()); - error = - hwc2_hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_); + error = hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting z_ order: %s", error.to_string().c_str()); } -void Layer::CommonLayerSetup() { +void Layer::CommonLayerSetup(const HWCDisplayMetrics& display_metrics) { HWC::Error error = - hwc2_hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); + hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); ALOGE_IF( error != HWC::Error::None, "Layer::CommonLayerSetup: Failed to create layer on primary display: %s", error.to_string().c_str()); - UpdateLayerSettings(); + UpdateLayerSettings(display_metrics); } void Layer::Prepare() { @@ -1157,12 +1065,12 @@ void Layer::Prepare() { if (!handle.get()) { if (composition_type_ == HWC::Composition::Invalid) { composition_type_ = HWC::Composition::SolidColor; - hwc2_hidl_->setLayerCompositionType( + hidl_->setLayerCompositionType( HWC_DISPLAY_PRIMARY, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0}; - hwc2_hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, - layer_color); + hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + layer_color); } else { // The composition type is already set. Nothing else to do until a // buffer arrives. @@ -1170,15 +1078,15 @@ void Layer::Prepare() { } else { if (composition_type_ != target_composition_type_) { composition_type_ = target_composition_type_; - hwc2_hidl_->setLayerCompositionType( + hidl_->setLayerCompositionType( HWC_DISPLAY_PRIMARY, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); } HWC::Error error{HWC::Error::None}; - error = hwc2_hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY, - hardware_composer_layer_, 0, handle, - acquire_fence_.Get()); + error = hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY, + hardware_composer_layer_, 0, handle, + acquire_fence_.Get()); ALOGE_IF(error != HWC::Error::None, "Layer::Prepare: Error setting layer buffer: %s", @@ -1187,9 +1095,9 @@ void Layer::Prepare() { if (!surface_rect_functions_applied_) { const float float_right = right; const float float_bottom = bottom; - error = hwc2_hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, - hardware_composer_layer_, - {0, 0, float_right, float_bottom}); + error = hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, + hardware_composer_layer_, + {0, 0, float_right, float_bottom}); ALOGE_IF(error != HWC::Error::None, "Layer::Prepare: Error setting layer source crop: %s", diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index a0c50e14d8..fc0efeeeb4 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -54,11 +54,6 @@ class Layer { public: Layer() {} - // Sets up the global state used by all Layer instances. This must be called - // before using any Layer methods. - static void InitializeGlobals(Hwc2::Composer* hwc2_hidl, - const HWCDisplayMetrics* metrics); - // Releases any shared pointers and fence handles held by this instance. void Reset(); @@ -72,6 +67,7 @@ class Layer { // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). // |index| is the index of this surface in the DirectDisplaySurface array. void Setup(const std::shared_ptr<DirectDisplaySurface>& surface, + const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl, HWC::BlendMode blending, HWC::Transform transform, HWC::Composition composition_type, size_t z_roder); @@ -83,9 +79,10 @@ class Layer { // |transform| receives HWC_TRANSFORM_* values. // |composition_type| receives either HWC_FRAMEBUFFER for most layers or // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). - void Setup(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending, - HWC::Transform transform, HWC::Composition composition_type, - size_t z_order); + void Setup(const std::shared_ptr<IonBuffer>& buffer, + const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl, + HWC::BlendMode blending, HWC::Transform transform, + HWC::Composition composition_type, size_t z_order); // Layers that use a direct IonBuffer should call this each frame to update // which buffer will be used for the next PostLayers. @@ -121,7 +118,7 @@ class Layer { bool IsLayerSetup() const { return !source_.empty(); } // Applies all of the settings to this layer using the hwc functions - void UpdateLayerSettings(); + void UpdateLayerSettings(const HWCDisplayMetrics& display_metrics); int GetSurfaceId() const { int surface_id = -1; @@ -142,10 +139,9 @@ class Layer { } private: - void CommonLayerSetup(); + void CommonLayerSetup(const HWCDisplayMetrics& display_metrics); - static Hwc2::Composer* hwc2_hidl_; - static const HWCDisplayMetrics* display_metrics_; + Hwc2::Composer* hidl_ = nullptr; // The hardware composer layer and metrics to use during the prepare cycle. hwc2_layer_t hardware_composer_layer_ = 0; @@ -263,11 +259,10 @@ class HardwareComposer { static constexpr size_t kMaxHardwareLayers = 4; HardwareComposer(); - HardwareComposer(Hwc2::Composer* hidl, - RequestDisplayCallback request_display_callback); ~HardwareComposer(); - bool Initialize(); + bool Initialize(Hwc2::Composer* hidl, + RequestDisplayCallback request_display_callback); bool IsInitialized() const { return initialized_; } @@ -281,11 +276,6 @@ class HardwareComposer { // Get the HMD display metrics for the current display. display::Metrics GetHmdDisplayMetrics() const; - HWC::Error GetDisplayAttribute(hwc2_display_t display, hwc2_config_t config, - hwc2_attribute_t attributes, - int32_t* out_value) const; - HWC::Error GetDisplayMetrics(hwc2_display_t display, hwc2_config_t config, - HWCDisplayMetrics* out_metrics) const; std::string Dump(); void SetVSyncCallback(VSyncCallback callback); @@ -308,34 +298,31 @@ class HardwareComposer { int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); - void OnHardwareComposerRefresh(); - private: - int32_t EnableVsync(bool enabled); + HWC::Error GetDisplayAttribute(Hwc2::Composer* hidl, hwc2_display_t display, + hwc2_config_t config, + hwc2_attribute_t attributes, + int32_t* out_value) const; + HWC::Error GetDisplayMetrics(Hwc2::Composer* hidl, hwc2_display_t display, + hwc2_config_t config, + HWCDisplayMetrics* out_metrics) const; + + HWC::Error EnableVsync(bool enabled); class ComposerCallback : public Hwc2::IComposerCallback { public: - ComposerCallback() {} - - hardware::Return<void> onHotplug(Hwc2::Display /*display*/, - Connection /*connected*/) override { - // TODO(skiazyk): depending on how the server is implemented, we might - // have to set it up to synchronize with receiving this event, as it can - // potentially be a critical event for setting up state within the - // hwc2 module. That is, we (technically) should not call any other hwc - // methods until this method has been called after registering the - // callbacks. - return hardware::Void(); - } - - hardware::Return<void> onRefresh(Hwc2::Display /*display*/) override { - return hardware::Void(); - } - - hardware::Return<void> onVsync(Hwc2::Display /*display*/, - int64_t /*timestamp*/) override { - return hardware::Void(); - } + ComposerCallback(); + hardware::Return<void> onHotplug(Hwc2::Display display, + Connection conn) override; + hardware::Return<void> onRefresh(Hwc2::Display display) override; + hardware::Return<void> onVsync(Hwc2::Display display, + int64_t timestamp) override; + const pdx::LocalHandle& GetVsyncEventFd() const; + int64_t GetVsyncTime(); + private: + std::mutex vsync_mutex_; + pdx::LocalHandle vsync_event_fd_; + int64_t vsync_time_ = -1; }; HWC::Error Validate(hwc2_display_t display); @@ -364,17 +351,18 @@ class HardwareComposer { void UpdatePostThreadState(uint32_t state, bool suspend); // Blocks until either event_fd becomes readable, or we're interrupted by a - // control thread. Any errors are returned as negative errno values. If we're - // interrupted, kPostThreadInterrupted will be returned. + // control thread, or timeout_ms is reached before any events occur. Any + // errors are returned as negative errno values, with -ETIMEDOUT returned in + // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be + // returned. int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd, - int requested_events); + int requested_events, + int timeout_ms); - // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made - // on the post thread that can be interrupted by a control thread. If - // interrupted, these calls return kPostThreadInterrupted. + // WaitForVSync and SleepUntil are blocking calls made on the post thread that + // can be interrupted by a control thread. If interrupted, these calls return + // kPostThreadInterrupted. int ReadWaitPPState(); - int BlockUntilVSync(); - int ReadVSyncTimestamp(int64_t* timestamp); int WaitForVSync(int64_t* timestamp); int SleepUntil(int64_t wakeup_timestamp); @@ -398,11 +386,9 @@ class HardwareComposer { bool initialized_; - // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own - // this pointer. - Hwc2::Composer* hwc2_hidl_; + std::unique_ptr<Hwc2::Composer> hidl_; + sp<ComposerCallback> hidl_callback_; RequestDisplayCallback request_display_callback_; - sp<ComposerCallback> callbacks_; // Display metrics of the physical display. HWCDisplayMetrics native_display_metrics_; @@ -433,7 +419,8 @@ class HardwareComposer { std::thread post_thread_; // Post thread state machine and synchronization primitives. - PostThreadStateType post_thread_state_{PostThreadState::Idle}; + PostThreadStateType post_thread_state_{ + PostThreadState::Idle | PostThreadState::Suspended}; std::atomic<bool> post_thread_quiescent_{true}; bool post_thread_resumed_{false}; pdx::LocalHandle post_thread_event_fd_; @@ -444,9 +431,6 @@ class HardwareComposer { // Backlight LED brightness sysfs node. pdx::LocalHandle backlight_brightness_fd_; - // Primary display vsync event sysfs node. - pdx::LocalHandle primary_display_vsync_event_fd_; - // Primary display wait_pingpong state sysfs node. pdx::LocalHandle primary_display_wait_pp_fd_; @@ -478,12 +462,6 @@ class HardwareComposer { static constexpr int kPostThreadInterrupted = 1; - static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display); - static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display, - int64_t timestamp); - static void HwcHotplug(hwc2_callback_data_t callbackData, - hwc2_display_t display, hwc2_connection_t connected); - HardwareComposer(const HardwareComposer&) = delete; void operator=(const HardwareComposer&) = delete; }; diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h index f41da87596..33cbc84d7d 100644 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h @@ -4,7 +4,7 @@ #include <thread> #include <memory> -#include <pdx/default_transport/service_dispatcher.h> +#include <pdx/service_dispatcher.h> #include <vr/vr_manager/vr_manager.h> namespace android { @@ -29,9 +29,6 @@ class VrFlinger { void GrantDisplayOwnership(); void SeizeDisplayOwnership(); - // Called on a binder thread. - void OnHardwareComposerRefresh(); - // dump all vr flinger state. std::string Dump(); diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp index 3a0ca4a417..fcf94f0865 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -18,8 +18,6 @@ #include <sys/prctl.h> #include <sys/resource.h> -#include <pdx/default_transport/service_dispatcher.h> - #include <functional> #include "DisplayHardware/ComposerHal.h" @@ -76,7 +74,7 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, request_display_callback_ = request_display_callback; - dispatcher_ = android::pdx::default_transport::ServiceDispatcher::Create(); + dispatcher_ = android::pdx::ServiceDispatcher::Create(); CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher."); display_service_ = @@ -135,10 +133,6 @@ void VrFlinger::SeizeDisplayOwnership() { display_service_->SeizeDisplayOwnership(); } -void VrFlinger::OnHardwareComposerRefresh() { - display_service_->OnHardwareComposerRefresh(); -} - std::string VrFlinger::Dump() { // TODO(karthikrs): Add more state information here. return display_service_->DumpState(0/*unused*/); diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp index 4ddf1f33cb..546c2b6996 100644 --- a/libs/vr/libvrsensor/pose_client.cpp +++ b/libs/vr/libvrsensor/pose_client.cpp @@ -18,14 +18,13 @@ using android::pdx::LocalChannelHandle; using android::pdx::Status; using android::pdx::Transaction; -#define arraysize(x) (static_cast<int32_t>(std::extent<decltype(x)>::value)) - namespace android { namespace dvr { namespace { typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing; +constexpr static int32_t MAX_CONTROLLERS = 2; } // namespace // PoseClient is a remote interface to the pose service in sensord. @@ -81,7 +80,7 @@ class PoseClient : public pdx::ClientBase<PoseClient> { int GetControllerPose(int32_t controller_id, uint32_t vsync_count, DvrPoseAsync* out_pose) { - if (controller_id < 0 || controller_id >= arraysize(controllers_)) { + if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) { return -EINVAL; } if (!controllers_[controller_id].mapped_pose_buffer) { @@ -166,7 +165,7 @@ class PoseClient : public pdx::ClientBase<PoseClient> { } int GetControllerRingBuffer(int32_t controller_id) { - if (controller_id < 0 || controller_id >= arraysize(controllers_)) { + if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) { return -EINVAL; } ControllerClientState& client_state = controllers_[controller_id]; @@ -254,7 +253,7 @@ class PoseClient : public pdx::ClientBase<PoseClient> { std::unique_ptr<BufferConsumer> pose_buffer; const DvrPoseAsync* mapped_pose_buffer = nullptr; }; - ControllerClientState controllers_[2]; + ControllerClientState controllers_[MAX_CONTROLLERS]; }; } // namespace dvr diff --git a/opengl/Android.bp b/opengl/Android.bp index aec5a95628..9ca8b0b0fd 100644 --- a/opengl/Android.bp +++ b/opengl/Android.bp @@ -52,6 +52,30 @@ ndk_headers { license: "include/KHR/NOTICE", } +llndk_library { + name: "libEGL", + symbol_file: "libs/libEGL.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv1_CM", + symbol_file: "libs/libGLESv1_CM.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv2", + symbol_file: "libs/libGLESv2.map.txt", + export_include_dirs: ["include"], +} + +llndk_library { + name: "libGLESv3", + symbol_file: "libs/libGLESv3.map.txt", + export_include_dirs: ["include"], +} + cc_library_headers { name: "gl_headers", vendor_available: true, diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index c4073a9505..466768ae2c 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -534,11 +534,6 @@ EGLAPI EGLBoolean EGLAPIENTRY eglPresentationTimeANDROID (EGLDisplay dpy, EGLSur #endif #endif /* EGL_ANDROID_presentation_time */ -#ifndef EGL_KHR_no_config_context -#define EGL_KHR_no_config_context 1 -#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0) -#endif /* EGL_KHR_no_config_context */ - #ifndef EGL_ANDROID_get_frame_timestamps #define EGL_ANDROID_get_frame_timestamps 1 #define EGL_TIMESTAMPS_ANDROID 0x3430 diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index b4cc2113e9..802b3b46e0 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -85,7 +85,6 @@ cc_defaults { cc_defaults { name: "egl_libs_defaults", defaults: ["gl_libs_defaults"], - vendor_available: true, cflags: [ "-DLOG_TAG=\"libEGL\"", ], @@ -152,7 +151,6 @@ cc_test { cc_defaults { name: "gles_libs_defaults", defaults: ["gl_libs_defaults"], - vendor_available: true, arch: { arm: { instruction_set: "arm", diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 32f8caa989..371239ddc0 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -327,17 +327,17 @@ static void* load_system_driver(const char* kind) { switch (emulationStatus) { case 0: #if defined(__LP64__) - result = "/system/lib64/egl/libGLES_android.so"; + result = "/vendor/lib64/egl/libGLES_android.so"; #else - result = "/system/lib/egl/libGLES_android.so"; + result = "/vendor/lib/egl/libGLES_android.so"; #endif return result; case 1: // Use host-side OpenGL through the "emulation" library #if defined(__LP64__) - result = std::string("/system/lib64/egl/lib") + kind + "_emulation.so"; + result = std::string("/vendor/lib64/egl/lib") + kind + "_emulation.so"; #else - result = std::string("/system/lib/egl/lib") + kind + "_emulation.so"; + result = std::string("/vendor/lib/egl/lib") + kind + "_emulation.so"; #endif return result; default: diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 0214b0eb56..94dfe6a9de 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -1447,7 +1447,7 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return setError(EGL_BAD_PARAMETER, (const char *)0); } -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) { clearError(); diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt index 89269a0231..fa26e33f39 100644 --- a/opengl/libs/libEGL.map.txt +++ b/opengl/libs/libEGL.map.txt @@ -21,6 +21,7 @@ LIBEGL { eglDestroyStreamKHR; # introduced=23 eglDestroySurface; eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglDupNativeFenceFDANDROID; # vndk eglGetConfigAttrib; eglGetConfigs; eglGetCurrentContext; @@ -44,6 +45,7 @@ LIBEGL { eglQueryStreamTimeKHR; # introduced=23 eglQueryStreamu64KHR; # introduced=23 eglQueryString; + eglQueryStringImplementationANDROID; # vndk eglQuerySurface; eglReleaseTexImage; eglReleaseThread; diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp index bf7aeb117f..639f351c69 100644 --- a/opengl/tests/Android.bp +++ b/opengl/tests/Android.bp @@ -1,4 +1,19 @@ + subdirs = [ + "angeles", + "configdump", + "EGLTest", + "fillrate", + "filter", + "finish", + "gl2_basic", + "gl2_copyTexImage", + "gl2_yuvtex", + "gl_basic", + "gl_perf", + "gl_yuvtex", // just renders magenta frame, broken? + "gralloc", "hwc", "lib", ] + diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk index 92d223cc7e..134854a8b7 100644 --- a/opengl/tests/Android.mk +++ b/opengl/tests/Android.mk @@ -1,19 +1,4 @@ dirs := \ - angeles \ - configdump \ - EGLTest \ - fillrate \ - filter \ - finish \ - gl2_basic \ - gl2_copyTexImage \ - gl2_yuvtex \ - gl_basic \ - gl_perf \ - gl_yuvtex \ - gralloc \ - include \ - lib \ linetex \ swapinterval \ textures \ diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp new file mode 100644 index 0000000000..d85af81b6b --- /dev/null +++ b/opengl/tests/EGLTest/Android.bp @@ -0,0 +1,31 @@ + +cc_test { + + name: "EGL_test", + + srcs: [ + "egl_cache_test.cpp", + "EGL_test.cpp", + ], + + shared_libs: [ + "android.hardware.configstore@1.0", + "android.hardware.configstore-utils", + "libEGL", + "libbase", + "libcutils", + "libbinder", + "libgui", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + + include_dirs: [ + "bionic/libc/private", + "frameworks/native/opengl/libs", + "frameworks/native/opengl/libs/EGL", + ], + +} diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk deleted file mode 100644 index 5620496e17..0000000000 --- a/opengl/tests/EGLTest/Android.mk +++ /dev/null @@ -1,44 +0,0 @@ -# Build the unit tests. -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE := EGL_test - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := \ - egl_cache_test.cpp \ - EGL_test.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - android.hardware.configstore@1.0 \ - android.hardware.configstore-utils \ - libEGL \ - libcutils \ - libbinder \ - libhidlbase \ - libhidltransport \ - libutils \ - libgui \ - libbase \ - liblog \ - -LOCAL_C_INCLUDES := \ - bionic/libc/private \ - frameworks/native/opengl/libs \ - frameworks/native/opengl/libs/EGL \ - -# gold in binutils 2.22 will warn about the usage of mktemp -LOCAL_LDFLAGS += -Wl,--no-fatal-warnings - -include $(BUILD_NATIVE_TEST) - -# Include subdirectory makefiles -# ============================================================ - -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index 62e6bd3055..b67a053021 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -200,6 +200,7 @@ TEST_F(EGLTest, EGLDisplayP3) { if (!hasWideColorDisplay) { // skip this test if device does not have wide-color display + std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl; return; } @@ -285,6 +286,7 @@ TEST_F(EGLTest, EGLDisplayP31010102) { if (!hasWideColorDisplay) { // skip this test if device does not have wide-color display + std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl; return; } @@ -370,6 +372,7 @@ TEST_F(EGLTest, EGLConfigFP16) { if (!hasWideColorDisplay) { // skip this test if device does not have wide-color display + std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl; return; } @@ -431,9 +434,10 @@ TEST_F(EGLTest, EGLConfigFP16) { EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); } -TEST_F(EGLTest, EGL_KHR_no_config_context) { +TEST_F(EGLTest, EGLNoConfigContext) { if (!hasWideColorDisplay) { // skip this test if device does not have wide-color display + std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl; return; } @@ -471,6 +475,7 @@ TEST_F(EGLTest, EGLConfig1010102) { if (!hasWideColorDisplay) { // skip this test if device does not have wide-color display + std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl; return; } diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp new file mode 100644 index 0000000000..bbbc447c07 --- /dev/null +++ b/opengl/tests/angeles/Android.bp @@ -0,0 +1,22 @@ +// Copyright 2006 The Android Open Source Project + +cc_test { + name: "angeles", + + srcs: [ + "app-linux.cpp", + "demo.c", + ], + + gtest: false, + + shared_libs: [ + "libEGL", + "libGLESv1_CM", + "libui", + "libgui", + "libutils", + ], + + static_libs: ["libglTest"], +} diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk deleted file mode 100644 index c78224ee18..0000000000 --- a/opengl/tests/angeles/Android.mk +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2006 The Android Open Source Project - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm -LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui libgui libutils -LOCAL_STATIC_LIBRARIES += libglTest -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) -LOCAL_MODULE:= angeles -LOCAL_MODULE_TAGS := optional -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/angeles/demo.c b/opengl/tests/angeles/demo.c index 39d871e968..30c3202bd4 100644 --- a/opengl/tests/angeles/demo.c +++ b/opengl/tests/angeles/demo.c @@ -462,7 +462,7 @@ static void drawFadeQuad() // Called from the app framework. void appInit() { - int a; + unsigned int a; glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST); @@ -492,7 +492,7 @@ void appInit() // Called from the app framework. void appDeinit() { - int a; + unsigned int a; for (a = 0; a < SUPERSHAPE_COUNT; ++a) freeGLObject(sSuperShapeObjects[a]); freeGLObject(sGroundPlane); diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp new file mode 100644 index 0000000000..c46477cc53 --- /dev/null +++ b/opengl/tests/configdump/Android.bp @@ -0,0 +1,13 @@ +cc_test { + name: "test-opengl-configdump", + + gtest: false, + + srcs: ["configdump.cpp"], + + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv1_CM", + ], +} diff --git a/opengl/tests/configdump/Android.mk b/opengl/tests/configdump/Android.mk deleted file mode 100644 index 3f7c915b41..0000000000 --- a/opengl/tests/configdump/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - configdump.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv1_CM - -LOCAL_MODULE:= test-opengl-configdump - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/configdump/configdump.cpp b/opengl/tests/configdump/configdump.cpp index c423105a11..a4bb8791ea 100644 --- a/opengl/tests/configdump/configdump.cpp +++ b/opengl/tests/configdump/configdump.cpp @@ -78,7 +78,7 @@ int main(int /*argc*/, char** /*argv*/) { for (EGLint i=0 ; i<n ; i++) { printf("EGLConfig[%d]\n", i); - for (int attr = 0 ; attr<sizeof(attributes)/sizeof(Attribute) ; attr++) { + for (unsigned attr = 0 ; attr<sizeof(attributes)/sizeof(Attribute) ; attr++) { EGLint value; eglGetConfigAttrib(dpy, configs[i], attributes[attr].attribute, &value); printf("\t%-32s: %10d (0x%08x)\n", attributes[attr].name, value, value); diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp new file mode 100644 index 0000000000..543f1e3de2 --- /dev/null +++ b/opengl/tests/fillrate/Android.bp @@ -0,0 +1,18 @@ +cc_test { + name: "test-opengl-fillrate", + + srcs: ["fillrate.cpp"], + + gtest: false, + + shared_libs: [ + "libcutils", + "libutils", + "libEGL", + "libGLESv1_CM", + "libui", + "libgui", + ], + + static_libs: ["libglTest"], +} diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk deleted file mode 100644 index 21ff52a9a6..0000000000 --- a/opengl/tests/fillrate/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - fillrate.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libEGL \ - libGLESv1_CM \ - libui \ - libgui - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-fillrate - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp index 2db63d7835..a42f3f2811 100644 --- a/opengl/tests/fillrate/fillrate.cpp +++ b/opengl/tests/fillrate/fillrate.cpp @@ -30,7 +30,7 @@ using namespace android; -int main(int argc, char** argv) +int main(int /*argc*/, char** /*argv*/) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 0, @@ -153,7 +153,7 @@ int main(int argc, char** argv) for (int c=1, j=0 ; c<32 ; c++, j++) { nsecs_t t = times[j]; - printf("%lld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0); + printf("%ld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0); } diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp new file mode 100644 index 0000000000..5f925c856b --- /dev/null +++ b/opengl/tests/filter/Android.bp @@ -0,0 +1,20 @@ +cc_test { + name: "test-opengl-filter", + + srcs: ["filter.cpp"], + + gtest: false, + + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv1_CM", + "libui", + "libgui", + "libutils", + ], + + static_libs: ["libglTest"], + + cflags: ["-DGL_GLEXT_PROTOTYPES"], +} diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk deleted file mode 100644 index 4cf9c962de..0000000000 --- a/opengl/tests/filter/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - filter.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv1_CM \ - libui \ - libgui \ - libutils - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-filter - -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp new file mode 100644 index 0000000000..fb5671de4b --- /dev/null +++ b/opengl/tests/finish/Android.bp @@ -0,0 +1,20 @@ +cc_test { + name: "test-opengl-finish", + + srcs: ["finish.cpp"], + + gtest: false, + + shared_libs: [ + "libcutils", + "libutils", + "libEGL", + "libGLESv1_CM", + "libui", + "libgui", + ], + + static_libs: ["libglTest"], + + cflags: ["-DGL_GLEXT_PROTOTYPES"], +} diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk deleted file mode 100644 index 0b9b7ea255..0000000000 --- a/opengl/tests/finish/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - finish.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libEGL \ - libGLESv1_CM \ - libui \ - libgui - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-finish - -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp index ea3a60f514..ab955fe162 100644 --- a/opengl/tests/finish/finish.cpp +++ b/opengl/tests/finish/finish.cpp @@ -31,7 +31,7 @@ using namespace android; -int main(int argc, char** argv) +int main(int /*argc*/, char** /*argv*/) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 0, diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp new file mode 100644 index 0000000000..74032716b6 --- /dev/null +++ b/opengl/tests/gl2_basic/Android.bp @@ -0,0 +1,20 @@ +cc_test { + name: "test-opengl-gl2_basic", + + srcs: ["gl2_basic.cpp"], + + gtest: false, + + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv2", + "libui", + "libgui", + "libutils", + ], + + static_libs: ["libglTest"], + + cflags: ["-DGL_GLEXT_PROTOTYPES"], +} diff --git a/opengl/tests/gl2_basic/Android.mk b/opengl/tests/gl2_basic/Android.mk deleted file mode 100644 index 520395c041..0000000000 --- a/opengl/tests/gl2_basic/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - gl2_basic.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libui \ - libgui \ - libutils - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-gl2_basic - -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index ee88667328..67c0969e21 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -30,7 +30,7 @@ #include <EGLUtils.h> using namespace android; -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp new file mode 100644 index 0000000000..51e269cf5d --- /dev/null +++ b/opengl/tests/gl2_copyTexImage/Android.bp @@ -0,0 +1,20 @@ +cc_test { + name: "test-opengl-gl2_copyTexImage", + + srcs: ["gl2_copyTexImage.cpp"], + + gtest: false, + + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv2", + "libui", + "libgui", + "libutils", + ], + + static_libs: ["libglTest"], + + cflags: ["-DGL_GLEXT_PROTOTYPES"], +} diff --git a/opengl/tests/gl2_copyTexImage/Android.mk b/opengl/tests/gl2_copyTexImage/Android.mk deleted file mode 100644 index ff43558d31..0000000000 --- a/opengl/tests/gl2_copyTexImage/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - gl2_copyTexImage.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libui \ - libgui \ - libutils - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-gl2_copyTexImage - -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp index 405a3f029c..e0aafa219b 100644 --- a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp +++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp @@ -362,7 +362,7 @@ int printEGLConfigurations(EGLDisplay dpy) { return true; } -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { EGLBoolean returnValue; EGLConfig myConfig = {0}; diff --git a/opengl/tests/gl2_jni/jni/gl_code.cpp b/opengl/tests/gl2_jni/jni/gl_code.cpp index c4180d4d9a..5af4f6b7cf 100644 --- a/opengl/tests/gl2_jni/jni/gl_code.cpp +++ b/opengl/tests/gl2_jni/jni/gl_code.cpp @@ -153,12 +153,12 @@ extern "C" { JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj); }; -JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height) +JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height) { setupGraphics(width, height); } -JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj) +JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * /*env*/, jobject /*obj*/) { renderFrame(); } diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp new file mode 100644 index 0000000000..613d678ef7 --- /dev/null +++ b/opengl/tests/gl2_yuvtex/Android.bp @@ -0,0 +1,24 @@ +cc_test { + name: "test-opengl-gl2_yuvtex", + + srcs: ["gl2_yuvtex.cpp"], + + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv2", + "libutils", + "libui", + "libgui", + "libutils", + ], + + gtest: false, + + static_libs: ["libglTest"], + + cflags: [ + "-DGL_GLEXT_PROTOTYPES", + "-DEGL_EGLEXT_PROTOTYPES", + ], +} diff --git a/opengl/tests/gl2_yuvtex/Android.mk b/opengl/tests/gl2_yuvtex/Android.mk deleted file mode 100644 index 42cf771f19..0000000000 --- a/opengl/tests/gl2_yuvtex/Android.mk +++ /dev/null @@ -1,26 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - gl2_yuvtex.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - libui \ - libgui \ - libutils - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-gl2_yuvtex - -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp new file mode 100644 index 0000000000..881d8cea4a --- /dev/null +++ b/opengl/tests/gl_basic/Android.bp @@ -0,0 +1,18 @@ +cc_test { + name: "test-opengl-gl_basic", + + srcs: ["gl_basic.cpp"], + + gtest: false, + + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv1_CM", + "libui", + "libgui", + "libutils", + ], + + static_libs: ["libglTest"], +} diff --git a/opengl/tests/gl_basic/Android.mk b/opengl/tests/gl_basic/Android.mk deleted file mode 100644 index 7f2259e8e0..0000000000 --- a/opengl/tests/gl_basic/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - gl_basic.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv1_CM \ - libui \ - libgui \ - libutils - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-gl_basic - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp index e50d88fab1..0b663f796f 100644 --- a/opengl/tests/gl_basic/gl_basic.cpp +++ b/opengl/tests/gl_basic/gl_basic.cpp @@ -189,7 +189,7 @@ int printEGLConfigurations(EGLDisplay dpy) { return true; } -int main(int argc, char **argv) +int main(int /*argc*/, char **/*argv*/) { int q; int start, end; diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp index 48944e0a45..3aa8adbc35 100644 --- a/opengl/tests/gl_jni/jni/gl_code.cpp +++ b/opengl/tests/gl_jni/jni/gl_code.cpp @@ -140,13 +140,13 @@ extern "C" { JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj); }; -JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj, jint width, jint height) +JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height) { init_scene(width, height); create_texture(); } -JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj) +JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * /*env*/, jobject /*obj*/) { const GLfloat vertices[] = { -1, -1, 0, @@ -177,7 +177,7 @@ JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobjec glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, quadIndices); } -JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj) +JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * /*env*/, jobject /*obj*/) { background = 1.0f - background; } diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp new file mode 100644 index 0000000000..0ffb12158e --- /dev/null +++ b/opengl/tests/gl_perf/Android.bp @@ -0,0 +1,24 @@ +cc_test { + name: "test-opengl-gl2_perf", + + srcs: [ + "gl2_perf.cpp", + "filltest.cpp", + ], + + gtest: false, + + shared_libs: [ + "libcutils", + "liblog", + "libEGL", + "libGLESv2", + "libui", + "libgui", + "libutils", + ], + + static_libs: ["libglTest"], + + cflags: ["-DGL_GLEXT_PROTOTYPES"], +} diff --git a/opengl/tests/gl_perf/Android.mk b/opengl/tests/gl_perf/Android.mk deleted file mode 100644 index 9a93fab9db..0000000000 --- a/opengl/tests/gl_perf/Android.mk +++ /dev/null @@ -1,27 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - gl2_perf.cpp \ - filltest.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - liblog \ - libEGL \ - libGLESv2 \ - libui \ - libgui \ - libutils - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-gl2_perf - -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp index 35df84fc0a..29988648e4 100644 --- a/opengl/tests/gl_perf/gl2_perf.cpp +++ b/opengl/tests/gl_perf/gl2_perf.cpp @@ -56,7 +56,7 @@ bool doTest(uint32_t w, uint32_t h); static EGLDisplay dpy; static EGLSurface surface; -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { EGLBoolean returnValue; EGLConfig myConfig = {0}; diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp index 946ee07c3a..0cb594a0b0 100644 --- a/opengl/tests/gl_perfapp/jni/gl_code.cpp +++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp @@ -61,7 +61,7 @@ extern "C" { JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj); }; -JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj, jint width, jint height) +JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height) { gWidth = width; gHeight = height; @@ -87,7 +87,7 @@ JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobj } } -JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj) +JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * /*env*/, jobject /*obj*/) { if (! done) { if (stateClock > 0 && ((stateClock & 1) == 0)) { diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp new file mode 100644 index 0000000000..b6be327a25 --- /dev/null +++ b/opengl/tests/gl_yuvtex/Android.bp @@ -0,0 +1,23 @@ +cc_test { + name: "test-opengl-gl_yuvtex", + + srcs: ["gl_yuvtex.cpp"], + + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv1_CM", + "libutils", + "libui", + "libgui", + ], + + gtest: false, + + static_libs: ["libglTest"], + + cflags: [ + "-DGL_GLEXT_PROTOTYPES", + "-DEGL_EGLEXT_PROTOTYPES", + ], +} diff --git a/opengl/tests/gl_yuvtex/Android.mk b/opengl/tests/gl_yuvtex/Android.mk deleted file mode 100644 index 7f2020ab62..0000000000 --- a/opengl/tests/gl_yuvtex/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - gl_yuvtex.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv1_CM \ - libutils \ - libui \ - libgui - -LOCAL_STATIC_LIBRARIES += libglTest - -LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= test-opengl-gl_yuvtex - -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp index fad26a69c7..7ef3f4e34c 100644 --- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp +++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp @@ -90,7 +90,7 @@ const bool yuvTexSameUV = false; static sp<GraphicBuffer> yuvTexBuffer; static GLuint yuvTex; -bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) { +static bool setupYuvTexSurface(EGLDisplay dpy) { int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1; int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1; yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat, @@ -298,7 +298,7 @@ int main(int /*argc*/, char** /*argv*/) { printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); - if(!setupYuvTexSurface(dpy, context)) { + if(!setupYuvTexSurface(dpy)) { fprintf(stderr, "Could not set up texture surface.\n"); return 1; } diff --git a/opengl/tests/gldual/jni/gl_code.cpp b/opengl/tests/gldual/jni/gl_code.cpp index 3b114002f1..90d150ba09 100644 --- a/opengl/tests/gldual/jni/gl_code.cpp +++ b/opengl/tests/gldual/jni/gl_code.cpp @@ -153,12 +153,12 @@ extern "C" { JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj); }; -JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * env, jobject obj, jint width, jint height)
+JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height)
{ setupGraphics(width, height); } -JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj) +JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * /*env*/, jobject /*obj*/) { renderFrame(); } diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp new file mode 100644 index 0000000000..414c80457f --- /dev/null +++ b/opengl/tests/gralloc/Android.bp @@ -0,0 +1,13 @@ +cc_test { + name: "test-opengl-gralloc", + + srcs: ["gralloc.cpp"], + + gtest: false, + + shared_libs: [ + "libcutils", + "libutils", + "libui", + ], +} diff --git a/opengl/tests/gralloc/Android.mk b/opengl/tests/gralloc/Android.mk deleted file mode 100644 index d43c39a462..0000000000 --- a/opengl/tests/gralloc/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - gralloc.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libui - -LOCAL_MODULE:= test-opengl-gralloc - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/gralloc/gralloc.cpp b/opengl/tests/gralloc/gralloc.cpp index 8987040c80..29e0882cd0 100644 --- a/opengl/tests/gralloc/gralloc.cpp +++ b/opengl/tests/gralloc/gralloc.cpp @@ -37,7 +37,7 @@ void* lamecpy(void* d, void const* s, size_t size) { return d; } -int main(int argc, char** argv) +int main(int /*argc*/, char** /*argv*/) { size_t size = 128*256*4; void* temp = malloc(size); diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp index 425f3740e4..55f058f922 100644 --- a/opengl/tests/hwc/Android.bp +++ b/opengl/tests/hwc/Android.bp @@ -55,6 +55,8 @@ cc_defaults { "libnativewindow" ], + gtest: false, + static_libs: [ "libglTest", "libhwcTest", diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp index 69e56ff59b..5956366809 100644 --- a/opengl/tests/hwc/hwcRects.cpp +++ b/opengl/tests/hwc/hwcRects.cpp @@ -170,7 +170,7 @@ static EGLSurface surface; static EGLint width, height; // Function prototypes -static Rectangle parseRect(string rectStr); +static Rectangle parseRect(const string& rectStr); void init(void); void printSyntax(const char *cmd); @@ -358,7 +358,7 @@ main(int argc, char *argv[]) // Parse string description of rectangle and add it to list of rectangles // to be rendered. -static Rectangle parseRect(string rectStr) +static Rectangle parseRect(const string& rectStr) { int rv; string str; diff --git a/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h index 014c2611ae..9dc6bcf56a 100644 --- a/opengl/tests/lib/include/EGLUtils.h +++ b/opengl/tests/lib/include/EGLUtils.h @@ -20,11 +20,16 @@ #include <stdint.h> #include <stdlib.h> +#include <vector> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> #include <system/window.h> #include <utils/Errors.h> -#include <EGL/egl.h> +#include <utils/String8.h> +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); // ---------------------------------------------------------------------------- namespace android { @@ -47,6 +52,17 @@ public: EGLint const* attrs, EGLNativeWindowType window, EGLConfig* outConfig); + + static inline String8 printGLString(const char* name, GLenum s); + static inline String8 printEGLString(EGLDisplay dpy, const char* name, GLenum s); + static inline String8 checkEglError(const char* op, EGLBoolean returnVal); + static inline String8 checkGlError(const char* op); + static inline String8 printEGLConfiguration(EGLDisplay dpy, EGLConfig config); + static inline bool printEGLConfigurations(EGLDisplay dpy, String8& msg); + static inline bool printEGLConfigurations(FILE* output, EGLDisplay dpy); + static inline String8 decodeColorSpace(EGLint colorSpace); + static inline bool hasEglExtension(EGLDisplay dpy, const char* name); + static inline bool hasExtension(const char* exts, const char* name); }; // ---------------------------------------------------------------------------- @@ -91,9 +107,8 @@ status_t EGLUtils::selectConfigForPixelFormat( if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE) return BAD_VALUE; - EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs); - if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) { - free(configs); + std::vector<EGLConfig> configs(numConfigs); + if (eglChooseConfig(dpy, attrs, configs.data(), numConfigs, &n) == EGL_FALSE) { return BAD_VALUE; } @@ -108,8 +123,6 @@ status_t EGLUtils::selectConfigForPixelFormat( } } - free(configs); - if (i<n) { *outConfig = config; return NO_ERROR; @@ -137,6 +150,159 @@ status_t EGLUtils::selectConfigForNativeWindow( return selectConfigForPixelFormat(dpy, attrs, format, outConfig); } +String8 EGLUtils::printGLString(const char* name, GLenum s) { + String8 msg; + const char* v = reinterpret_cast<const char*>(glGetString(s)); + msg.appendFormat("GL %s = %s\n", name, v); + return msg; +} + +String8 EGLUtils::printEGLString(EGLDisplay dpy, const char* name, GLenum s) { + String8 msg; + const char* v = static_cast<const char*>(eglQueryString(dpy, s)); + msg.appendFormat("GL %s = %s\n", name, v); + const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s); + msg.appendFormat("ImplementationANDROID: %s = %s\n", name, va); + return msg; +} + +String8 EGLUtils::checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { + String8 msg; + if (returnVal != EGL_TRUE) { + msg.appendFormat("%s() returned %d\n", op, returnVal); + } + + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { + msg.appendFormat("after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error); + } + return msg; +} + +String8 EGLUtils::checkGlError(const char* op) { + String8 msg; + for (GLint error = glGetError(); error != GL_NO_ERROR; error = glGetError()) { + msg.appendFormat("after %s() glError (0x%x)\n", op, error); + } + return msg; +} + +String8 EGLUtils::printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { +#define X(VAL) \ + { VAL, #VAL } + struct { + EGLint attribute; + const char* name; + } names[] = { + X(EGL_BUFFER_SIZE), + X(EGL_ALPHA_SIZE), + X(EGL_BLUE_SIZE), + X(EGL_GREEN_SIZE), + X(EGL_RED_SIZE), + X(EGL_DEPTH_SIZE), + X(EGL_STENCIL_SIZE), + X(EGL_CONFIG_CAVEAT), + X(EGL_CONFIG_ID), + X(EGL_LEVEL), + X(EGL_MAX_PBUFFER_HEIGHT), + X(EGL_MAX_PBUFFER_PIXELS), + X(EGL_MAX_PBUFFER_WIDTH), + X(EGL_NATIVE_RENDERABLE), + X(EGL_NATIVE_VISUAL_ID), + X(EGL_NATIVE_VISUAL_TYPE), + X(EGL_SAMPLES), + X(EGL_SAMPLE_BUFFERS), + X(EGL_SURFACE_TYPE), + X(EGL_TRANSPARENT_TYPE), + X(EGL_TRANSPARENT_RED_VALUE), + X(EGL_TRANSPARENT_GREEN_VALUE), + X(EGL_TRANSPARENT_BLUE_VALUE), + X(EGL_BIND_TO_TEXTURE_RGB), + X(EGL_BIND_TO_TEXTURE_RGBA), + X(EGL_MIN_SWAP_INTERVAL), + X(EGL_MAX_SWAP_INTERVAL), + X(EGL_LUMINANCE_SIZE), + X(EGL_ALPHA_MASK_SIZE), + X(EGL_COLOR_BUFFER_TYPE), + X(EGL_RENDERABLE_TYPE), + X(EGL_CONFORMANT), + }; +#undef X + + String8 msg; + for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { + EGLint value = -1; + EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); + EGLint error = eglGetError(); + if (returnVal && error == EGL_SUCCESS) { + msg.appendFormat(" %s: %d (0x%x)", names[j].name, value, value); + } + } + msg.append("\n"); + return msg; +} + +bool EGLUtils::printEGLConfigurations(EGLDisplay dpy, String8& msg) { + EGLint numConfig = 0; + EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig); + msg.append(checkEglError("eglGetConfigs", returnVal)); + if (!returnVal) { + return false; + } + + msg.appendFormat("Number of EGL configuration: %d\n", numConfig); + + std::vector<EGLConfig> configs(numConfig); + + returnVal = eglGetConfigs(dpy, configs.data(), numConfig, &numConfig); + msg.append(checkEglError("eglGetConfigs", returnVal)); + if (!returnVal) { + return false; + } + + for (int i = 0; i < numConfig; i++) { + msg.appendFormat("Configuration %d\n", i); + msg.append(printEGLConfiguration(dpy, configs[i])); + } + + return true; +} + +bool EGLUtils::printEGLConfigurations(FILE* output, EGLDisplay dpy) { + String8 msg; + bool status = printEGLConfigurations(dpy, msg); + fprintf(output, "%s", msg.c_str()); + return status; +} + +String8 EGLUtils::decodeColorSpace(EGLint colorSpace) { + switch (colorSpace) { + case EGL_GL_COLORSPACE_SRGB_KHR: + return String8("EGL_GL_COLORSPACE_SRGB_KHR"); + case EGL_GL_COLORSPACE_DISPLAY_P3_EXT: + return String8("EGL_GL_COLORSPACE_DISPLAY_P3_EXT"); + case EGL_GL_COLORSPACE_LINEAR_KHR: + return String8("EGL_GL_COLORSPACE_LINEAR_KHR"); + default: + return String8::format("UNKNOWN ColorSpace %d", colorSpace); + } +} + +bool EGLUtils::hasExtension(const char* exts, const char* name) { + size_t nameLen = strlen(name); + if (exts) { + for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) { + if (match[nameLen] == '\0' || match[nameLen] == ' ') { + return true; + } + } + } + return false; +} + +bool EGLUtils::hasEglExtension(EGLDisplay dpy, const char* name) { + return hasExtension(eglQueryString(dpy, EGL_EXTENSIONS), name); +} + // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp index 5ad695bc84..cdc051bc5a 100644 --- a/opengl/tests/linetex/linetex.cpp +++ b/opengl/tests/linetex/linetex.cpp @@ -29,7 +29,7 @@ using namespace android; -int main(int argc, char** argv) +int main(int /*argc*/, char** /*argv*/) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 0, diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp index 3a8a8a184d..c4261e68f6 100644 --- a/opengl/tests/swapinterval/swapinterval.cpp +++ b/opengl/tests/swapinterval/swapinterval.cpp @@ -28,7 +28,7 @@ using namespace android; -int main(int argc, char** argv) +int main(int /*argc*/, char** /*argv*/) { EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp index 1e55db0e07..7be942a764 100644 --- a/opengl/tests/textures/textures.cpp +++ b/opengl/tests/textures/textures.cpp @@ -27,7 +27,7 @@ using namespace android; -int main(int argc, char** argv) +int main(int /*argc*/, char** /*argv*/) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 0, diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp index e441bdafed..4c7265b654 100644 --- a/services/batteryservice/Android.bp +++ b/services/batteryservice/Android.bp @@ -1,3 +1,11 @@ +cc_library_headers { + name: "libbatteryservice_headers", + vendor_available: true, + export_include_dirs: ["include"], + header_libs: ["libbinder_headers"], + export_header_lib_headers: ["libbinder_headers"], +} + cc_library { name: "libbatteryservice", @@ -8,6 +16,9 @@ cc_library { "IBatteryPropertiesRegistrar.cpp", ], + header_libs: ["libbatteryservice_headers"], + export_header_lib_headers: ["libbatteryservice_headers"], + shared_libs: [ "libutils", "libbinder", @@ -19,4 +30,4 @@ cc_library { "-Wunused", "-Wunreachable-code", ], -}
\ No newline at end of file +} diff --git a/include/batteryservice/BatteryService.h b/services/batteryservice/include/batteryservice/BatteryService.h index 80ab7f3e9e..80ab7f3e9e 100644 --- a/include/batteryservice/BatteryService.h +++ b/services/batteryservice/include/batteryservice/BatteryService.h diff --git a/include/batteryservice/BatteryServiceConstants.h b/services/batteryservice/include/batteryservice/BatteryServiceConstants.h index 8a90a12f2b..8a90a12f2b 100644 --- a/include/batteryservice/BatteryServiceConstants.h +++ b/services/batteryservice/include/batteryservice/BatteryServiceConstants.h diff --git a/include/batteryservice/IBatteryPropertiesListener.h b/services/batteryservice/include/batteryservice/IBatteryPropertiesListener.h index b226dd6fd0..b226dd6fd0 100644 --- a/include/batteryservice/IBatteryPropertiesListener.h +++ b/services/batteryservice/include/batteryservice/IBatteryPropertiesListener.h diff --git a/include/batteryservice/IBatteryPropertiesRegistrar.h b/services/batteryservice/include/batteryservice/IBatteryPropertiesRegistrar.h index a7dbea65e5..a7dbea65e5 100644 --- a/include/batteryservice/IBatteryPropertiesRegistrar.h +++ b/services/batteryservice/include/batteryservice/IBatteryPropertiesRegistrar.h diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index cc81a298a2..935d0f626e 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -147,7 +147,33 @@ static const int32_t keyCodeRotationMap[][4] = { static const size_t keyCodeRotationMapSize = sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); +static int32_t rotateStemKey(int32_t value, int32_t orientation, + const int32_t map[][2], size_t mapSize) { + if (orientation == DISPLAY_ORIENTATION_180) { + for (size_t i = 0; i < mapSize; i++) { + if (value == map[i][0]) { + return map[i][1]; + } + } + } + return value; +} + +// The mapping can be defined using input device configuration properties keyboard.rotated.stem_X +static int32_t stemKeyRotationMap[][2] = { + // key codes enumerated with the original (unrotated) key first + // no rotation, 180 degree rotation + { AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY }, + { AKEYCODE_STEM_1, AKEYCODE_STEM_1 }, + { AKEYCODE_STEM_2, AKEYCODE_STEM_2 }, + { AKEYCODE_STEM_3, AKEYCODE_STEM_3 }, +}; +static const size_t stemKeyRotationMapSize = + sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]); + static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { + keyCode = rotateStemKey(keyCode, orientation, + stemKeyRotationMap, stemKeyRotationMapSize); return rotateValueUsingRotationMap(keyCode, orientation, keyCodeRotationMap, keyCodeRotationMapSize); } @@ -2260,18 +2286,36 @@ void KeyboardInputMapper::configure(nsecs_t when, } } +static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const *property) { + int32_t mapped = 0; + if (config.tryGetProperty(String8(property), mapped) && mapped > 0) { + for (size_t i = 0; i < stemKeyRotationMapSize; i++) { + if (stemKeyRotationMap[i][0] == keyCode) { + stemKeyRotationMap[i][1] = mapped; + return; + } + } + } +} + void KeyboardInputMapper::configureParameters() { mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"), + const PropertyMap& config = getDevice()->getConfiguration(); + config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; if (mParameters.orientationAware) { mParameters.hasAssociatedDisplay = true; + + mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary"); + mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1"); + mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2"); + mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3"); } mParameters.handlesKeyRepeat = false; - getDevice()->getConfiguration().tryGetProperty(String8("keyboard.handlesKeyRepeat"), + config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat); } @@ -2926,7 +2970,7 @@ void CursorInputMapper::fadePointer() { // --- RotaryEncoderInputMapper --- RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) : - InputMapper(device) { + InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) { mSource = AINPUT_SOURCE_ROTARY_ENCODER; } @@ -2968,6 +3012,14 @@ void RotaryEncoderInputMapper::configure(nsecs_t when, if (!changes) { mRotaryEncoderScrollAccumulator.configure(getDevice()); } + if (!changes || (InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + DisplayViewport v; + if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) { + mOrientation = v.orientation; + } else { + mOrientation = DISPLAY_ORIENTATION_0; + } + } } void RotaryEncoderInputMapper::reset(nsecs_t when) { @@ -3005,6 +3057,10 @@ void RotaryEncoderInputMapper::sync(nsecs_t when) { policyFlags |= POLICY_FLAG_WAKE; } + if (mOrientation == DISPLAY_ORIENTATION_180) { + scroll = -scroll; + } + // Send motion event. if (scrolled) { int32_t metaState = mContext->getGlobalMetaState(); diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index c4f786ad0e..a6b9798759 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -1227,6 +1227,7 @@ private: int32_t mSource; float mScalingFactor; + int32_t mOrientation; void sync(nsecs_t when); }; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 62c2756d2f..dc491d97c0 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -933,8 +933,14 @@ sp<ISensorEventConnection> SensorService::createSensorEventConnection(const Stri } uid_t uid = IPCThreadState::self()->getCallingUid(); - sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName, - requestedMode == DATA_INJECTION, opPackageName)); + pid_t pid = IPCThreadState::self()->getCallingPid(); + + String8 connPackageName = + (packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName; + String16 connOpPackageName = + (opPackageName == String16("")) ? String16(connPackageName) : opPackageName; + sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName, + requestedMode == DATA_INJECTION, connOpPackageName)); if (requestedMode == DATA_INJECTION) { if (mActiveConnections.indexOf(result) < 0) { mActiveConnections.add(result); diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp index 8bbc4c59a8..02c13fa579 100644 --- a/services/sensorservice/hidl/Android.bp +++ b/services/sensorservice/hidl/Android.bp @@ -14,6 +14,7 @@ cc_library_shared { "libbase", "libhidlbase", "libhidltransport", + "libhwbinder", "libutils", "libsensor", "android.frameworks.sensorservice@1.0", diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp index cf5ab05082..fee6da1e60 100644 --- a/services/sensorservice/hidl/SensorManager.cpp +++ b/services/sensorservice/hidl/SensorManager.cpp @@ -29,6 +29,9 @@ #include "DirectReportChannel.h" #include "utils.h" +#include <hwbinder/IPCThreadState.h> +#include <utils/String8.h> + namespace android { namespace frameworks { namespace sensorservice { @@ -212,7 +215,9 @@ Return<void> SensorManager::createEventQueue( return Void(); } - sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(); + String8 package(String8::format("hidl_client_pid_%d", + android::hardware::IPCThreadState::self()->getCallingPid())); + sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(package); if (internalQueue == nullptr) { LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr."; _hidl_cb(nullptr, Result::UNKNOWN_ERROR); diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index cc93105543..4775e4ef54 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -2,3 +2,5 @@ cc_library_static { name: "libsurfaceflingerincludes", export_include_dirs: ["."], } + +subdirs = ["tests/fakehwc"]
\ No newline at end of file diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp index ea048397d0..bef12ea50f 100644 --- a/services/surfaceflinger/DispSync.cpp +++ b/services/surfaceflinger/DispSync.cpp @@ -30,7 +30,7 @@ #include <utils/Trace.h> #include <utils/Vector.h> -#include <ui/Fence.h> +#include <ui/FenceTime.h> #include "DispSync.h" #include "SurfaceFlinger.h" @@ -421,25 +421,13 @@ void DispSync::reset() { resetErrorLocked(); } -bool DispSync::addPresentFence(const sp<Fence>& fence) { +bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) { Mutex::Autolock lock(mMutex); - mPresentFences[mPresentSampleOffset] = fence; - mPresentTimes[mPresentSampleOffset] = 0; + mPresentFences[mPresentSampleOffset] = fenceTime; mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES; mNumResyncSamplesSincePresent = 0; - for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { - const sp<Fence>& f(mPresentFences[i]); - if (f != NULL) { - nsecs_t t = f->getSignalTime(); - if (t < INT64_MAX) { - mPresentFences[i].clear(); - mPresentTimes[i] = t + mPresentTimeOffset; - } - } - } - updateErrorLocked(); return !mModelUpdated || mError > kErrorThreshold; @@ -604,21 +592,39 @@ void DispSync::updateErrorLocked() { nsecs_t sqErrSum = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { - nsecs_t sample = mPresentTimes[i] - mReferenceTime; - if (sample > mPhase) { - nsecs_t sampleErr = (sample - mPhase) % period; - if (sampleErr > period / 2) { - sampleErr -= period; - } - sqErrSum += sampleErr * sampleErr; - numErrSamples++; + // Only check for the cached value of signal time to avoid unecessary + // syscalls. It is the responsibility of the DispSync owner to + // call getSignalTime() periodically so the cache is updated when the + // fence signals. + nsecs_t time = mPresentFences[i]->getCachedSignalTime(); + if (time == Fence::SIGNAL_TIME_PENDING || + time == Fence::SIGNAL_TIME_INVALID) { + continue; + } + + nsecs_t sample = time - mReferenceTime; + if (sample <= mPhase) { + continue; + } + + nsecs_t sampleErr = (sample - mPhase) % period; + if (sampleErr > period / 2) { + sampleErr -= period; } + sqErrSum += sampleErr * sampleErr; + numErrSamples++; } if (numErrSamples > 0) { mError = sqErrSum / numErrSamples; + mZeroErrSamplesCount = 0; } else { mError = 0; + // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam. + mZeroErrSamplesCount++; + ALOGE_IF( + (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0, + "No present times for model error."); } if (kTraceDetailedInfo) { @@ -629,9 +635,9 @@ void DispSync::updateErrorLocked() { void DispSync::resetErrorLocked() { mPresentSampleOffset = 0; mError = 0; + mZeroErrSamplesCount = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { - mPresentFences[i].clear(); - mPresentTimes[i] = 0; + mPresentFences[i] = FenceTime::NO_FENCE; } } @@ -670,19 +676,19 @@ void DispSync::dump(String8& result) const { previous = sampleTime; } - result.appendFormat("mPresentFences / mPresentTimes [%d]:\n", + result.appendFormat("mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - previous = 0; + previous = Fence::SIGNAL_TIME_INVALID; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES; - bool signaled = mPresentFences[idx] == NULL; - nsecs_t presentTime = mPresentTimes[idx]; - if (!signaled) { + nsecs_t presentTime = mPresentFences[idx]->getSignalTime(); + if (presentTime == Fence::SIGNAL_TIME_PENDING) { result.appendFormat(" [unsignaled fence]\n"); - } else if (presentTime == 0) { - result.appendFormat(" 0\n"); - } else if (previous == 0) { + } else if(presentTime == Fence::SIGNAL_TIME_INVALID) { + result.appendFormat(" [invalid fence]\n"); + } else if (previous == Fence::SIGNAL_TIME_PENDING || + previous == Fence::SIGNAL_TIME_INVALID) { result.appendFormat(" %" PRId64 " (%.3f ms ago)\n", presentTime, (now - presentTime) / 1000000.0); } else { diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index 3c34fb08a4..880a24d6ad 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -23,10 +23,14 @@ #include <utils/Timers.h> #include <utils/RefBase.h> +#include <ui/FenceTime.h> + +#include <memory> + namespace android { class String8; -class Fence; +class FenceTime; class DispSyncThread; // DispSync maintains a model of the periodic hardware-based vsync events of a @@ -69,7 +73,7 @@ public: // // This method should be called with the retire fence from each HWComposer // set call that affects the display. - bool addPresentFence(const sp<Fence>& fence); + bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime); // The beginResync, addResyncSample, and endResync methods are used to re- // synchronize the DispSync's model to the hardware vsync events. The re- @@ -131,6 +135,7 @@ private: enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 }; enum { NUM_PRESENT_SAMPLES = 8 }; enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 }; + enum { ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT = 64 }; const char* const mName; @@ -148,9 +153,14 @@ private: // mError is the computed model error. It is based on the difference // between the estimated vsync event times and those observed in the - // mPresentTimes array. + // mPresentFences array. nsecs_t mError; + // mZeroErrSamplesCount keeps track of how many times in a row there were + // zero timestamps available in the mPresentFences array. + // Used to sanity check that we are able to calculate the model error. + size_t mZeroErrSamplesCount; + // Whether we have updated the vsync event model since the last resync. bool mModelUpdated; @@ -164,8 +174,8 @@ private: // These member variables store information about the present fences used // to validate the currently computed model. - sp<Fence> mPresentFences[NUM_PRESENT_SAMPLES]; - nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES]; + std::shared_ptr<FenceTime> + mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE}; size_t mPresentSampleOffset; int mRefreshSkipCount; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index fc60002334..248ef53f55 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -65,7 +65,7 @@ using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) == 3; + &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3; #if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle) // Dummy implementation in case it is missing. @@ -134,9 +134,11 @@ DisplayDevice::DisplayDevice( EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { #ifdef USE_HWC2 - config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888); + config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888, + /*logConfig*/ false); #else - config = RenderEngine::chooseEglConfig(display, format); + config = RenderEngine::chooseEglConfig(display, format, + /*logConfig*/ false); #endif } eglSurface = eglCreateWindowSurface(display, config, window, NULL); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index e34fa163c4..433a224e25 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -157,15 +157,11 @@ void Composer::CommandWriter::writeBufferMetadata( write64(metadata.usage); } -Composer::Composer(bool useVrComposer) +Composer::Composer(const std::string& serviceName) : mWriter(kWriterInitialSize), - mIsUsingVrComposer(useVrComposer) + mIsUsingVrComposer(serviceName == std::string("vr")) { - if (mIsUsingVrComposer) { - mComposer = IComposer::getService("vr"); - } else { - mComposer = IComposer::getService(); // use default name - } + mComposer = IComposer::getService(serviceName); if (mComposer == nullptr) { LOG_ALWAYS_FATAL("failed to get hwcomposer service"); @@ -219,6 +215,10 @@ void Composer::registerCallback(const sp<IComposerCallback>& callback) } } +bool Composer::isRemote() { + return mClient->isRemote(); +} + void Composer::resetCommands() { mWriter.reset(); } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 96dd833cd5..31a3c1d785 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -136,13 +136,18 @@ private: // Composer is a wrapper to IComposer, a proxy to server-side composer. class Composer { public: - Composer(bool useVrComposer); + Composer(const std::string& serviceName); std::vector<IComposer::Capability> getCapabilities(); std::string dumpDebugInfo(); void registerCallback(const sp<IComposerCallback>& callback); + // Returns true if the connected composer service is running in a remote + // process, false otherwise. This will return false if the service is + // configured in passthrough mode, for example. + bool isRemote(); + // Reset all pending commands in the command buffer. Useful if you want to // skip a frame but have already queued some commands. void resetCommands(); diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 68d7a18d3a..93c6d5486f 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -34,6 +34,7 @@ #include <gui/BufferQueue.h> #include <gui/Surface.h> +#include <ui/DebugUtils.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> @@ -103,6 +104,7 @@ status_t FramebufferSurface::advanceFrame() { sp<Fence> acquireFence(Fence::NO_FENCE); android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; status_t result = nextBuffer(slot, buf, acquireFence, dataspace); + mDataSpace = dataspace; if (result != NO_ERROR) { ALOGE("error latching next FramebufferSurface buffer: %s (%d)", strerror(-result), result); @@ -173,16 +175,17 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer); outDataspace = item.mDataSpace; -#else - outBuffer = mCurrentBuffer; -#endif status_t result = mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace); if (result != NO_ERROR) { ALOGE("error posting framebuffer: %d", result); + return result; } +#else + outBuffer = mCurrentBuffer; +#endif - return result; + return NO_ERROR; } #ifndef USE_HWC2 @@ -248,7 +251,10 @@ status_t FramebufferSurface::compositionComplete() #endif void FramebufferSurface::dumpAsString(String8& result) const { - ConsumerBase::dumpState(result); + Mutex::Autolock lock(mMutex); + result.appendFormat("FramebufferSurface: dataspace: %s(%d)\n", + dataspaceDetails(mDataSpace).c_str(), mDataSpace); + ConsumerBase::dumpLocked(result, ""); } void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 69a72d7ede..a1756ca3c2 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -83,6 +83,13 @@ private: // or the buffer is not associated with a slot. int mCurrentBufferSlot; + // mDataSpace is the dataspace of the current composition buffer for + // this FramebufferSurface. It will be 0 when HWC is doing the + // compositing. Otherwise it will display the dataspace of the buffer + // use for compositing which can change as wide-color content is + // on/off. + android_dataspace mDataSpace; + // mCurrentBuffer is the current buffer or NULL to indicate that there is // no current buffer. sp<GraphicBuffer> mCurrentBuffer; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 270a73228b..78c0c8567a 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -33,45 +33,6 @@ #include <algorithm> #include <inttypes.h> -extern "C" { - static void hotplug_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId, int32_t intConnected) { - auto device = static_cast<HWC2::Device*>(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - auto connected = static_cast<HWC2::Connection>(intConnected); - device->callHotplug(std::move(display), connected); - } else { - ALOGE("Hotplug callback called with unknown display %" PRIu64, - displayId); - } - } - - static void refresh_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId) { - auto device = static_cast<HWC2::Device*>(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - device->callRefresh(std::move(display)); - } else { - ALOGE("Refresh callback called with unknown display %" PRIu64, - displayId); - } - } - - static void vsync_hook(hwc2_callback_data_t callbackData, - hwc2_display_t displayId, int64_t timestamp) { - auto device = static_cast<HWC2::Device*>(callbackData); - auto display = device->getDisplayById(displayId); - if (display) { - device->callVsync(std::move(display), timestamp); - } else { - ALOGE("Vsync callback called with unknown display %" PRIu64, - displayId); - } - } -} - using android::Fence; using android::FloatRect; using android::GraphicBuffer; @@ -86,51 +47,78 @@ namespace HWC2 { namespace Hwc2 = android::Hwc2; +namespace { + +class ComposerCallbackBridge : public Hwc2::IComposerCallback { +public: + ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId) + : mCallback(callback), mSequenceId(sequenceId), + mHasPrimaryDisplay(false) {} + + Return<void> onHotplug(Hwc2::Display display, + IComposerCallback::Connection conn) override + { + HWC2::Connection connection = static_cast<HWC2::Connection>(conn); + if (!mHasPrimaryDisplay) { + LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected, + "Initial onHotplug callback should be " + "primary display connected"); + mHasPrimaryDisplay = true; + mCallback->onHotplugReceived(mSequenceId, display, + connection, true); + } else { + mCallback->onHotplugReceived(mSequenceId, display, + connection, false); + } + return Void(); + } + + Return<void> onRefresh(Hwc2::Display display) override + { + mCallback->onRefreshReceived(mSequenceId, display); + return Void(); + } + + Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override + { + mCallback->onVsyncReceived(mSequenceId, display, timestamp); + return Void(); + } + + bool HasPrimaryDisplay() { return mHasPrimaryDisplay; } + +private: + ComposerCallback* mCallback; + int32_t mSequenceId; + bool mHasPrimaryDisplay; +}; + +} // namespace anonymous + + // Device methods -Device::Device(bool useVrComposer) - : mComposer(std::make_unique<Hwc2::Composer>(useVrComposer)), +Device::Device(const std::string& serviceName) + : mComposer(std::make_unique<Hwc2::Composer>(serviceName)), mCapabilities(), mDisplays(), - mHotplug(), - mPendingHotplugs(), - mRefresh(), - mPendingRefreshes(), - mVsync(), - mPendingVsyncs() + mRegisteredCallback(false) { loadCapabilities(); - registerCallbacks(); } -Device::~Device() -{ - for (auto element : mDisplays) { - auto display = element.second.lock(); - if (!display) { - ALOGE("~Device: Found a display (%" PRId64 " that has already been" - " destroyed", element.first); - continue; - } - - DisplayType displayType = HWC2::DisplayType::Invalid; - auto error = display->getType(&displayType); - if (error != Error::None) { - ALOGE("~Device: Failed to determine type of display %" PRIu64 - ": %s (%d)", display->getId(), to_string(error).c_str(), - static_cast<int32_t>(error)); - continue; - } - - if (displayType == HWC2::DisplayType::Physical) { - error = display->setVsyncEnabled(HWC2::Vsync::Disable); - if (error != Error::None) { - ALOGE("~Device: Failed to disable vsync for display %" PRIu64 - ": %s (%d)", display->getId(), to_string(error).c_str(), - static_cast<int32_t>(error)); - } - } +void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) { + if (mRegisteredCallback) { + ALOGW("Callback already registered. Ignored extra registration " + "attempt."); + return; } + mRegisteredCallback = true; + sp<ComposerCallbackBridge> callbackBridge( + new ComposerCallbackBridge(callback, sequenceId)); + mComposer->registerCallback(callbackBridge); + LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(), + "Registered composer callback but didn't get primary display"); } // Required by HWC2 device @@ -146,7 +134,7 @@ uint32_t Device::getMaxVirtualDisplayCount() const } Error Device::createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, std::shared_ptr<Display>* outDisplay) + android_pixel_format_t* format, Display** outDisplay) { ALOGI("Creating virtual display"); @@ -159,104 +147,66 @@ Error Device::createVirtualDisplay(uint32_t width, uint32_t height, return error; } - ALOGI("Created virtual display"); + auto display = std::make_unique<Display>( + *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual); + *outDisplay = display.get(); *format = static_cast<android_pixel_format_t>(intFormat); - *outDisplay = getDisplayById(displayId); - if (!*outDisplay) { - ALOGE("Failed to get display by id"); - return Error::BadDisplay; - } - (*outDisplay)->setConnected(true); + mDisplays.emplace(displayId, std::move(display)); + ALOGI("Created virtual display"); return Error::None; } -void Device::registerHotplugCallback(HotplugCallback hotplug) +void Device::destroyDisplay(hwc2_display_t displayId) { - ALOGV("registerHotplugCallback"); - mHotplug = hotplug; - for (auto& pending : mPendingHotplugs) { - auto& display = pending.first; - auto connected = pending.second; - ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(), - to_string(connected).c_str()); - mHotplug(std::move(display), connected); - } + ALOGI("Destroying display %" PRIu64, displayId); + mDisplays.erase(displayId); } -void Device::registerRefreshCallback(RefreshCallback refresh) -{ - mRefresh = refresh; - for (auto& pending : mPendingRefreshes) { - mRefresh(std::move(pending)); - } -} - -void Device::registerVsyncCallback(VsyncCallback vsync) -{ - mVsync = vsync; - for (auto& pending : mPendingVsyncs) { - auto& display = pending.first; - auto timestamp = pending.second; - mVsync(std::move(display), timestamp); - } -} - -// For use by Device callbacks +void Device::onHotplug(hwc2_display_t displayId, Connection connection) { + if (connection == Connection::Connected) { + auto display = getDisplayById(displayId); + if (display) { + if (display->isConnected()) { + ALOGW("Attempt to hotplug connect display %" PRIu64 + " , which is already connected.", displayId); + } else { + display->setConnected(true); + } + } else { + DisplayType displayType; + auto intError = mComposer->getDisplayType(displayId, + reinterpret_cast<Hwc2::IComposerClient::DisplayType *>( + &displayType)); + auto error = static_cast<Error>(intError); + if (error != Error::None) { + ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). " + "Aborting hotplug attempt.", + displayId, to_string(error).c_str(), intError); + return; + } -void Device::callHotplug(std::shared_ptr<Display> display, Connection connected) -{ - if (connected == Connection::Connected) { - if (!display->isConnected()) { - mComposer->setClientTargetSlotCount(display->getId()); - display->loadConfigs(); - display->setConnected(true); + auto newDisplay = std::make_unique<Display>( + *mComposer.get(), mCapabilities, displayId, displayType); + mDisplays.emplace(displayId, std::move(newDisplay)); + } + } else if (connection == Connection::Disconnected) { + // The display will later be destroyed by a call to + // destroyDisplay(). For now we just mark it disconnected. + auto display = getDisplayById(displayId); + if (display) { + display->setConnected(false); + } else { + ALOGW("Attempted to disconnect unknown display %" PRIu64, + displayId); } - } else { - display->setConnected(false); - mDisplays.erase(display->getId()); - } - - if (mHotplug) { - mHotplug(std::move(display), connected); - } else { - ALOGV("callHotplug called, but no valid callback registered, storing"); - mPendingHotplugs.emplace_back(std::move(display), connected); - } -} - -void Device::callRefresh(std::shared_ptr<Display> display) -{ - if (mRefresh) { - mRefresh(std::move(display)); - } else { - ALOGV("callRefresh called, but no valid callback registered, storing"); - mPendingRefreshes.emplace_back(std::move(display)); - } -} - -void Device::callVsync(std::shared_ptr<Display> display, nsecs_t timestamp) -{ - if (mVsync) { - mVsync(std::move(display), timestamp); - } else { - ALOGV("callVsync called, but no valid callback registered, storing"); - mPendingVsyncs.emplace_back(std::move(display), timestamp); } } // Other Device methods -std::shared_ptr<Display> Device::getDisplayById(hwc2_display_t id) { - if (mDisplays.count(id) != 0) { - auto strongDisplay = mDisplays[id].lock(); - ALOGE_IF(!strongDisplay, "Display %" PRId64 " is in mDisplays but is no" - " longer alive", id); - return strongDisplay; - } - - auto display = std::make_shared<Display>(*this, id); - mDisplays.emplace(id, display); - return display; +Display* Device::getDisplayById(hwc2_display_t id) { + auto iter = mDisplays.find(id); + return iter == mDisplays.end() ? nullptr : iter->second.get(); } // Device initialization methods @@ -271,84 +221,37 @@ void Device::loadCapabilities() } } -bool Device::hasCapability(HWC2::Capability capability) const -{ - return std::find(mCapabilities.cbegin(), mCapabilities.cend(), - capability) != mCapabilities.cend(); -} - -namespace { -class ComposerCallback : public Hwc2::IComposerCallback { -public: - ComposerCallback(Device* device) : mDevice(device) {} - - Return<void> onHotplug(Hwc2::Display display, - Connection connected) override - { - hotplug_hook(mDevice, display, static_cast<int32_t>(connected)); - return Void(); - } - - Return<void> onRefresh(Hwc2::Display display) override - { - refresh_hook(mDevice, display); - return Void(); - } - - Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override - { - vsync_hook(mDevice, display, timestamp); - return Void(); - } - -private: - Device* mDevice; -}; -} // namespace anonymous - -void Device::registerCallbacks() -{ - sp<ComposerCallback> callback = new ComposerCallback(this); - mComposer->registerCallback(callback); -} - - -// For use by Display - -void Device::destroyVirtualDisplay(hwc2_display_t display) -{ - ALOGI("Destroying virtual display"); - auto intError = mComposer->destroyVirtualDisplay(display); - auto error = static_cast<Error>(intError); - ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:" - " %s (%d)", display, to_string(error).c_str(), intError); - mDisplays.erase(display); -} - // Display methods -Display::Display(Device& device, hwc2_display_t id) - : mDevice(device), +Display::Display(android::Hwc2::Composer& composer, + const std::unordered_set<Capability>& capabilities, + hwc2_display_t id, DisplayType type) + : mComposer(composer), + mCapabilities(capabilities), mId(id), mIsConnected(false), - mType(DisplayType::Invalid) + mType(type) { ALOGV("Created display %" PRIu64, id); - - auto intError = mDevice.mComposer->getDisplayType(mId, - reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(&mType)); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)", - id, to_string(error).c_str(), intError); - } + setConnected(true); } -Display::~Display() -{ - ALOGV("Destroyed display %" PRIu64, mId); +Display::~Display() { + mLayers.clear(); + if (mType == DisplayType::Virtual) { - mDevice.destroyVirtualDisplay(mId); + ALOGV("Destroying virtual display"); + auto intError = mComposer.destroyVirtualDisplay(mId); + auto error = static_cast<Error>(intError); + ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 + ") failed: %s (%d)", mId, to_string(error).c_str(), intError); + } else if (mType == DisplayType::Physical) { + auto error = setVsyncEnabled(HWC2::Vsync::Disable); + if (error != Error::None) { + ALOGE("~Display: Failed to disable vsync for display %" PRIu64 + ": %s (%d)", mId, to_string(error).c_str(), + static_cast<int32_t>(error)); + } } } @@ -383,22 +286,35 @@ float Display::Config::Builder::getDefaultDensity() { Error Display::acceptChanges() { - auto intError = mDevice.mComposer->acceptDisplayChanges(mId); + auto intError = mComposer.acceptDisplayChanges(mId); return static_cast<Error>(intError); } -Error Display::createLayer(std::shared_ptr<Layer>* outLayer) +Error Display::createLayer(Layer** outLayer) { + if (!outLayer) { + return Error::BadParameter; + } hwc2_layer_t layerId = 0; - auto intError = mDevice.mComposer->createLayer(mId, &layerId); + auto intError = mComposer.createLayer(mId, &layerId); auto error = static_cast<Error>(intError); if (error != Error::None) { return error; } - auto layer = std::make_shared<Layer>(shared_from_this(), layerId); - mLayers.emplace(layerId, layer); - *outLayer = std::move(layer); + auto layer = std::make_unique<Layer>( + mComposer, mCapabilities, mId, layerId); + *outLayer = layer.get(); + mLayers.emplace(layerId, std::move(layer)); + return Error::None; +} + +Error Display::destroyLayer(Layer* layer) +{ + if (!layer) { + return Error::BadParameter; + } + mLayers.erase(layer->getId()); return Error::None; } @@ -407,7 +323,7 @@ Error Display::getActiveConfig( { ALOGV("[%" PRIu64 "] getActiveConfig", mId); hwc2_config_t configId = 0; - auto intError = mDevice.mComposer->getActiveConfig(mId, &configId); + auto intError = mComposer.getActiveConfig(mId, &configId); auto error = static_cast<Error>(intError); if (error != Error::None) { @@ -430,12 +346,12 @@ Error Display::getActiveConfig( } Error Display::getChangedCompositionTypes( - std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes) + std::unordered_map<Layer*, Composition>* outTypes) { std::vector<Hwc2::Layer> layerIds; std::vector<Hwc2::IComposerClient::Composition> types; - auto intError = mDevice.mComposer->getChangedCompositionTypes(mId, - &layerIds, &types); + auto intError = mComposer.getChangedCompositionTypes( + mId, &layerIds, &types); uint32_t numElements = layerIds.size(); auto error = static_cast<Error>(intError); error = static_cast<Error>(intError); @@ -464,7 +380,7 @@ Error Display::getChangedCompositionTypes( Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const { std::vector<Hwc2::ColorMode> modes; - auto intError = mDevice.mComposer->getColorModes(mId, &modes); + auto intError = mComposer.getColorModes(mId, &modes); uint32_t numModes = modes.size(); auto error = static_cast<Error>(intError); if (error != Error::None) { @@ -489,19 +405,18 @@ std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const Error Display::getName(std::string* outName) const { - auto intError = mDevice.mComposer->getDisplayName(mId, outName); + auto intError = mComposer.getDisplayName(mId, outName); return static_cast<Error>(intError); } Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, - std::unordered_map<std::shared_ptr<Layer>, LayerRequest>* - outLayerRequests) + std::unordered_map<Layer*, LayerRequest>* outLayerRequests) { uint32_t intDisplayRequests; std::vector<Hwc2::Layer> layerIds; std::vector<uint32_t> layerRequests; - auto intError = mDevice.mComposer->getDisplayRequests(mId, - &intDisplayRequests, &layerIds, &layerRequests); + auto intError = mComposer.getDisplayRequests( + mId, &intDisplayRequests, &layerIds, &layerRequests); uint32_t numElements = layerIds.size(); auto error = static_cast<Error>(intError); if (error != Error::None) { @@ -535,7 +450,7 @@ Error Display::getType(DisplayType* outType) const Error Display::supportsDoze(bool* outSupport) const { bool intSupport = false; - auto intError = mDevice.mComposer->getDozeSupport(mId, &intSupport); + auto intError = mComposer.getDozeSupport(mId, &intSupport); auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -552,7 +467,7 @@ Error Display::getHdrCapabilities( float maxAverageLuminance = -1.0f; float minLuminance = -1.0f; std::vector<Hwc2::Hdr> intTypes; - auto intError = mDevice.mComposer->getHdrCapabilities(mId, &intTypes, + auto intError = mComposer.getHdrCapabilities(mId, &intTypes, &maxLuminance, &maxAverageLuminance, &minLuminance); auto error = static_cast<HWC2::Error>(intError); @@ -571,25 +486,24 @@ Error Display::getHdrCapabilities( } Error Display::getReleaseFences( - std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const + std::unordered_map<Layer*, sp<Fence>>* outFences) const { std::vector<Hwc2::Layer> layerIds; std::vector<int> fenceFds; - auto intError = mDevice.mComposer->getReleaseFences(mId, - &layerIds, &fenceFds); + auto intError = mComposer.getReleaseFences(mId, &layerIds, &fenceFds); auto error = static_cast<Error>(intError); uint32_t numElements = layerIds.size(); if (error != Error::None) { return error; } - std::unordered_map<std::shared_ptr<Layer>, sp<Fence>> releaseFences; + std::unordered_map<Layer*, sp<Fence>> releaseFences; releaseFences.reserve(numElements); for (uint32_t element = 0; element < numElements; ++element) { auto layer = getLayerById(layerIds[element]); if (layer) { sp<Fence> fence(new Fence(fenceFds[element])); - releaseFences.emplace(std::move(layer), fence); + releaseFences.emplace(layer, fence); } else { ALOGE("getReleaseFences: invalid layer %" PRIu64 " found on display %" PRIu64, layerIds[element], mId); @@ -607,7 +521,7 @@ Error Display::getReleaseFences( Error Display::present(sp<Fence>* outPresentFence) { int32_t presentFenceFd = -1; - auto intError = mDevice.mComposer->presentDisplay(mId, &presentFenceFd); + auto intError = mComposer.presentDisplay(mId, &presentFenceFd); auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -625,7 +539,7 @@ Error Display::setActiveConfig(const std::shared_ptr<const Config>& config) config->getDisplayId(), mId); return Error::BadConfig; } - auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId()); + auto intError = mComposer.setActiveConfig(mId, config->getId()); return static_cast<Error>(intError); } @@ -634,7 +548,7 @@ Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target, { // TODO: Properly encode client target surface damage int32_t fenceFd = acquireFence->dup(); - auto intError = mDevice.mComposer->setClientTarget(mId, slot, target, + auto intError = mComposer.setClientTarget(mId, slot, target, fenceFd, static_cast<Hwc2::Dataspace>(dataspace), std::vector<Hwc2::IComposerClient::Rect>()); return static_cast<Error>(intError); @@ -642,15 +556,15 @@ Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target, Error Display::setColorMode(android_color_mode_t mode) { - auto intError = mDevice.mComposer->setColorMode(mId, - static_cast<Hwc2::ColorMode>(mode)); + auto intError = mComposer.setColorMode( + mId, static_cast<Hwc2::ColorMode>(mode)); return static_cast<Error>(intError); } Error Display::setColorTransform(const android::mat4& matrix, android_color_transform_t hint) { - auto intError = mDevice.mComposer->setColorTransform(mId, + auto intError = mComposer.setColorTransform(mId, matrix.asArray(), static_cast<Hwc2::ColorTransform>(hint)); return static_cast<Error>(intError); } @@ -660,7 +574,7 @@ Error Display::setOutputBuffer(const sp<GraphicBuffer>& buffer, { int32_t fenceFd = releaseFence->dup(); auto handle = buffer->getNativeBuffer()->handle; - auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd); + auto intError = mComposer.setOutputBuffer(mId, handle, fenceFd); close(fenceFd); return static_cast<Error>(intError); } @@ -668,14 +582,14 @@ Error Display::setOutputBuffer(const sp<GraphicBuffer>& buffer, Error Display::setPowerMode(PowerMode mode) { auto intMode = static_cast<Hwc2::IComposerClient::PowerMode>(mode); - auto intError = mDevice.mComposer->setPowerMode(mId, intMode); + auto intError = mComposer.setPowerMode(mId, intMode); return static_cast<Error>(intError); } Error Display::setVsyncEnabled(Vsync enabled) { auto intEnabled = static_cast<Hwc2::IComposerClient::Vsync>(enabled); - auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled); + auto intError = mComposer.setVsyncEnabled(mId, intEnabled); return static_cast<Error>(intError); } @@ -683,8 +597,7 @@ Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests) { uint32_t numTypes = 0; uint32_t numRequests = 0; - auto intError = mDevice.mComposer->validateDisplay(mId, - &numTypes, &numRequests); + auto intError = mComposer.validateDisplay(mId, &numTypes, &numRequests); auto error = static_cast<Error>(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -701,7 +614,8 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests uint32_t numTypes = 0; uint32_t numRequests = 0; int32_t presentFenceFd = -1; - auto intError = mDevice.mComposer->presentOrValidateDisplay(mId, &numTypes, &numRequests, &presentFenceFd, state); + auto intError = mComposer.presentOrValidateDisplay( + mId, &numTypes, &numRequests, &presentFenceFd, state); auto error = static_cast<Error>(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -720,15 +634,23 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests void Display::discardCommands() { - mDevice.mComposer->resetCommands(); + mComposer.resetCommands(); } // For use by Device +void Display::setConnected(bool connected) { + if (!mIsConnected && connected && mType == DisplayType::Physical) { + mComposer.setClientTargetSlotCount(mId); + loadConfigs(); + } + mIsConnected = connected; +} + int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute) { int32_t value = 0; - auto intError = mDevice.mComposer->getDisplayAttribute(mId, configId, + auto intError = mComposer.getDisplayAttribute(mId, configId, static_cast<Hwc2::IComposerClient::Attribute>(attribute), &value); auto error = static_cast<Error>(intError); @@ -760,7 +682,7 @@ void Display::loadConfigs() ALOGV("[%" PRIu64 "] loadConfigs", mId); std::vector<Hwc2::Config> configIds; - auto intError = mDevice.mComposer->getDisplayConfigs(mId, &configIds); + auto intError = mComposer.getDisplayConfigs(mId, &configIds); auto error = static_cast<Error>(intError); if (error != Error::None) { ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId, @@ -773,54 +695,51 @@ void Display::loadConfigs() } } -// For use by Layer - -void Display::destroyLayer(hwc2_layer_t layerId) -{ - auto intError =mDevice.mComposer->destroyLayer(mId, layerId); - auto error = static_cast<Error>(intError); - ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" - " failed: %s (%d)", mId, layerId, to_string(error).c_str(), - intError); - mLayers.erase(layerId); -} - // Other Display methods -std::shared_ptr<Layer> Display::getLayerById(hwc2_layer_t id) const +Layer* Display::getLayerById(hwc2_layer_t id) const { if (mLayers.count(id) == 0) { return nullptr; } - auto layer = mLayers.at(id).lock(); - return layer; + return mLayers.at(id).get(); } // Layer methods -Layer::Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id) - : mDisplay(display), - mDisplayId(display->getId()), - mDevice(display->getDevice()), - mId(id) +Layer::Layer(android::Hwc2::Composer& composer, + const std::unordered_set<Capability>& capabilities, + hwc2_display_t displayId, hwc2_layer_t layerId) + : mComposer(composer), + mCapabilities(capabilities), + mDisplayId(displayId), + mId(layerId) { - ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id, - display->getId()); + ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId); } Layer::~Layer() { - auto display = mDisplay.lock(); - if (display) { - display->destroyLayer(mId); + auto intError = mComposer.destroyLayer(mDisplayId, mId); + auto error = static_cast<Error>(intError); + ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" + " failed: %s (%d)", mDisplayId, mId, to_string(error).c_str(), + intError); + if (mLayerDestroyedListener) { + mLayerDestroyedListener(this); } } +void Layer::setLayerDestroyedListener(std::function<void(Layer*)> listener) { + LOG_ALWAYS_FATAL_IF(mLayerDestroyedListener && listener, + "Attempt to set layer destroyed listener multiple times"); + mLayerDestroyedListener = listener; +} + Error Layer::setCursorPosition(int32_t x, int32_t y) { - auto intError = mDevice.mComposer->setCursorPosition(mDisplayId, - mId, x, y); + auto intError = mComposer.setCursorPosition(mDisplayId, mId, x, y); return static_cast<Error>(intError); } @@ -828,8 +747,8 @@ Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence) { int32_t fenceFd = acquireFence->dup(); - auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId, - mId, slot, buffer, fenceFd); + auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer, + fenceFd); return static_cast<Error>(intError); } @@ -839,7 +758,7 @@ Error Layer::setSurfaceDamage(const Region& damage) // rects for HWC Hwc2::Error intError = Hwc2::Error::NONE; if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) { - intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, + intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, std::vector<Hwc2::IComposerClient::Rect>()); } else { size_t rectCount = 0; @@ -851,8 +770,7 @@ Error Layer::setSurfaceDamage(const Region& damage) rectArray[rect].right, rectArray[rect].bottom}); } - intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, - mId, hwcRects); + intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, hwcRects); } return static_cast<Error>(intError); @@ -861,24 +779,22 @@ Error Layer::setSurfaceDamage(const Region& damage) Error Layer::setBlendMode(BlendMode mode) { auto intMode = static_cast<Hwc2::IComposerClient::BlendMode>(mode); - auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId, - mId, intMode); + auto intError = mComposer.setLayerBlendMode(mDisplayId, mId, intMode); return static_cast<Error>(intError); } Error Layer::setColor(hwc_color_t color) { Hwc2::IComposerClient::Color hwcColor{color.r, color.g, color.b, color.a}; - auto intError = mDevice.mComposer->setLayerColor(mDisplayId, - mId, hwcColor); + auto intError = mComposer.setLayerColor(mDisplayId, mId, hwcColor); return static_cast<Error>(intError); } Error Layer::setCompositionType(Composition type) { auto intType = static_cast<Hwc2::IComposerClient::Composition>(type); - auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId, - mId, intType); + auto intError = mComposer.setLayerCompositionType( + mDisplayId, mId, intType); return static_cast<Error>(intError); } @@ -889,8 +805,7 @@ Error Layer::setDataspace(android_dataspace_t dataspace) } mDataSpace = dataspace; auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace); - auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId, - mId, intDataspace); + auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace); return static_cast<Error>(intError); } @@ -898,27 +813,24 @@ Error Layer::setDisplayFrame(const Rect& frame) { Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top, frame.right, frame.bottom}; - auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId, - mId, hwcRect); + auto intError = mComposer.setLayerDisplayFrame(mDisplayId, mId, hwcRect); return static_cast<Error>(intError); } Error Layer::setPlaneAlpha(float alpha) { - auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId, - mId, alpha); + auto intError = mComposer.setLayerPlaneAlpha(mDisplayId, mId, alpha); return static_cast<Error>(intError); } Error Layer::setSidebandStream(const native_handle_t* stream) { - if (!mDevice.hasCapability(Capability::SidebandStream)) { + if (mCapabilities.count(Capability::SidebandStream) == 0) { ALOGE("Attempted to call setSidebandStream without checking that the " "device supports sideband streams"); return Error::Unsupported; } - auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId, - mId, stream); + auto intError = mComposer.setLayerSidebandStream(mDisplayId, mId, stream); return static_cast<Error>(intError); } @@ -926,16 +838,14 @@ Error Layer::setSourceCrop(const FloatRect& crop) { Hwc2::IComposerClient::FRect hwcRect{ crop.left, crop.top, crop.right, crop.bottom}; - auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId, - mId, hwcRect); + auto intError = mComposer.setLayerSourceCrop(mDisplayId, mId, hwcRect); return static_cast<Error>(intError); } Error Layer::setTransform(Transform transform) { auto intTransform = static_cast<Hwc2::Transform>(transform); - auto intError = mDevice.mComposer->setLayerTransform(mDisplayId, - mId, intTransform); + auto intError = mComposer.setLayerTransform(mDisplayId, mId, intTransform); return static_cast<Error>(intError); } @@ -950,20 +860,19 @@ Error Layer::setVisibleRegion(const Region& region) rectArray[rect].right, rectArray[rect].bottom}); } - auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId, - mId, hwcRects); + auto intError = mComposer.setLayerVisibleRegion(mDisplayId, mId, hwcRects); return static_cast<Error>(intError); } Error Layer::setZOrder(uint32_t z) { - auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z); + auto intError = mComposer.setLayerZOrder(mDisplayId, mId, z); return static_cast<Error>(intError); } Error Layer::setInfo(uint32_t type, uint32_t appId) { - auto intError = mDevice.mComposer->setLayerInfo(mDisplayId, mId, type, appId); + auto intError = mComposer.setLayerInfo(mDisplayId, mId, type, appId); return static_cast<Error>(intError); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 404bb284c5..fbe4c7ebed 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -53,24 +53,37 @@ namespace HWC2 { class Display; class Layer; -typedef std::function<void(std::shared_ptr<Display>, Connection)> - HotplugCallback; -typedef std::function<void(std::shared_ptr<Display>)> RefreshCallback; -typedef std::function<void(std::shared_ptr<Display>, nsecs_t)> VsyncCallback; +// Implement this interface to receive hardware composer events. +// +// These callback functions will generally be called on a hwbinder thread, but +// when first registering the callback the onHotplugReceived() function will +// immediately be called on the thread calling registerCallback(). +// +// All calls receive a sequenceId, which will be the value that was supplied to +// HWC2::Device::registerCallback(). It's used to help differentiate callbacks +// from different hardware composer instances. +class ComposerCallback { + public: + virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, + Connection connection, + bool primaryDisplay) = 0; + virtual void onRefreshReceived(int32_t sequenceId, + hwc2_display_t display) = 0; + virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, + int64_t timestamp) = 0; + virtual ~ComposerCallback() = default; +}; // C++ Wrapper around hwc2_device_t. Load all functions pointers // and handle callback registration. class Device { public: - // useVrComposer is passed to the composer HAL. When true, the composer HAL - // will use the vr composer service, otherwise it uses the real hardware - // composer. - Device(bool useVrComposer); - ~Device(); + // Service name is expected to be 'default' or 'vr' for normal use. + // 'vr' will slightly modify the behavior of the mComposer. + Device(const std::string& serviceName); - friend class HWC2::Display; - friend class HWC2::Layer; + void registerCallback(ComposerCallback* callback, int32_t sequenceId); // Required by HWC2 @@ -82,27 +95,14 @@ public: uint32_t getMaxVirtualDisplayCount() const; Error createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, - std::shared_ptr<Display>* outDisplay); - - void registerHotplugCallback(HotplugCallback hotplug); - void registerRefreshCallback(RefreshCallback refresh); - void registerVsyncCallback(VsyncCallback vsync); + android_pixel_format_t* format, Display** outDisplay); + void destroyDisplay(hwc2_display_t displayId); - // For use by callbacks - - void callHotplug(std::shared_ptr<Display> display, Connection connected); - void callRefresh(std::shared_ptr<Display> display); - void callVsync(std::shared_ptr<Display> display, nsecs_t timestamp); + void onHotplug(hwc2_display_t displayId, Connection connection); // Other Device methods - // This will create a Display if one is not found, but it will not be marked - // as connected. This Display may be null if the display has been torn down - // but has not been removed from the map yet. - std::shared_ptr<Display> getDisplayById(hwc2_display_t id); - - bool hasCapability(HWC2::Capability capability) const; + Display* getDisplayById(hwc2_display_t id); android::Hwc2::Composer* getComposer() { return mComposer.get(); } @@ -110,37 +110,23 @@ private: // Initialization methods void loadCapabilities(); - void registerCallbacks(); - - // For use by Display - - void destroyVirtualDisplay(hwc2_display_t display); // Member variables std::unique_ptr<android::Hwc2::Composer> mComposer; - std::unordered_set<Capability> mCapabilities; - std::unordered_map<hwc2_display_t, std::weak_ptr<Display>> mDisplays; - - HotplugCallback mHotplug; - std::vector<std::pair<std::shared_ptr<Display>, Connection>> - mPendingHotplugs; - RefreshCallback mRefresh; - std::vector<std::shared_ptr<Display>> mPendingRefreshes; - VsyncCallback mVsync; - std::vector<std::pair<std::shared_ptr<Display>, nsecs_t>> mPendingVsyncs; + std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays; + bool mRegisteredCallback; }; // Convenience C++ class to access hwc2_device_t Display functions directly. -class Display : public std::enable_shared_from_this<Display> +class Display { public: - Display(Device& device, hwc2_display_t id); + Display(android::Hwc2::Composer& composer, + const std::unordered_set<Capability>& capabilities, + hwc2_display_t id, DisplayType type); ~Display(); - friend class HWC2::Device; - friend class HWC2::Layer; - class Config { public: @@ -213,12 +199,12 @@ public: // Required by HWC2 [[clang::warn_unused_result]] Error acceptChanges(); - [[clang::warn_unused_result]] Error createLayer( - std::shared_ptr<Layer>* outLayer); + [[clang::warn_unused_result]] Error createLayer(Layer** outLayer); + [[clang::warn_unused_result]] Error destroyLayer(Layer* layer); [[clang::warn_unused_result]] Error getActiveConfig( std::shared_ptr<const Config>* outConfig) const; [[clang::warn_unused_result]] Error getChangedCompositionTypes( - std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes); + std::unordered_map<Layer*, Composition>* outTypes); [[clang::warn_unused_result]] Error getColorModes( std::vector<android_color_mode_t>* outModes) const; @@ -228,14 +214,13 @@ public: [[clang::warn_unused_result]] Error getName(std::string* outName) const; [[clang::warn_unused_result]] Error getRequests( DisplayRequest* outDisplayRequests, - std::unordered_map<std::shared_ptr<Layer>, LayerRequest>* - outLayerRequests); + std::unordered_map<Layer*, LayerRequest>* outLayerRequests); [[clang::warn_unused_result]] Error getType(DisplayType* outType) const; [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const; [[clang::warn_unused_result]] Error getHdrCapabilities( std::unique_ptr<android::HdrCapabilities>* outCapabilities) const; [[clang::warn_unused_result]] Error getReleaseFences( - std::unordered_map<std::shared_ptr<Layer>, + std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const; [[clang::warn_unused_result]] Error present( android::sp<android::Fence>* outPresentFence); @@ -267,32 +252,31 @@ public: // Other Display methods - Device& getDevice() const { return mDevice; } hwc2_display_t getId() const { return mId; } bool isConnected() const { return mIsConnected; } + void setConnected(bool connected); // For use by Device only private: - // For use by Device - - void setConnected(bool connected) { mIsConnected = connected; } int32_t getAttribute(hwc2_config_t configId, Attribute attribute); void loadConfig(hwc2_config_t configId); void loadConfigs(); - // For use by Layer - void destroyLayer(hwc2_layer_t layerId); - // This may fail (and return a null pointer) if no layer with this ID exists // on this display - std::shared_ptr<Layer> getLayerById(hwc2_layer_t id) const; + Layer* getLayerById(hwc2_layer_t id) const; // Member variables - Device& mDevice; + // These are references to data owned by HWC2::Device, which will outlive + // this HWC2::Display, so these references are guaranteed to be valid for + // the lifetime of this object. + android::Hwc2::Composer& mComposer; + const std::unordered_set<Capability>& mCapabilities; + hwc2_display_t mId; bool mIsConnected; DisplayType mType; - std::unordered_map<hwc2_layer_t, std::weak_ptr<Layer>> mLayers; + std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers; // The ordering in this map matters, for getConfigs(), when it is // converted to a vector std::map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs; @@ -302,12 +286,18 @@ private: class Layer { public: - Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id); + Layer(android::Hwc2::Composer& composer, + const std::unordered_set<Capability>& capabilities, + hwc2_display_t displayId, hwc2_layer_t layerId); ~Layer(); - bool isAbandoned() const { return mDisplay.expired(); } hwc2_layer_t getId() const { return mId; } + // Register a listener to be notified when the layer is destroyed. When the + // listener function is called, the Layer will be in the process of being + // destroyed, so it's not safe to call methods on it. + void setLayerDestroyedListener(std::function<void(Layer*)> listener); + [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y); [[clang::warn_unused_result]] Error setBuffer(uint32_t slot, const android::sp<android::GraphicBuffer>& buffer, @@ -334,11 +324,16 @@ public: [[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId); private: - std::weak_ptr<Display> mDisplay; + // These are references to data owned by HWC2::Device, which will outlive + // this HWC2::Layer, so these references are guaranteed to be valid for + // the lifetime of this object. + android::Hwc2::Composer& mComposer; + const std::unordered_set<Capability>& mCapabilities; + hwc2_display_t mDisplayId; - Device& mDevice; hwc2_layer_t mId; android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + std::function<void(Layer*)> mLayerDestroyedListener; }; } // namespace HWC2 diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index ac2dde29d4..b096a3ae57 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -59,13 +59,12 @@ namespace android { // --------------------------------------------------------------------------- -HWComposer::HWComposer(bool useVrComposer) +HWComposer::HWComposer(const std::string& serviceName) : mHwcDevice(), mDisplayData(2), mFreeDisplaySlots(), mHwcDisplaySlots(), mCBContext(), - mEventHandler(nullptr), mVSyncCounts(), mRemainingHwcVirtualDisplays(0) { @@ -74,40 +73,15 @@ HWComposer::HWComposer(bool useVrComposer) mVSyncCounts[i] = 0; } - loadHwcModule(useVrComposer); + mHwcDevice = std::make_unique<HWC2::Device>(serviceName); + mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); } HWComposer::~HWComposer() {} -void HWComposer::setEventHandler(EventHandler* handler) -{ - if (handler == nullptr) { - ALOGE("setEventHandler: Rejected attempt to clear handler"); - return; - } - - bool wasNull = (mEventHandler == nullptr); - mEventHandler = handler; - - if (wasNull) { - auto hotplugHook = std::bind(&HWComposer::hotplug, this, - std::placeholders::_1, std::placeholders::_2); - mHwcDevice->registerHotplugCallback(hotplugHook); - auto invalidateHook = std::bind(&HWComposer::invalidate, this, - std::placeholders::_1); - mHwcDevice->registerRefreshCallback(invalidateHook); - auto vsyncHook = std::bind(&HWComposer::vsync, this, - std::placeholders::_1, std::placeholders::_2); - mHwcDevice->registerVsyncCallback(vsyncHook); - } -} - -// Load and prepare the hardware composer module. Sets mHwc. -void HWComposer::loadHwcModule(bool useVrComposer) -{ - ALOGV("loadHwcModule"); - mHwcDevice = std::make_unique<HWC2::Device>(useVrComposer); - mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); +void HWComposer::registerCallback(HWC2::ComposerCallback* callback, + int32_t sequenceId) { + mHwcDevice->registerCallback(callback, sequenceId); } bool HWComposer::hasCapability(HWC2::Capability capability) const @@ -145,54 +119,51 @@ void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) { } } -void HWComposer::hotplug(const std::shared_ptr<HWC2::Display>& display, - HWC2::Connection connected) { - ALOGV("hotplug: %" PRIu64 ", %s", display->getId(), - to_string(connected).c_str()); - int32_t disp = 0; +void HWComposer::onHotplug(hwc2_display_t displayId, + HWC2::Connection connection) { + ALOGV("hotplug: %" PRIu64 ", %s", displayId, + to_string(connection).c_str()); + mHwcDevice->onHotplug(displayId, connection); if (!mDisplayData[0].hwcDisplay) { - ALOGE_IF(connected != HWC2::Connection::Connected, "Assumed primary" + ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary" " display would be connected"); - mDisplayData[0].hwcDisplay = display; - mHwcDisplaySlots[display->getId()] = 0; - disp = DisplayDevice::DISPLAY_PRIMARY; + mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId); + mHwcDisplaySlots[displayId] = 0; } else { // Disconnect is handled through HWComposer::disconnectDisplay via // SurfaceFlinger's onHotplugReceived callback handling - if (connected == HWC2::Connection::Connected) { - mDisplayData[1].hwcDisplay = display; - mHwcDisplaySlots[display->getId()] = 1; + if (connection == HWC2::Connection::Connected) { + mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId); + mHwcDisplaySlots[displayId] = 1; } - disp = DisplayDevice::DISPLAY_EXTERNAL; } - mEventHandler->onHotplugReceived(this, disp, - connected == HWC2::Connection::Connected); -} - -void HWComposer::invalidate(const std::shared_ptr<HWC2::Display>& /*display*/) { - mEventHandler->onInvalidateReceived(this); } -void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display, - int64_t timestamp) { +bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp, + int32_t* outDisplay) { + auto display = mHwcDevice->getDisplayById(displayId); + if (!display) { + ALOGE("onVsync Failed to find display %" PRIu64, displayId); + return false; + } auto displayType = HWC2::DisplayType::Invalid; auto error = display->getType(&displayType); if (error != HWC2::Error::None) { - ALOGE("vsync: Failed to determine type of display %" PRIu64, + ALOGE("onVsync: Failed to determine type of display %" PRIu64, display->getId()); - return; + return false; } if (displayType == HWC2::DisplayType::Virtual) { ALOGE("Virtual display %" PRIu64 " passed to vsync callback", display->getId()); - return; + return false; } if (mHwcDisplaySlots.count(display->getId()) == 0) { ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback", display->getId()); - return; + return false; } int32_t disp = mHwcDisplaySlots[display->getId()]; @@ -206,17 +177,21 @@ void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display, if (timestamp == mLastHwVSync[disp]) { ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", timestamp); - return; + return false; } mLastHwVSync[disp] = timestamp; } + if (outDisplay) { + *outDisplay = disp; + } + char tag[16]; snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); - mEventHandler->onVSyncReceived(this, disp, timestamp); + return true; } status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, @@ -235,7 +210,7 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, return INVALID_OPERATION; } - std::shared_ptr<HWC2::Display> display; + HWC2::Display* display; auto error = mHwcDevice->createVirtualDisplay(width, height, format, &display); if (error != HWC2::Error::None) { @@ -264,13 +239,13 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, return NO_ERROR; } -std::shared_ptr<HWC2::Layer> HWComposer::createLayer(int32_t displayId) { +HWC2::Layer* HWComposer::createLayer(int32_t displayId) { if (!isValidDisplay(displayId)) { ALOGE("Failed to create layer on invalid display %d", displayId); return nullptr; } auto display = mDisplayData[displayId].hwcDisplay; - std::shared_ptr<HWC2::Layer> layer; + HWC2::Layer* layer; auto error = display->createLayer(&layer); if (error != HWC2::Error::None) { ALOGE("Failed to create layer on display %d: %s (%d)", displayId, @@ -280,6 +255,19 @@ std::shared_ptr<HWC2::Layer> HWComposer::createLayer(int32_t displayId) { return layer; } +void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) { + if (!isValidDisplay(displayId)) { + ALOGE("Failed to destroy layer on invalid display %d", displayId); + return; + } + auto display = mDisplayData[displayId].hwcDisplay; + auto error = display->destroyLayer(layer); + if (error != HWC2::Error::None) { + ALOGE("Failed to destroy layer on display %d: %s (%d)", displayId, + to_string(error).c_str(), static_cast<int32_t>(error)); + } +} + nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const { // this returns the last refresh timestamp. // if the last one is not available, we estimate it based on @@ -347,10 +335,8 @@ std::vector<android_color_mode_t> HWComposer::getColorModes(int32_t displayId) c displayId); return modes; } - const std::shared_ptr<HWC2::Display>& hwcDisplay = - mDisplayData[displayId].hwcDisplay; - auto error = hwcDisplay->getColorModes(&modes); + auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes); if (error != HWC2::Error::None) { ALOGE("getColorModes failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast<int32_t>(error)); @@ -470,7 +456,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { return UNKNOWN_ERROR; } if (state == 1) { //Present Succeeded. - std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences; + std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); displayData.releaseFences = std::move(releaseFences); displayData.lastPresentFence = outPresentFence; @@ -489,8 +475,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { return BAD_INDEX; } - std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::Composition> - changedTypes; + std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes; changedTypes.reserve(numTypes); error = hwcDisplay->getChangedCompositionTypes(&changedTypes); if (error != HWC2::Error::None) { @@ -502,8 +487,7 @@ status_t HWComposer::prepare(DisplayDevice& displayDevice) { displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0); - std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::LayerRequest> - layerRequests; + std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests; layerRequests.reserve(numRequests); error = hwcDisplay->getRequests(&displayData.displayRequests, &layerRequests); @@ -597,7 +581,7 @@ sp<Fence> HWComposer::getPresentFence(int32_t displayId) const { } sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId, - const std::shared_ptr<HWC2::Layer>& layer) const { + HWC2::Layer* layer) const { if (!isValidDisplay(displayId)) { ALOGE("getLayerReleaseFence: Invalid display"); return Fence::NO_FENCE; @@ -638,7 +622,7 @@ status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) { return UNKNOWN_ERROR; } - std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences; + std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); if (error != HWC2::Error::None) { ALOGE("presentAndGetReleaseFences: Failed to get release fences " @@ -786,6 +770,8 @@ void HWComposer::disconnectDisplay(int displayId) { auto hwcId = displayData.hwcDisplay->getId(); mHwcDisplaySlots.erase(hwcId); displayData.reset(); + + mHwcDevice->destroyDisplay(hwcId); } status_t HWComposer::setOutputBuffer(int32_t displayId, @@ -884,7 +870,7 @@ void HWComposer::dump(String8& result) const { HWComposer::DisplayData::DisplayData() : hasClientComposition(false), hasDeviceComposition(false), - hwcDisplay(), + hwcDisplay(nullptr), lastPresentFence(Fence::NO_FENCE), outbufHandle(nullptr), outbufAcquireFence(Fence::NO_FENCE), diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 7463362c35..3640bb5a98 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -65,24 +65,14 @@ class String8; class HWComposer { public: - class EventHandler { - friend class HWComposer; - virtual void onVSyncReceived( - HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0; - virtual void onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) = 0; - virtual void onInvalidateReceived(HWComposer* composer) = 0; - protected: - virtual ~EventHandler() {} - }; - - // useVrComposer is passed to the composer HAL. When true, the composer HAL - // will use the vr composer service, otherwise it uses the real hardware - // composer. - HWComposer(bool useVrComposer); + // Uses the named composer service. Valid choices for normal use + // are 'default' and 'vr'. + HWComposer(const std::string& serviceName); ~HWComposer(); - void setEventHandler(EventHandler* handler); + void registerCallback(HWC2::ComposerCallback* callback, + int32_t sequenceId); bool hasCapability(HWC2::Capability capability) const; @@ -92,7 +82,9 @@ public: android_pixel_format_t* format, int32_t* outId); // Attempts to create a new layer on this display - std::shared_ptr<HWC2::Layer> createLayer(int32_t displayId); + HWC2::Layer* createLayer(int32_t displayId); + // Destroy a previously created layer + void destroyLayer(int32_t displayId, HWC2::Layer* layer); // Asks the HAL what it can do status_t prepare(DisplayDevice& displayDevice); @@ -127,7 +119,7 @@ public: // Get last release fence for the given layer sp<Fence> getLayerReleaseFence(int32_t displayId, - const std::shared_ptr<HWC2::Layer>& layer) const; + HWC2::Layer* layer) const; // Set the output buffer and acquire fence for a virtual display. // Returns INVALID_OPERATION if displayId is not a virtual display. @@ -143,6 +135,12 @@ public: // Events handling --------------------------------------------------------- + // Returns true if successful, false otherwise. The + // DisplayDevice::DisplayType of the display is returned as an output param. + bool onVsync(hwc2_display_t displayId, int64_t timestamp, + int32_t* outDisplay); + void onHotplug(hwc2_display_t displayId, HWC2::Connection connection); + void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled); // Query display parameters. Pass in a display index (e.g. @@ -170,19 +168,11 @@ public: private: static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2; - void loadHwcModule(bool useVrComposer); - bool isValidDisplay(int32_t displayId) const; static void validateChange(HWC2::Composition from, HWC2::Composition to); struct cb_context; - void invalidate(const std::shared_ptr<HWC2::Display>& display); - void vsync(const std::shared_ptr<HWC2::Display>& display, - int64_t timestamp); - void hotplug(const std::shared_ptr<HWC2::Display>& display, - HWC2::Connection connected); - struct DisplayData { DisplayData(); ~DisplayData(); @@ -190,11 +180,10 @@ private: bool hasClientComposition; bool hasDeviceComposition; - std::shared_ptr<HWC2::Display> hwcDisplay; + HWC2::Display* hwcDisplay; HWC2::DisplayRequest displayRequests; sp<Fence> lastPresentFence; // signals when the last set op retires - std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> - releaseFences; + std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; buffer_handle_t outbufHandle; sp<Fence> outbufAcquireFence; mutable std::unordered_map<int32_t, @@ -215,7 +204,6 @@ private: mutable Mutex mDisplayLock; cb_context* mCBContext; - EventHandler* mEventHandler; size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]; uint32_t mRemainingHwcVirtualDisplays; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index c129ae546c..1de5e48cb9 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -345,8 +345,9 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) { LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId); - status_t result = mSource[source]->dequeueBuffer(sslot, fence, - mSinkBufferWidth, mSinkBufferHeight, format, usage, nullptr); + status_t result = + mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight, + format, usage, nullptr, nullptr); if (result < 0) return result; int pslot = mapSource2ProducerSlot(source, *sslot); @@ -384,12 +385,13 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, return result; } -status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, - uint32_t w, uint32_t h, PixelFormat format, uint64_t usage, - FrameEventHistoryDelta* outTimestamps) { +status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h, + PixelFormat format, uint64_t usage, + uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) { if (mDisplayId < 0) { - return mSource[SOURCE_SINK]->dequeueBuffer( - pslot, fence, w, h, format, usage, outTimestamps); + return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge, + outTimestamps); } VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, @@ -449,6 +451,9 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, *pslot = mapSource2ProducerSlot(source, sslot); } } + if (outBufferAge) { + *outBufferAge = 0; + } return result; } @@ -622,6 +627,10 @@ status_t VirtualDisplaySurface::getUniqueId(uint64_t* /*outId*/) const { return INVALID_OPERATION; } +status_t VirtualDisplaySurface::getConsumerUsage(uint64_t* outUsage) const { + return mSource[SOURCE_SINK]->getConsumerUsage(outUsage); +} + void VirtualDisplaySurface::updateQueueBufferOutput( QueueBufferOutput&& qbo) { mQueueBufferOutput = std::move(qbo); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 7f8b39b62b..1671aba1d8 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -104,9 +104,9 @@ private: virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf); virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); - virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, - uint32_t h, PixelFormat format, uint64_t usage, - FrameEventHistoryDelta *outTimestamps); + virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h, + PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); @@ -130,6 +130,7 @@ private: virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) override; virtual status_t getUniqueId(uint64_t* outId) const override; + virtual status_t getConsumerUsage(uint64_t* outUsage) const override; // // Utility methods diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp index ee6e886d12..052a959724 100644 --- a/services/surfaceflinger/EventControlThread.cpp +++ b/services/surfaceflinger/EventControlThread.cpp @@ -31,34 +31,35 @@ void EventControlThread::setVsyncEnabled(bool enabled) { } bool EventControlThread::threadLoop() { - Mutex::Autolock lock(mMutex); - - bool vsyncEnabled = mVsyncEnabled; - -#ifdef USE_HWC2 - mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); -#else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, - mVsyncEnabled); -#endif + enum class VsyncState {Unset, On, Off}; + auto currentVsyncState = VsyncState::Unset; while (true) { - status_t err = mCond.wait(mMutex); - if (err != NO_ERROR) { - ALOGE("error waiting for new events: %s (%d)", - strerror(-err), err); - return false; + auto requestedVsyncState = VsyncState::On; + { + Mutex::Autolock lock(mMutex); + requestedVsyncState = + mVsyncEnabled ? VsyncState::On : VsyncState::Off; + while (currentVsyncState == requestedVsyncState) { + status_t err = mCond.wait(mMutex); + if (err != NO_ERROR) { + ALOGE("error waiting for new events: %s (%d)", + strerror(-err), err); + return false; + } + requestedVsyncState = + mVsyncEnabled ? VsyncState::On : VsyncState::Off; + } } - if (vsyncEnabled != mVsyncEnabled) { + bool enable = requestedVsyncState == VsyncState::On; #ifdef USE_HWC2 - mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); + mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable); #else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, - SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled); + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, + SurfaceFlinger::EVENT_VSYNC, enable); #endif - vsyncEnabled = mVsyncEnabled; - } + currentVsyncState = requestedVsyncState; } return false; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 1b864fd2d8..e92565fd9c 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -40,6 +40,7 @@ #include <gui/BufferItem.h> #include <gui/BufferQueue.h> +#include <gui/LayerDebugInfo.h> #include <gui/Surface.h> #include "clz.h" @@ -200,6 +201,14 @@ Layer::~Layer() { } mFlinger->deleteTextureAsync(mTextureName); mFrameTracker.logAndResetStats(mName); + +#ifdef USE_HWC2 + if (!mHwcLayers.empty()) { + ALOGE("Found stale hardware composer layers when destroying " + "surface flinger layer %s", mName.string()); + destroyAllHwcLayers(); + } +#endif } // --------------------------------------------------------------------------- @@ -287,22 +296,29 @@ void Layer::onSidebandStreamChanged() { } } -// called with SurfaceFlinger::mStateLock from the drawing thread after -// the layer has been remove from the current state list (and just before -// it's removed from the drawing state list) -void Layer::onRemoved() { +void Layer::onRemovedFromCurrentState() { + // the layer is removed from SF mCurrentState to mLayersPendingRemoval + if (mCurrentState.zOrderRelativeOf != nullptr) { sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote(); if (strongRelative != nullptr) { strongRelative->removeZOrderRelative(this); + mFlinger->setTransactionFlags(eTraversalNeeded); } mCurrentState.zOrderRelativeOf = nullptr; } - mSurfaceFlingerConsumer->abandon(); + for (const auto& child : mCurrentChildren) { + child->onRemovedFromCurrentState(); + } +} +void Layer::onRemoved() { + // the layer is removed from SF mLayersPendingRemoval + + mSurfaceFlingerConsumer->abandon(); #ifdef USE_HWC2 - clearHwcLayers(); + destroyAllHwcLayers(); #endif for (const auto& child : mCurrentChildren) { @@ -363,6 +379,48 @@ sp<IGraphicBufferProducer> Layer::getProducer() const { // h/w composer set-up // --------------------------------------------------------------------------- +#ifdef USE_HWC2 +bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) { + LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, + "Already have a layer for hwcId %d", hwcId); + HWC2::Layer* layer = hwc->createLayer(hwcId); + if (!layer) { + return false; + } + HWCInfo& hwcInfo = mHwcLayers[hwcId]; + hwcInfo.hwc = hwc; + hwcInfo.layer = layer; + layer->setLayerDestroyedListener( + [this, hwcId] (HWC2::Layer* /*layer*/){mHwcLayers.erase(hwcId);}); + return true; +} + +void Layer::destroyHwcLayer(int32_t hwcId) { + if (mHwcLayers.count(hwcId) == 0) { + return; + } + auto& hwcInfo = mHwcLayers[hwcId]; + LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, + "Attempt to destroy null layer"); + LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer"); + hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer); + // The layer destroyed listener should have cleared the entry from + // mHwcLayers. Verify that. + LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, + "Stale layer entry in mHwcLayers"); +} + +void Layer::destroyAllHwcLayers() { + size_t numLayers = mHwcLayers.size(); + for (size_t i = 0; i < numLayers; ++i) { + LOG_ALWAYS_FATAL_IF(mHwcLayers.empty(), "destroyAllHwcLayers failed"); + destroyHwcLayer(mHwcLayers.begin()->first); + } + LOG_ALWAYS_FATAL_IF(!mHwcLayers.empty(), + "All hardware composer layers should have been destroyed"); +} +#endif + Rect Layer::getContentCrop() const { // this is the crop rectangle that applies to the buffer // itself (as opposed to the window) @@ -1309,7 +1367,8 @@ bool Layer::headFenceHasSignaled() const { // able to be latched. To avoid this, grab this buffer anyway. return true; } - return mQueueItems[0].mFence->getSignalTime() != INT64_MAX; + return mQueueItems[0].mFenceTime->getSignalTime() != + Fence::SIGNAL_TIME_PENDING; #else return true; #endif @@ -2011,9 +2070,6 @@ bool Layer::onPreComposition(nsecs_t refreshStartTime) { bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence, const std::shared_ptr<FenceTime>& presentFence, const CompositorTiming& compositorTiming) { - mAcquireTimeline.updateSignalTimes(); - mReleaseTimeline.updateSignalTimes(); - // mFrameLatencyNeeded is true when a new frame was latched for the // composition. if (!mFrameLatencyNeeded) @@ -2064,6 +2120,7 @@ void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { auto releaseFenceTime = std::make_shared<FenceTime>( mSurfaceFlingerConsumer->getPrevFinalReleaseFence()); + mReleaseTimeline.updateSignalTimes(); mReleaseTimeline.push(releaseFenceTime); Mutex::Autolock lock(mFrameEventHistoryMutex); @@ -2254,6 +2311,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) #ifndef USE_HWC2 auto releaseFenceTime = std::make_shared<FenceTime>( mSurfaceFlingerConsumer->getPrevFinalReleaseFence()); + mReleaseTimeline.updateSignalTimes(); mReleaseTimeline.push(releaseFenceTime); if (mPreviousFrameNumber != 0) { mFrameEventHistory.addRelease(mPreviousFrameNumber, @@ -2363,69 +2421,51 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { // debugging // ---------------------------------------------------------------------------- -void Layer::dump(String8& result, Colorizer& colorizer) const -{ - const Layer::State& s(getDrawingState()); - - colorizer.colorize(result, Colorizer::GREEN); - result.appendFormat( - "+ %s %p (%s)\n", - getTypeId(), this, getName().string()); - colorizer.reset(result); - - s.activeTransparentRegion.dump(result, "transparentRegion"); - visibleRegion.dump(result, "visibleRegion"); - surfaceDamageRegion.dump(result, "surfaceDamageRegion"); - sp<Client> client(mClientRef.promote()); - PixelFormat pf = PIXEL_FORMAT_UNKNOWN; - const sp<GraphicBuffer>& buffer(getActiveBuffer()); - if (buffer != NULL) { - pf = buffer->getPixelFormat(); - } - - result.appendFormat( " " - "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), " - "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), " - "isOpaque=%1d, invalidate=%1d, " - "dataspace=%s, pixelformat=%s " -#ifdef USE_HWC2 - "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" -#else - "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" -#endif - " client=%p\n", - getLayerStack(), s.z, - s.active.transform.tx(), s.active.transform.ty(), - s.active.w, s.active.h, - s.crop.left, s.crop.top, - s.crop.right, s.crop.bottom, - s.finalCrop.left, s.finalCrop.top, - s.finalCrop.right, s.finalCrop.bottom, - isOpaque(s), contentDirty, - dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(), - s.alpha, s.flags, - s.active.transform[0][0], s.active.transform[0][1], - s.active.transform[1][0], s.active.transform[1][1], - client.get()); - - sp<const GraphicBuffer> buf0(mActiveBuffer); - uint32_t w0=0, h0=0, s0=0, f0=0; - if (buf0 != 0) { - w0 = buf0->getWidth(); - h0 = buf0->getHeight(); - s0 = buf0->getStride(); - f0 = buf0->format; - } - result.appendFormat( - " " - "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," - " queued-frames=%d, mRefreshPending=%d\n", - mFormat, w0, h0, s0,f0, - mQueuedFrames, mRefreshPending); - - if (mSurfaceFlingerConsumer != 0) { - mSurfaceFlingerConsumer->dumpState(result, " "); +LayerDebugInfo Layer::getLayerDebugInfo() const { + LayerDebugInfo info; + const Layer::State& ds = getDrawingState(); + info.mName = getName(); + sp<Layer> parent = getParent(); + info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string()); + info.mType = String8(getTypeId()); + info.mTransparentRegion = ds.activeTransparentRegion; + info.mVisibleRegion = visibleRegion; + info.mSurfaceDamageRegion = surfaceDamageRegion; + info.mLayerStack = getLayerStack(); + info.mX = ds.active.transform.tx(); + info.mY = ds.active.transform.ty(); + info.mZ = ds.z; + info.mWidth = ds.active.w; + info.mHeight = ds.active.h; + info.mCrop = ds.crop; + info.mFinalCrop = ds.finalCrop; + info.mAlpha = ds.alpha; + info.mFlags = ds.flags; + info.mPixelFormat = getPixelFormat(); + info.mDataSpace = getDataSpace(); + info.mMatrix[0][0] = ds.active.transform[0][0]; + info.mMatrix[0][1] = ds.active.transform[0][1]; + info.mMatrix[1][0] = ds.active.transform[1][0]; + info.mMatrix[1][1] = ds.active.transform[1][1]; + { + sp<const GraphicBuffer> activeBuffer = getActiveBuffer(); + if (activeBuffer != 0) { + info.mActiveBufferWidth = activeBuffer->getWidth(); + info.mActiveBufferHeight = activeBuffer->getHeight(); + info.mActiveBufferStride = activeBuffer->getStride(); + info.mActiveBufferFormat = activeBuffer->format; + } else { + info.mActiveBufferWidth = 0; + info.mActiveBufferHeight = 0; + info.mActiveBufferStride = 0; + info.mActiveBufferFormat = 0; + } } + info.mNumQueuedFrames = getQueuedFrameCount(); + info.mRefreshPending = isBufferLatched(); + info.mIsOpaque = isOpaque(ds); + info.mContentDirty = contentDirty; + return info; } #ifdef USE_HWC2 @@ -2509,6 +2549,12 @@ void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta *outDelta) { Mutex::Autolock lock(mFrameEventHistoryMutex); if (newTimestamps) { + // If there are any unsignaled fences in the aquire timeline at this + // point, the previously queued frame hasn't been latched yet. Go ahead + // and try to get the signal time here so the syscall is taken out of + // the main thread's critical path. + mAcquireTimeline.updateSignalTimes(); + // Push the new fence after updating since it's likely still pending. mAcquireTimeline.push(newTimestamps->acquireFence); mFrameEventHistory.addQueue(*newTimestamps); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2306d1a43a..f7b82e4fb7 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -60,6 +60,7 @@ class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; +class LayerDebugInfo; // --------------------------------------------------------------------------- @@ -419,8 +420,14 @@ public: bool isPotentialCursor() const { return mPotentialCursor;} /* - * called with the state lock when the surface is removed from the - * current list + * called with the state lock from a binder thread when the layer is + * removed from the current list to the pending removal list + */ + void onRemovedFromCurrentState(); + + /* + * called with the state lock from the main thread when the layer is + * removed from the pending removal list */ void onRemoved(); @@ -441,40 +448,26 @@ public: bool hasQueuedFrame() const { return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; } + int32_t getQueuedFrameCount() const { return mQueuedFrames; } + #ifdef USE_HWC2 // ----------------------------------------------------------------------- + bool createHwcLayer(HWComposer* hwc, int32_t hwcId); + void destroyHwcLayer(int32_t hwcId); + void destroyAllHwcLayers(); + bool hasHwcLayer(int32_t hwcId) { - if (mHwcLayers.count(hwcId) == 0) { - return false; - } - if (mHwcLayers[hwcId].layer->isAbandoned()) { - ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId); - mHwcLayers.erase(hwcId); - return false; - } - return true; + return mHwcLayers.count(hwcId) > 0; } - std::shared_ptr<HWC2::Layer> getHwcLayer(int32_t hwcId) { + HWC2::Layer* getHwcLayer(int32_t hwcId) { if (mHwcLayers.count(hwcId) == 0) { return nullptr; } return mHwcLayers[hwcId].layer; } - void setHwcLayer(int32_t hwcId, std::shared_ptr<HWC2::Layer>&& layer) { - if (layer) { - mHwcLayers[hwcId].layer = layer; - } else { - mHwcLayers.erase(hwcId); - } - } - - void clearHwcLayers() { - mHwcLayers.clear(); - } - #endif // ----------------------------------------------------------------------- @@ -489,9 +482,9 @@ public: inline const State& getCurrentState() const { return mCurrentState; } inline State& getCurrentState() { return mCurrentState; } + LayerDebugInfo getLayerDebugInfo() const; /* always call base class first */ - void dump(String8& result, Colorizer& colorizer) const; #ifdef USE_HWC2 static void miniDumpHeader(String8& result); void miniDump(String8& result, int32_t hwcId) const; @@ -689,6 +682,9 @@ public: sp<IGraphicBufferProducer> getProducer() const; const String8& getName() const; void notifyAvailableFrames(); + + PixelFormat getPixelFormat() const { return mFormat; } + private: // ----------------------------------------------------------------------- @@ -760,12 +756,14 @@ private: // HWC items, accessed from the main thread struct HWCInfo { HWCInfo() - : layer(), + : hwc(nullptr), + layer(nullptr), forceClientComposition(false), compositionType(HWC2::Composition::Invalid), clearClientTarget(false) {} - std::shared_ptr<HWC2::Layer> layer; + HWComposer* hwc; + HWC2::Layer* layer; bool forceClientComposition; HWC2::Composition compositionType; bool clearClientTarget; diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index e717632c0f..1a5a85e079 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -68,11 +68,11 @@ status_t MonitoredProducer::setAsyncMode(bool async) { return mProducer->setAsyncMode(async); } -status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, - uint32_t w, uint32_t h, PixelFormat format, uint64_t usage, - FrameEventHistoryDelta* outTimestamps) { - return mProducer->dequeueBuffer( - slot, fence, w, h, format, usage, outTimestamps); +status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, + PixelFormat format, uint64_t usage, + uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) { + return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps); } status_t MonitoredProducer::detachBuffer(int slot) { @@ -158,6 +158,10 @@ status_t MonitoredProducer::getUniqueId(uint64_t* outId) const { return mProducer->getUniqueId(outId); } +status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const { + return mProducer->getConsumerUsage(outUsage); +} + IBinder* MonitoredProducer::onAsBinder() { return this; } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index 58b9bc4e2e..1246d142f3 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -39,9 +39,9 @@ public: virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); - virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, - uint32_t h, PixelFormat format, uint64_t usage, - FrameEventHistoryDelta* outTimestamps); + virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, + PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); @@ -68,6 +68,7 @@ public: virtual status_t setAutoRefresh(bool autoRefresh) override; virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override; virtual status_t getUniqueId(uint64_t* outId) const override; + virtual status_t getConsumerUsage(uint64_t* outUsage) const override; // The Layer which created this producer, and on which queued Buffer's will be displayed. sp<Layer> getLayer() const; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index ac2d8b2aba..56e9ac07ad 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -26,7 +26,7 @@ #include <vector> #include <SurfaceFlinger.h> -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); // --------------------------------------------------------------------------- namespace android { @@ -64,7 +64,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f "EGL_ANDROIDX_no_config_context") && !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), "EGL_KHR_no_config_context")) { - config = chooseEglConfig(display, hwcFormat); + config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint renderableType = 0; @@ -108,7 +108,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f EGLConfig dummyConfig = config; if (dummyConfig == EGL_NO_CONFIG) { - dummyConfig = chooseEglConfig(display, hwcFormat); + dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs); @@ -406,7 +406,8 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, return err; } -EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { +EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, + bool logConfig) { status_t err; EGLConfig config; @@ -427,18 +428,20 @@ EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { } } - // print some debugging info - EGLint r,g,b,a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); - ALOGI("EGL information:"); - ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); - ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); - ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); - ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + if (logConfig) { + // print some debugging info + EGLint r,g,b,a; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); + ALOGI("EGL information:"); + ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); + ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); + ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + } return config; } diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 56f582755e..954457946e 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -64,7 +64,7 @@ public: }; static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags); - static EGLConfig chooseEglConfig(EGLDisplay display, int format); + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); void primeCache() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8ed6686ebf..6a01f308a3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -46,6 +46,7 @@ #include <gui/BufferQueue.h> #include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> +#include <gui/LayerDebugInfo.h> #include <gui/Surface.h> #include <ui/GraphicBufferAllocator.h> @@ -76,6 +77,7 @@ #include "MonitoredProducer.h" #include "SurfaceFlinger.h" +#include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" @@ -96,14 +98,28 @@ */ #define DEBUG_SCREENSHOTS false -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { - using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +namespace { +class ConditionalLock { +public: + ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) { + if (lock) { + mMutex.lock(); + } + } + ~ConditionalLock() { if (mLocked) mMutex.unlock(); } +private: + Mutex& mMutex; + bool mLocked; +}; +} // namespace anonymous + // --------------------------------------------------------------------------- const String16 sHardwareTest("android.permission.HARDWARE_TEST"); @@ -123,6 +139,21 @@ bool SurfaceFlinger::useVrFlinger; int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; bool SurfaceFlinger::hasWideColorDisplay; + +std::string getHwcServiceName() { + char value[PROPERTY_VALUE_MAX] = {}; + property_get("debug.sf.hwc_service_name", value, "default"); + ALOGI("Using HWComposer service: '%s'", value); + return std::string(value); +} + +bool useTrebleTestingOverride() { + char value[PROPERTY_VALUE_MAX] = {}; + property_get("debug.sf.treble_testing_override", value, "false"); + ALOGI("Treble testing override: '%s'", value); + return std::string(value) == "true"; +} + SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), mTransactionFlags(0), @@ -131,9 +162,7 @@ SurfaceFlinger::SurfaceFlinger() mLayersRemoved(false), mLayersAdded(false), mRepaintEverything(0), - mHwc(nullptr), - mRealHwc(nullptr), - mVrHwc(nullptr), + mHwcServiceName(getHwcServiceName()), mRenderEngine(nullptr), mBootTime(systemTime()), mBuiltinDisplays(), @@ -160,7 +189,9 @@ SurfaceFlinger::SurfaceFlinger() mTotalTime(0), mLastSwapTime(0), mNumLayers(0), - mVrFlingerRequestsDisplay(false) + mVrFlingerRequestsDisplay(false), + mMainThreadId(std::this_thread::get_id()), + mComposerSequenceId(0) { ALOGI("SurfaceFlinger is starting"); @@ -233,6 +264,15 @@ SurfaceFlinger::SurfaceFlinger() // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is // instead read after the boot animation + + if (useTrebleTestingOverride()) { + // Without the override SurfaceFlinger cannot connect to HIDL + // services that are not listed in the manifests. Considered + // deriving the setting from the set service name, but it + // would be brittle if the name that's not 'default' is used + // for production purposes later on. + setenv("TREBLE_TESTING_OVERRIDE", "true", true); + } } void SurfaceFlinger::onFirstRef() @@ -547,48 +587,46 @@ void SurfaceFlinger::init() { ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs); - { // Autolock scope - Mutex::Autolock _l(mStateLock); + Mutex::Autolock _l(mStateLock); - // initialize EGL for the default display - mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(mEGLDisplay, NULL, NULL); - - // start the EventThread - sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, - vsyncPhaseOffsetNs, true, "app"); - mEventThread = new EventThread(vsyncSrc, *this, false); - sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, - sfVsyncPhaseOffsetNs, true, "sf"); - mSFEventThread = new EventThread(sfVsyncSrc, *this, true); - mEventQueue.setEventThread(mSFEventThread); + // initialize EGL for the default display + mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEGLDisplay, NULL, NULL); - // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter - struct sched_param param = {0}; - param.sched_priority = 2; - if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); - } - if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for EventThread"); - } + // start the EventThread + sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, + vsyncPhaseOffsetNs, true, "app"); + mEventThread = new EventThread(vsyncSrc, *this, false); + sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, + sfVsyncPhaseOffsetNs, true, "sf"); + mSFEventThread = new EventThread(sfVsyncSrc, *this, true); + mEventQueue.setEventThread(mSFEventThread); - // Get a RenderEngine for the given display / config (can't fail) - mRenderEngine = RenderEngine::create(mEGLDisplay, - HAL_PIXEL_FORMAT_RGBA_8888, - hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); + // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter + struct sched_param param = {0}; + param.sched_priority = 2; + if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); + } + if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for EventThread"); } - // Drop the state lock while we initialize the hardware composer. We drop - // the lock because on creation, it will call back into SurfaceFlinger to - // initialize the primary display. - LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, - "Starting with vr flinger active is not currently supported."); - mRealHwc = new HWComposer(false); - mHwc = mRealHwc; - mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this)); + // Get a RenderEngine for the given display / config (can't fail) + mRenderEngine = RenderEngine::create(mEGLDisplay, + HAL_PIXEL_FORMAT_RGBA_8888, + hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); - Mutex::Autolock _l(mStateLock); + // retrieve the EGL context that was selected/created + mEGLContext = mRenderEngine->getEGLContext(); + + LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, + "couldn't create EGLContext"); + + LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, + "Starting with vr flinger active is not currently supported."); + mHwc.reset(new HWComposer(mHwcServiceName)); + mHwc->registerCallback(this, mComposerSequenceId); if (useVrFlinger) { auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { @@ -603,16 +641,6 @@ void SurfaceFlinger::init() { } } - // retrieve the EGL context that was selected/created - mEGLContext = mRenderEngine->getEGLContext(); - - LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, - "couldn't create EGLContext"); - - // make the GLContext current so that we can create textures when creating - // Layers (which may happens before we render something) - getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext); - mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); @@ -1045,6 +1073,33 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { return NO_ERROR; } +status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + + // Try to acquire a lock for 1s, fail gracefully + const status_t err = mStateLock.timedLock(s2ns(1)); + const bool locked = (err == NO_ERROR); + if (!locked) { + ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err); + return TIMED_OUT; + } + + outLayers->clear(); + mCurrentState.traverseInZOrder([&](Layer* layer) { + outLayers->push_back(layer->getLayerDebugInfo()); + }); + + mStateLock.unlock(); + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( @@ -1155,11 +1210,16 @@ void SurfaceFlinger::resyncWithRateLimit() { sLastResyncAttempted = now; } -void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type, - nsecs_t timestamp) { +void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, + hwc2_display_t displayId, int64_t timestamp) { Mutex::Autolock lock(mStateLock); - // Ignore any vsyncs from the non-active hardware composer. - if (composer != mHwc) { + // Ignore any vsyncs from a previous hardware composer. + if (sequenceId != mComposerSequenceId) { + return; + } + + int32_t type; + if (!mHwc->onVsync(displayId, timestamp, &type)) { return; } @@ -1167,7 +1227,7 @@ void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type, { // Scope for the lock Mutex::Autolock _l(mHWVsyncLock); - if (type == 0 && mPrimaryHWVsyncEnabled) { + if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) { needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); } } @@ -1185,7 +1245,7 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { } void SurfaceFlinger::createDefaultDisplayDevice() { - const int32_t type = DisplayDevice::DISPLAY_PRIMARY; + const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY; wp<IBinder> token = mBuiltinDisplays[type]; // All non-virtual displays are currently considered secure. @@ -1220,28 +1280,49 @@ void SurfaceFlinger::createDefaultDisplayDevice() { } setActiveColorModeInternal(hw, defaultColorMode); hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN); -} -void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) { - ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false"); + // Add the primary display token to mDrawingState so we don't try to + // recreate the DisplayDevice for the primary display. + mDrawingState.displays.add(token, DisplayDeviceState(type, true)); - if (composer->isUsingVrComposer()) { - // We handle initializing the primary display device for the VR - // window manager hwc explicitly at the time of transition. - if (disp != DisplayDevice::DISPLAY_PRIMARY) { - ALOGE("External displays are not supported by the vr hardware composer."); - } - return; - } + // make the GLContext current so that we can create textures when creating + // Layers (which may happens before we render something) + hw->makeCurrent(mEGLDisplay, mEGLContext); +} - if (disp == DisplayDevice::DISPLAY_PRIMARY) { - Mutex::Autolock lock(mStateLock); - createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); +void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, + hwc2_display_t display, HWC2::Connection connection, + bool primaryDisplay) { + ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)", + sequenceId, display, + connection == HWC2::Connection::Connected ? + "connected" : "disconnected", + primaryDisplay ? "primary" : "external"); + + // Only lock if we're not on the main thread. This function is normally + // called on a hwbinder thread, but for the primary display it's called on + // the main thread with the state lock already held, so don't attempt to + // acquire it here. + ConditionalLock lock(mStateLock, + std::this_thread::get_id() != mMainThreadId); + + if (primaryDisplay) { + mHwc->onHotplug(display, connection); + if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) { + createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); + } createDefaultDisplayDevice(); } else { + if (sequenceId != mComposerSequenceId) { + return; + } + if (mHwc->isUsingVrComposer()) { + ALOGE("External displays are not supported by the vr hardware composer."); + return; + } + mHwc->onHotplug(display, connection); auto type = DisplayDevice::DISPLAY_EXTERNAL; - Mutex::Autolock _l(mStateLock); - if (connected) { + if (connection == HWC2::Connection::Connected) { createBuiltinDisplayLocked(type); } else { mCurrentState.displays.removeItem(mBuiltinDisplays[type]); @@ -1253,46 +1334,31 @@ void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool } } -void SurfaceFlinger::onInvalidateReceived(HWComposer* composer) { +void SurfaceFlinger::onRefreshReceived(int sequenceId, + hwc2_display_t /*display*/) { Mutex::Autolock lock(mStateLock); - if (composer == mHwc) { - repaintEverything(); - } else { - // This isn't from our current hardware composer. If it's a callback - // from the real composer, forward the refresh request to vr - // flinger. Otherwise ignore it. - if (!composer->isUsingVrComposer()) { - mVrFlinger->OnHardwareComposerRefresh(); - } + if (sequenceId != mComposerSequenceId) { + return; } + repaintEverything(); } void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) { ATRACE_CALL(); + Mutex::Autolock lock(mStateLock); getHwComposer().setVsyncEnabled(disp, enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); } // Note: it is assumed the caller holds |mStateLock| when this is called -void SurfaceFlinger::resetHwcLocked() { +void SurfaceFlinger::resetDisplayState() { disableHardwareVsync(true); - clearHwcLayers(mDrawingState.layersSortedByZ); - clearHwcLayers(mCurrentState.layersSortedByZ); - for (size_t disp = 0; disp < mDisplays.size(); ++disp) { - clearHwcLayers(mDisplays[disp]->getVisibleLayersSortedByZ()); - } // Clear the drawing state so that the logic inside of // handleTransactionLocked will fire. It will determine the delta between // mCurrentState and mDrawingState and re-apply all changes when we make the // transition. mDrawingState.displays.clear(); - // Release virtual display hwcId during vr mode transition. - for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { - const sp<DisplayDevice>& displayDevice = mDisplays[displayId]; - if (displayDevice->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL) { - displayDevice->disconnect(getHwComposer()); - } - } + eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); mDisplays.clear(); } @@ -1304,57 +1370,54 @@ void SurfaceFlinger::updateVrFlinger() { return; } - if (vrFlingerRequestsDisplay && !mVrHwc) { - // Construct new HWComposer without holding any locks. - mVrHwc = new HWComposer(true); - - // Set up the event handlers. This step is neccessary to initialize the internal state of - // the hardware composer object properly. Our callbacks are designed such that if they are - // triggered between now and the point where the display is properly re-initialized, they - // will not have any effect, so this is safe to do here, before the lock is aquired. - mVrHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this)); - ALOGV("Vr HWC created"); + if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) { + ALOGE("Vr flinger is only supported for remote hardware composer" + " service connections. Ignoring request to transition to vr" + " flinger."); + mVrFlingerRequestsDisplay = false; + return; } Mutex::Autolock _l(mStateLock); - if (vrFlingerRequestsDisplay) { - resetHwcLocked(); - - mHwc = mVrHwc; - mVrFlinger->GrantDisplayOwnership(); + int currentDisplayPowerMode = getDisplayDeviceLocked( + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode(); - } else { + if (!vrFlingerRequestsDisplay) { mVrFlinger->SeizeDisplayOwnership(); + } + + resetDisplayState(); + mHwc.reset(); // Delete the current instance before creating the new one + mHwc.reset(new HWComposer( + vrFlingerRequestsDisplay ? "vr" : mHwcServiceName)); + mHwc->registerCallback(this, ++mComposerSequenceId); - resetHwcLocked(); + LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(), + "Switched to non-remote hardware composer"); - mHwc = mRealHwc; + if (vrFlingerRequestsDisplay) { + mVrFlinger->GrantDisplayOwnership(); + } else { enableHardwareVsync(); } mVisibleRegionsDirty = true; invalidateHwcGeometry(); - // Explicitly re-initialize the primary display. This is because some other - // parts of this class rely on the primary display always being available. - createDefaultDisplayDevice(); - // Re-enable default display. - sp<LambdaMessage> requestMessage = new LambdaMessage([&]() { - sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); - setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL); - - // Reset the timing values to account for the period of the swapped in HWC - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); - const nsecs_t period = activeConfig->getVsyncPeriod(); - mAnimFrameTracker.setDisplayRefreshPeriod(period); - - // Use phase of 0 since phase is not known. - // Use latency of 0, which will snap to the ideal latency. - setCompositorTimingSnapped(0, period, 0); - }); - postMessageAsync(requestMessage); + sp<DisplayDevice> hw(getDisplayDeviceLocked( + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); + setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true); + + // Reset the timing values to account for the period of the swapped in HWC + const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const nsecs_t period = activeConfig->getVsyncPeriod(); + mAnimFrameTracker.setDisplayRefreshPeriod(period); + + // Use phase of 0 since phase is not known. + // Use latency of 0, which will snap to the ideal latency. + setCompositorTimingSnapped(0, period, 0); android_atomic_or(1, &mRepaintEverything); setTransactionFlags(eDisplayTransactionNeeded); @@ -1370,7 +1433,6 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { Fence::SIGNAL_TIME_PENDING); ATRACE_INT("FrameMissed", static_cast<int>(frameMissed)); if (mPropagateBackpressure && frameMissed) { - ALOGD("Backpressure trigger, skipping transaction & refresh!"); signalLayerUpdate(); break; } @@ -1572,6 +1634,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) // |mStateLock| not needed as we are on the main thread const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); + mGlCompositionDoneTimeline.updateSignalTimes(); std::shared_ptr<FenceTime> glCompositionDoneFenceTime; if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) { glCompositionDoneFenceTime = @@ -1580,12 +1643,11 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) } else { glCompositionDoneFenceTime = FenceTime::NO_FENCE; } - mGlCompositionDoneTimeline.updateSignalTimes(); + mDisplayTimeline.updateSignalTimes(); sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY); auto presentFenceTime = std::make_shared<FenceTime>(presentFence); mDisplayTimeline.push(presentFenceTime); - mDisplayTimeline.updateSignalTimes(); nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0); nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod(); @@ -1610,8 +1672,8 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) } }); - if (presentFence->isValid()) { - if (mPrimaryDispSync.addPresentFence(presentFence)) { + if (presentFenceTime->isValid()) { + if (mPrimaryDispSync.addPresentFence(presentFenceTime)) { enableHardwareVsync(); } else { disableHardwareVsync(false); @@ -1691,15 +1753,14 @@ void SurfaceFlinger::rebuildLayerStacks() { } else { // Clear out the HWC layer if this layer was // previously visible, but no longer is - layer->setHwcLayer(displayDevice->getHwcDisplayId(), - nullptr); + layer->destroyHwcLayer( + displayDevice->getHwcDisplayId()); } } else { // WM changes displayDevice->layerStack upon sleep/awake. // Here we make sure we delete the HWC layers even if // WM changed their layer stack. - layer->setHwcLayer(displayDevice->getHwcDisplayId(), - nullptr); + layer->destroyHwcLayer(displayDevice->getHwcDisplayId()); } }); } @@ -1814,10 +1875,7 @@ void SurfaceFlinger::setUpHWComposer() { for (size_t i = 0; i < currentLayers.size(); i++) { const auto& layer = currentLayers[i]; if (!layer->hasHwcLayer(hwcId)) { - auto hwcLayer = mHwc->createLayer(hwcId); - if (hwcLayer) { - layer->setHwcLayer(hwcId, std::move(hwcLayer)); - } else { + if (!layer->createHwcLayer(mHwc.get(), hwcId)) { layer->forceClientComposition(hwcId); continue; } @@ -2098,7 +2156,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (state.surface != NULL) { // Allow VR composer to use virtual displays. - if (mUseHwcVirtualDisplays || mHwc == mVrHwc) { + if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) { int width = 0; int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); @@ -2775,6 +2833,7 @@ status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) return NO_ERROR; } + layer->onRemovedFromCurrentState(); mLayersPendingRemoval.add(layer); mLayersRemoved = true; mNumLayers -= 1 + layer->getChildrenCount(); @@ -2972,7 +3031,10 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } if (what & layer_state_t::eRelativeLayerChanged) { + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); flags |= eTransactionNeeded|eTraversalNeeded; } } @@ -3221,7 +3283,8 @@ void SurfaceFlinger::onInitializeDisplays() { d.height = 0; displays.add(d); setTransactionState(state, displays, 0); - setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL); + setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL, + /*stateLockHeld*/ false); const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); @@ -3247,7 +3310,7 @@ void SurfaceFlinger::initializeDisplays() { } void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, - int mode) { + int mode, bool stateLockHeld) { ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), this); int32_t type = hw->getDisplayType(); @@ -3264,7 +3327,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, } if (mInterceptor.isEnabled()) { - Mutex::Autolock _l(mStateLock); + ConditionalLock lock(mStateLock, !stateLockHeld); ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken()); if (idx < 0) { ALOGW("Surface Interceptor SavePowerMode: invalid display token"); @@ -3350,7 +3413,8 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) { ALOGW("Attempt to set power mode = %d for virtual display", mMode); } else { - mFlinger.setPowerModeInternal(hw, mMode); + mFlinger.setPowerModeInternal( + hw, mMode, /*stateLockHeld*/ false); } return true; } @@ -3695,7 +3759,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, result.appendFormat("Visible layers (count = %zu)\n", mNumLayers); colorizer.reset(result); mCurrentState.traverseInZOrder([&](Layer* layer) { - layer->dump(result, colorizer); + result.append(to_string(layer->getLayerDebugInfo()).c_str()); }); /* diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index acfad46526..058f4a1d3b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -60,13 +60,20 @@ #include "SurfaceInterceptor.h" #include "StartPropertySetThread.h" +#ifdef USE_HWC2 +#include "DisplayHardware/HWC2.h" #include "DisplayHardware/HWComposer.h" +#else +#include "DisplayHardware/HWComposer_hwc1.h" +#endif + #include "Effects/Daltonizer.h" #include <map> #include <mutex> #include <queue> #include <string> +#include <thread> #include <utility> namespace android { @@ -99,7 +106,11 @@ enum { class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, +#ifdef USE_HWC2 + private HWC2::ComposerCallback +#else private HWComposer::EventHandler +#endif { public: @@ -300,6 +311,7 @@ private: HdrCapabilities* outCapabilities) const; virtual status_t enableVSyncInjections(bool enable); virtual status_t injectVSync(nsecs_t when); + virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const; /* ------------------------------------------------------------------------ @@ -313,11 +325,20 @@ private: virtual void onFirstRef(); /* ------------------------------------------------------------------------ - * HWComposer::EventHandler interface + * HWC2::ComposerCallback / HWComposer::EventHandler interface */ - virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp); - virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected); - virtual void onInvalidateReceived(HWComposer* composer); +#ifdef USE_HWC2 + void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, + int64_t timestamp) override; + void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, + HWC2::Connection connection, + bool primaryDisplay) override; + void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override; +#else + void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp) override; + void onHotplugReceived(HWComposer* composer, int disp, bool connected) override; + void onInvalidateReceived(HWComposer* composer) override; +#endif /* ------------------------------------------------------------------------ * Message handling @@ -332,7 +353,12 @@ private: // called on the main thread in response to setActiveConfig() void setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode); // called on the main thread in response to setPowerMode() +#ifdef USE_HWC2 + void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode, + bool stateLockHeld); +#else void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode); +#endif // Called on the main thread in response to setActiveColorMode() void setActiveColorModeInternal(const sp<DisplayDevice>& hw, android_color_mode_t colorMode); @@ -590,13 +616,7 @@ private: /* ------------------------------------------------------------------------ * VrFlinger */ - template<typename T> - void clearHwcLayers(const T& layers) { - for (size_t i = 0; i < layers.size(); ++i) { - layers[i]->clearHwcLayers(); - } - } - void resetHwcLocked(); + void resetDisplayState(); // Check to see if we should handoff to vr flinger. void updateVrFlinger(); @@ -623,12 +643,14 @@ private: // access must be protected by mInvalidateLock volatile int32_t mRepaintEverything; - // current, real and vr hardware composers. - HWComposer* mHwc; + // The current hardware composer interface. When switching into and out of + // vr, our HWComposer instance will be recreated. + std::unique_ptr<HWComposer> mHwc; + #ifdef USE_HWC2 - HWComposer* mRealHwc; - HWComposer* mVrHwc; + const std::string mHwcServiceName; // "default" for real use, something else for testing. #endif + // constant members (no synchronization needed for access) RenderEngine* mRenderEngine; nsecs_t mBootTime; @@ -642,10 +664,6 @@ private: EGLDisplay mEGLDisplay; sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES]; -#ifdef USE_HWC2 - std::unique_ptr<dvr::VrFlinger> mVrFlinger; -#endif - // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState{LayerVector::StateSet::Drawing}; @@ -767,8 +785,14 @@ private: status_t CheckTransactCodeCredentials(uint32_t code); #ifdef USE_HWC2 + std::unique_ptr<dvr::VrFlinger> mVrFlinger; std::atomic<bool> mVrFlingerRequestsDisplay; static bool useVrFlinger; + std::thread::id mMainThreadId; + // The composer sequence id is a monotonically increasing integer that we + // use to differentiate callbacks from different hardware composer + // instances. Each hardware composer instance gets a different sequence id. + int32_t mComposerSequenceId; #endif float mSaturation = 1.0f; diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index 247d80bc07..a92e1f9f89 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -41,6 +41,7 @@ #include <gui/BufferQueue.h> #include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> +#include <gui/LayerDebugInfo.h> #include <gui/Surface.h> #include <ui/GraphicBufferAllocator.h> @@ -94,7 +95,7 @@ */ #define DEBUG_SCREENSHOTS false -EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { // --------------------------------------------------------------------------- @@ -534,8 +535,8 @@ void SurfaceFlinger::init() { // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. - mHwc = new HWComposer(this, - *static_cast<HWComposer::EventHandler *>(this)); + mHwc.reset(new HWComposer(this, + *static_cast<HWComposer::EventHandler *>(this))); // get a RenderEngine for the given display / config (can't fail) mRenderEngine = RenderEngine::create(mEGLDisplay, @@ -931,6 +932,34 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { return NO_ERROR; } +status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + + // Try to acquire a lock for 1s, fail gracefully + status_t err = mStateLock.timedLock(s2ns(1)); + bool locked = (err == NO_ERROR); + if (!locked) { + ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err); + return TIMED_OUT; + } + + outLayers->clear(); + mCurrentState.traverseInZOrder([&](Layer* layer) { + outLayers->push_back(layer->getLayerDebugInfo()); + }); + + mStateLock.unlock(); + + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( @@ -1257,6 +1286,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) const HWComposer& hwc = getHwComposer(); const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + mGlCompositionDoneTimeline.updateSignalTimes(); std::shared_ptr<FenceTime> glCompositionDoneFenceTime; if (getHwComposer().hasGlesComposition(hw->getHwcDisplayId())) { glCompositionDoneFenceTime = @@ -1265,12 +1295,11 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) } else { glCompositionDoneFenceTime = FenceTime::NO_FENCE; } - mGlCompositionDoneTimeline.updateSignalTimes(); + mDisplayTimeline.updateSignalTimes(); sp<Fence> retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY); auto retireFenceTime = std::make_shared<FenceTime>(retireFence); mDisplayTimeline.push(retireFenceTime); - mDisplayTimeline.updateSignalTimes(); nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0); nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod(); @@ -1298,7 +1327,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) }); if (retireFence->isValid()) { - if (mPrimaryDispSync.addPresentFence(retireFence)) { + if (mPrimaryDispSync.addPresentFence(retireFenceTime)) { enableHardwareVsync(); } else { disableHardwareVsync(false); @@ -2382,6 +2411,7 @@ status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) return NO_ERROR; } + layer->onRemovedFromCurrentState(); mLayersPendingRemoval.add(layer); mLayersRemoved = true; mNumLayers -= 1 + layer->getChildrenCount(); @@ -2576,6 +2606,14 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } } + if (what & layer_state_t::eRelativeLayerChanged) { + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + flags |= eTransactionNeeded|eTraversalNeeded; + } + } if (what & layer_state_t::eSizeChanged) { if (layer->setSize(s.w, s.h)) { flags |= eTraversalNeeded; @@ -3253,7 +3291,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, result.appendFormat("Visible layers (count = %zu)\n", mNumLayers); colorizer.reset(result); mCurrentState.traverseInZOrder([&](Layer* layer) { - layer->dump(result, colorizer); + result.append(to_string(layer->getLayerDebugInfo()).c_str()); }); /* diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter index 915b5cd3ca..6be708ad1c 100644 --- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter +++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter @@ -1,5 +1,5 @@ { "presubmit": { - "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*" + "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*" } }
\ No newline at end of file diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index b7792c7852..4ce14f8d3a 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -566,6 +566,15 @@ protected: sc->expectBGColor(127, 127); sc->expectBGColor(128, 128); } + + void EXPECT_RESIZE_STATE(const char* trace) { + SCOPED_TRACE(trace); + ScreenCapture::captureScreen(&sc); + // The FG is now resized too 128,128 at 64,64 + sc->expectFGColor(64, 64); + sc->expectFGColor(191, 191); + sc->expectBGColor(192, 192); + } }; TEST_F(CropLatchingTest, CropLatching) { @@ -666,15 +675,17 @@ TEST_F(CropLatchingTest, FinalCropLatchingRegressionForb37531386) { mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); SurfaceComposerClient::closeGlobalTransaction(true); + EXPECT_INITIAL_STATE("after setting crops with geometryAppliesWithResize"); + SurfaceComposerClient::openGlobalTransaction(); mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); SurfaceComposerClient::closeGlobalTransaction(true); - EXPECT_INITIAL_STATE("after setting crops with geometryAppliesWithResize"); + EXPECT_INITIAL_STATE("after setting another crop"); completeFGResize(); - EXPECT_INITIAL_STATE("after the resize finishes"); + EXPECT_RESIZE_STATE("after the resize finishes"); } TEST_F(LayerUpdateTest, DeferredTransactionTest) { diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp new file mode 100644 index 0000000000..94f3f2561a --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -0,0 +1,35 @@ +cc_test { + name: "sffakehwc_test", + srcs: [ + "FakeComposerClient.cpp", + "FakeComposerService.cpp", + "FakeComposerUtils.cpp", + "SFFakeHwc_test.cpp" + ], + shared_libs: [ + "libcutils", + "libutils", + "libbinder", + "libui", + "libgui", + "liblog", + "libnativewindow", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0", + "libhwbinder", + "libhardware", + "libhidlbase", + "libsync", + "libfmq", + "libbase", + "libhidltransport" + ], + static_libs: [ + "libhwcomposer-client", + "libsurfaceflingerincludes", + "libtrace_proto", + "libgmock" + ], + tags: ["tests"], + test_suites: ["device-tests"] +}
\ No newline at end of file diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp new file mode 100644 index 0000000000..60916f3ab9 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp @@ -0,0 +1,613 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeComposer" + +#include "FakeComposerClient.h" + +#include <gui/SurfaceComposerClient.h> + +#include <log/log.h> + +#include <gtest/gtest.h> + +#include <inttypes.h> +#include <time.h> +#include <algorithm> +#include <condition_variable> +#include <iostream> +#include <mutex> +#include <set> +#include <thread> + +constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0); +constexpr Display DEFAULT_DISPLAY = static_cast<Display>(1); + +using namespace sftest; + +using android::Condition; +using android::Mutex; + +using Clock = std::chrono::steady_clock; +using TimePoint = std::chrono::time_point<Clock>; + +namespace { + +// Internal state of a layer in the HWC API. +class LayerImpl { +public: + LayerImpl() = default; + + bool mValid = true; + RenderState mRenderState; + uint32_t mZ = 0; +}; + +// Struct for storing per frame rectangle state. Contains the render +// state shared to the test case. Basically a snapshot and a subset of +// LayerImpl sufficient to re-create the pixels of a layer for the +// frame. +struct FrameRect { +public: + FrameRect(Layer layer_, const RenderState& state, uint32_t z_) + : layer(layer_), renderState(state), z(z_) {} + + const Layer layer; + const RenderState renderState; + const uint32_t z; +}; + +// Collection of FrameRects forming one rendered frame. Could store +// related fences and other data in the future. +class Frame { +public: + Frame() = default; + std::vector<std::unique_ptr<FrameRect>> rectangles; +}; + +class DelayedEventGenerator { +public: + DelayedEventGenerator(std::function<void()> onTimerExpired) + : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {} + + ~DelayedEventGenerator() { + ALOGI("DelayedEventGenerator exiting."); + { + std::unique_lock<std::mutex> lock(mMutex); + mRunning = false; + mWakeups.clear(); + mCondition.notify_one(); + } + mThread.join(); + ALOGI("DelayedEventGenerator exited."); + } + + void wakeAfter(std::chrono::nanoseconds waitTime) { + std::unique_lock<std::mutex> lock(mMutex); + mWakeups.insert(Clock::now() + waitTime); + mCondition.notify_one(); + } + +private: + void loop() { + while (true) { + // Lock scope + { + std::unique_lock<std::mutex> lock(mMutex); + mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); }); + if (!mRunning && mWakeups.empty()) { + // This thread should only exit once the destructor has been called and all + // wakeups have been processed + return; + } + + // At this point, mWakeups will not be empty + + TimePoint target = *(mWakeups.begin()); + auto status = mCondition.wait_until(lock, target); + while (status == std::cv_status::no_timeout) { + // This was either a spurious wakeup or another wakeup was added, so grab the + // oldest point and wait again + target = *(mWakeups.begin()); + status = mCondition.wait_until(lock, target); + } + + // status must have been timeout, so we can finally clear this point + mWakeups.erase(target); + } + // Callback *without* locks! + mOnTimerExpired(); + } + } + + std::function<void()> mOnTimerExpired; + std::thread mThread; + std::mutex mMutex; + std::condition_variable mCondition; + bool mRunning = true; + std::set<TimePoint> mWakeups; +}; + +} // namespace + +FakeComposerClient::FakeComposerClient() + : mCallbacksOn(false), + mClient(nullptr), + mCurrentConfig(NULL_DISPLAY_CONFIG), + mVsyncEnabled(false), + mLayers(), + mDelayedEventGenerator( + std::make_unique<DelayedEventGenerator>([this]() { this->requestVSync(); })), + mSurfaceComposer(nullptr) {} + +FakeComposerClient::~FakeComposerClient() {} + +void FakeComposerClient::removeClient() { + ALOGV("removeClient"); + // TODO: Ahooga! Only thing current lifetime management choices in + // APIs make possible. Sad. + delete this; +} + +void FakeComposerClient::enableCallback(bool enable) { + ALOGV("enableCallback"); + mCallbacksOn = enable; + if (mCallbacksOn) { + mClient->onHotplug(DEFAULT_DISPLAY, IComposerCallback::Connection::CONNECTED); + } +} + +void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) { + if (mCallbacksOn) { + mClient->onHotplug(display, state); + } +} + +uint32_t FakeComposerClient::getMaxVirtualDisplayCount() { + ALOGV("getMaxVirtualDisplayCount"); + return 1; +} + +Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/, + PixelFormat* /*format*/, Display* /*outDisplay*/) { + ALOGV("createVirtualDisplay"); + return Error::NONE; +} + +Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) { + ALOGV("destroyVirtualDisplay"); + return Error::NONE; +} + +Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) { + ALOGV("createLayer"); + *outLayer = mLayers.size(); + auto newLayer = std::make_unique<LayerImpl>(); + mLayers.push_back(std::move(newLayer)); + return Error::NONE; +} + +Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) { + ALOGV("destroyLayer"); + mLayers[layer]->mValid = false; + return Error::NONE; +} + +Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) { + ALOGV("getActiveConfig"); + + // TODO Assert outConfig != nullptr + + // TODO This is my reading of the + // IComposerClient::getActiveConfig, but returning BAD_CONFIG + // seems to not fit SurfaceFlinger plans. See version 2 below. + // if (mCurrentConfig == NULL_DISPLAY_CONFIG) { + // return Error::BAD_CONFIG; + // } + //*outConfig = mCurrentConfig; + *outConfig = 1; // Very special config for you my friend + return Error::NONE; +} + +Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/, + uint32_t /*height*/, PixelFormat /*format*/, + Dataspace /*dataspace*/) { + ALOGV("getClientTargetSupport"); + return Error::NONE; +} + +Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec<ColorMode>* /*outModes*/) { + ALOGV("getColorModes"); + return Error::NONE; +} + +Error FakeComposerClient::getDisplayAttribute(Display display, Config config, + IComposerClient::Attribute attribute, + int32_t* outValue) { + ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display), + static_cast<int>(config), static_cast<int>(attribute), outValue); + + // TODO: SOOO much fun to be had with these alone + switch (attribute) { + case IComposerClient::Attribute::WIDTH: + *outValue = 1920; + break; + case IComposerClient::Attribute::HEIGHT: + *outValue = 1080; + break; + case IComposerClient::Attribute::VSYNC_PERIOD: + *outValue = 1666666666; + break; // TOOD: Tests break down if lowered to 16ms? + case IComposerClient::Attribute::DPI_X: + *outValue = 240; + break; + case IComposerClient::Attribute::DPI_Y: + *outValue = 240; + break; + default: + LOG_ALWAYS_FATAL("Say what!?! New attribute"); + } + + return Error::NONE; +} + +Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec<Config>* outConfigs) { + ALOGV("getDisplayConfigs"); + // TODO assert display == 1, outConfigs != nullptr + + outConfigs->resize(1); + (*outConfigs)[0] = 1; + + return Error::NONE; +} + +Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) { + ALOGV("getDisplayName"); + return Error::NONE; +} + +Error FakeComposerClient::getDisplayType(Display /*display*/, + IComposerClient::DisplayType* outType) { + ALOGV("getDisplayType"); + // TODO: This setting nothing on the output had no effect on initial trials. Is first display + // assumed to be physical? + *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL); + return Error::NONE; +} + +Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) { + ALOGV("getDozeSupport"); + return Error::NONE; +} + +Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec<Hdr>* /*outTypes*/, + float* /*outMaxLuminance*/, + float* /*outMaxAverageLuminance*/, + float* /*outMinLuminance*/) { + ALOGV("getHdrCapabilities"); + return Error::NONE; +} + +Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) { + ALOGV("setActiveConfig"); + mCurrentConfig = config; + return Error::NONE; +} + +Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) { + ALOGV("setColorMode"); + return Error::NONE; +} + +Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) { + ALOGV("setPowerMode"); + return Error::NONE; +} + +Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) { + mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE); + ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE"); + return Error::NONE; +} + +Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/, + int32_t /*hint*/) { + ALOGV("setColorTransform"); + return Error::NONE; +} + +Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/, + int32_t /*acquireFence*/, int32_t /*dataspace*/, + const std::vector<hwc_rect_t>& /*damage*/) { + ALOGV("setClientTarget"); + return Error::NONE; +} + +Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/, + int32_t /*releaseFence*/) { + ALOGV("setOutputBuffer"); + return Error::NONE; +} + +Error FakeComposerClient::validateDisplay( + Display /*display*/, std::vector<Layer>* /*outChangedLayers*/, + std::vector<IComposerClient::Composition>* /*outCompositionTypes*/, + uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/, + std::vector<uint32_t>* /*outRequestMasks*/) { + ALOGV("validateDisplay"); + // TODO: Assume touching nothing means All Korrekt! + return Error::NONE; +} + +Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) { + ALOGV("acceptDisplayChanges"); + // Didn't ask for changes because software is omnipotent. + return Error::NONE; +} + +bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) { + return a->z <= b->z; +} + +Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/, + std::vector<Layer>* /*outLayers*/, + std::vector<int32_t>* /*outReleaseFences*/) { + ALOGV("presentDisplay"); + // TODO Leaving layers and their fences out for now. Doing so + // means that we've already processed everything. Important to + // test that the fences are respected, though. (How?) + + std::unique_ptr<Frame> newFrame(new Frame); + for (uint64_t layer = 0; layer < mLayers.size(); layer++) { + const LayerImpl& layerImpl = *mLayers[layer]; + + if (!layerImpl.mValid) continue; + + auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ); + newFrame->rectangles.push_back(std::move(rect)); + } + std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering); + { + Mutex::Autolock _l(mStateMutex); + mFrames.push_back(std::move(newFrame)); + mFramesAvailable.broadcast(); + } + return Error::NONE; +} + +Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/, + int32_t /*x*/, int32_t /*y*/) { + ALOGV("setLayerCursorPosition"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer, + int32_t acquireFence) { + ALOGV("setLayerBuffer"); + LayerImpl& l = getLayerImpl(layer); + if (buffer != l.mRenderState.mBuffer) { + l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not? + } + l.mRenderState.mBuffer = buffer; + l.mRenderState.mAcquireFence = acquireFence; + + return Error::NONE; +} + +Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/, + const std::vector<hwc_rect_t>& /*damage*/) { + ALOGV("setLayerSurfaceDamage"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) { + ALOGV("setLayerBlendMode"); + getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode); + return Error::NONE; +} + +Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer, + IComposerClient::Color color) { + ALOGV("setLayerColor"); + getLayerImpl(layer).mRenderState.mLayerColor.r = color.r; + getLayerImpl(layer).mRenderState.mLayerColor.g = color.g; + getLayerImpl(layer).mRenderState.mLayerColor.b = color.b; + getLayerImpl(layer).mRenderState.mLayerColor.a = color.a; + return Error::NONE; +} + +Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/, + int32_t /*type*/) { + ALOGV("setLayerCompositionType"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/, + int32_t /*dataspace*/) { + ALOGV("setLayerDataspace"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer, + const hwc_rect_t& frame) { + ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right, + frame.bottom); + getLayerImpl(layer).mRenderState.mDisplayFrame = frame; + return Error::NONE; +} + +Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) { + ALOGV("setLayerPlaneAlpha"); + getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha; + return Error::NONE; +} + +Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/, + buffer_handle_t /*stream*/) { + ALOGV("setLayerSidebandStream"); + return Error::NONE; +} + +Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer, + const hwc_frect_t& crop) { + ALOGV("setLayerSourceCrop"); + getLayerImpl(layer).mRenderState.mSourceCrop = crop; + return Error::NONE; +} + +Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) { + ALOGV("setLayerTransform"); + getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform); + return Error::NONE; +} + +Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer, + const std::vector<hwc_rect_t>& visible) { + ALOGV("setLayerVisibleRegion"); + getLayerImpl(layer).mRenderState.mVisibleRegion = visible; + return Error::NONE; +} + +Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) { + ALOGV("setLayerZOrder"); + getLayerImpl(layer).mZ = z; + return Error::NONE; +} + +////////////////////////////////////////////////////////////////// + +void FakeComposerClient::setClient(ComposerClient* client) { + mClient = client; +} + +void FakeComposerClient::requestVSync(uint64_t vsyncTime) { + if (mCallbacksOn) { + uint64_t timestamp = vsyncTime; + ALOGV("Vsync"); + if (timestamp == 0) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; + } + if (mSurfaceComposer != nullptr) { + mSurfaceComposer->injectVSync(timestamp); + } else { + mClient->onVsync(DEFAULT_DISPLAY, timestamp); + } + } +} + +void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) { + mDelayedEventGenerator->wakeAfter(wait); +} + +LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) { + // TODO Change these to an internal state check that can be + // invoked from the gtest? GTest macros do not seem all that safe + // when used outside the test class + EXPECT_GE(handle, static_cast<Layer>(0)); + EXPECT_LT(handle, mLayers.size()); + return *(mLayers[handle]); +} + +int FakeComposerClient::getFrameCount() const { + return mFrames.size(); +} + +static std::vector<RenderState> extractRenderState( + const std::vector<std::unique_ptr<FrameRect>>& internalRects) { + std::vector<RenderState> result; + result.reserve(internalRects.size()); + for (const std::unique_ptr<FrameRect>& rect : internalRects) { + result.push_back(rect->renderState); + } + return result; +} + +std::vector<RenderState> FakeComposerClient::getFrameRects(int frame) const { + Mutex::Autolock _l(mStateMutex); + return extractRenderState(mFrames[frame]->rectangles); +} + +std::vector<RenderState> FakeComposerClient::getLatestFrame() const { + Mutex::Autolock _l(mStateMutex); + return extractRenderState(mFrames[mFrames.size() - 1]->rectangles); +} + +void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) { + int currentFrame = 0; + { + Mutex::Autolock _l(mStateMutex); // I hope this is ok... + currentFrame = static_cast<int>(mFrames.size()); + requestVSync(); + } + waitUntilFrame(currentFrame + 1, maxWait); +} + +void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const { + Mutex::Autolock _l(mStateMutex); + while (mFrames.size() < static_cast<size_t>(targetFrame)) { + android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count()); + if (result == android::TIMED_OUT) { + ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame, + mFrames.size(), maxWait.count()); + return; + } + } +} + +void FakeComposerClient::clearFrames() { + Mutex::Autolock _l(mStateMutex); + mFrames.clear(); + for (const std::unique_ptr<LayerImpl>& layer : mLayers) { + if (layer->mValid) { + layer->mRenderState.mSwapCount = 0; + } + } +} + +void FakeComposerClient::onSurfaceFlingerStart() { + mSurfaceComposer == nullptr; + do { + mSurfaceComposer = new android::SurfaceComposerClient; + android::status_t initResult = mSurfaceComposer->initCheck(); + if (initResult != android::NO_ERROR) { + ALOGD("Init result: %d", initResult); + mSurfaceComposer = nullptr; + std::this_thread::sleep_for(10ms); + } + } while (mSurfaceComposer == nullptr); + ALOGD("SurfaceComposerClient created"); + mSurfaceComposer->enableVSyncInjections(true); +} + +void FakeComposerClient::onSurfaceFlingerStop() { + mSurfaceComposer->dispose(); + mSurfaceComposer.clear(); +} + +// Includes destroyed layers, stored in order of creation. +int FakeComposerClient::getLayerCount() const { + return mLayers.size(); +} + +Layer FakeComposerClient::getLayer(size_t index) const { + // NOTE: If/when passing calls through to actual implementation, + // this might get more involving. + return static_cast<Layer>(index); +} diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h new file mode 100644 index 0000000000..294abb2c59 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h @@ -0,0 +1,146 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ComposerClient.h" +#include "RenderState.h" + +#include <utils/Condition.h> + +#include <chrono> + +using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_1::implementation; +using namespace android::hardware; +using namespace std::chrono_literals; + +namespace { +class LayerImpl; +class Frame; +class DelayedEventGenerator; +} // namespace + +namespace android { +class SurfaceComposerClient; +} // namespace android + +namespace sftest { + +class FakeComposerClient : public ComposerBase { +public: + FakeComposerClient(); + virtual ~FakeComposerClient(); + + void removeClient() override; + void enableCallback(bool enable) override; + uint32_t getMaxVirtualDisplayCount() override; + Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, + Display* outDisplay) override; + Error destroyVirtualDisplay(Display display) override; + Error createLayer(Display display, Layer* outLayer) override; + Error destroyLayer(Display display, Layer layer) override; + + Error getActiveConfig(Display display, Config* outConfig) override; + Error getClientTargetSupport(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) override; + Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override; + Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, + int32_t* outValue) override; + Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override; + Error getDisplayName(Display display, hidl_string* outName) override; + Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override; + Error getDozeSupport(Display display, bool* outSupport) override; + Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance, + float* outMaxAverageLuminance, float* outMinLuminance) override; + + Error setActiveConfig(Display display, Config config) override; + Error setColorMode(Display display, ColorMode mode) override; + Error setPowerMode(Display display, IComposerClient::PowerMode mode) override; + Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override; + + Error setColorTransform(Display display, const float* matrix, int32_t hint) override; + Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence, + int32_t dataspace, const std::vector<hwc_rect_t>& damage) override; + Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override; + Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers, + std::vector<IComposerClient::Composition>* outCompositionTypes, + uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers, + std::vector<uint32_t>* outRequestMasks) override; + Error acceptDisplayChanges(Display display) override; + Error presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers, + std::vector<int32_t>* outReleaseFences) override; + + Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override; + Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer, + int32_t acquireFence) override; + Error setLayerSurfaceDamage(Display display, Layer layer, + const std::vector<hwc_rect_t>& damage) override; + Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override; + Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override; + Error setLayerCompositionType(Display display, Layer layer, int32_t type) override; + Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override; + Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override; + Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override; + Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override; + Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override; + Error setLayerTransform(Display display, Layer layer, int32_t transform) override; + Error setLayerVisibleRegion(Display display, Layer layer, + const std::vector<hwc_rect_t>& visible) override; + Error setLayerZOrder(Display display, Layer layer, uint32_t z) override; + + void setClient(ComposerClient* client); + + void requestVSync(uint64_t vsyncTime = 0); + // We don't want tests hanging, so always use a timeout. Remember + // to always check the number of frames with test ASSERT_! + // Wait until next frame is rendered after requesting vsync. + void runVSyncAndWait(std::chrono::nanoseconds maxWait = 100ms); + void runVSyncAfter(std::chrono::nanoseconds wait); + + int getFrameCount() const; + // We don't want tests hanging, so always use a timeout. Remember + // to always check the number of frames with test ASSERT_! + void waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait = 100ms) const; + std::vector<RenderState> getFrameRects(int frame) const; + std::vector<RenderState> getLatestFrame() const; + void clearFrames(); + + void onSurfaceFlingerStart(); + void onSurfaceFlingerStop(); + + int getLayerCount() const; + Layer getLayer(size_t index) const; + + void hotplugDisplay(Display display, IComposerCallback::Connection state); + +private: + LayerImpl& getLayerImpl(Layer handle); + + bool mCallbacksOn; + ComposerClient* mClient; + Config mCurrentConfig; + bool mVsyncEnabled; + std::vector<std::unique_ptr<LayerImpl>> mLayers; + std::vector<std::unique_ptr<Frame>> mFrames; + // Using a pointer to hide the implementation into the CPP file. + std::unique_ptr<DelayedEventGenerator> mDelayedEventGenerator; + android::sp<android::SurfaceComposerClient> mSurfaceComposer; // For VSync injections + mutable android::Mutex mStateMutex; + mutable android::Condition mFramesAvailable; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp new file mode 100644 index 0000000000..c411604587 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcService" +#include <log/log.h> + +#include "FakeComposerService.h" + +using namespace android::hardware; + +namespace sftest { + +FakeComposerService::FakeComposerService(android::sp<ComposerClient>& client) : mClient(client) {} + +FakeComposerService::~FakeComposerService() { + ALOGI("Maybe killing client %p", mClient.get()); + // Rely on sp to kill the client. +} + +Return<void> FakeComposerService::getCapabilities(getCapabilities_cb hidl_cb) { + ALOGI("FakeComposerService::getCapabilities"); + hidl_cb(hidl_vec<Capability>()); + return Void(); +} + +Return<void> FakeComposerService::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) { + ALOGI("FakeComposerService::dumpDebugInfo"); + hidl_cb(hidl_string()); + return Void(); +} + +Return<void> FakeComposerService::createClient(createClient_cb hidl_cb) { + ALOGI("FakeComposerService::createClient %p", mClient.get()); + mClient->initialize(); + hidl_cb(Error::NONE, mClient); + return Void(); +} + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h new file mode 100644 index 0000000000..520408496f --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ComposerClient.h" + +using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_1::implementation; +using android::hardware::Return; + +namespace sftest { + +class FakeComposerService : public IComposer { +public: + FakeComposerService(android::sp<ComposerClient>& client); + virtual ~FakeComposerService(); + + Return<void> getCapabilities(getCapabilities_cb hidl_cb) override; + Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; + Return<void> createClient(createClient_cb hidl_cb) override; + +private: + android::sp<ComposerClient> mClient; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp new file mode 100644 index 0000000000..51956ec970 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp @@ -0,0 +1,183 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcUtil" +#include <log/log.h> + +#include "FakeComposerUtils.h" +#include "RenderState.h" + +#include "SurfaceFlinger.h" // Get the name of the service... + +#include <binder/IServiceManager.h> + +#include <cutils/properties.h> + +#include <iomanip> +#include <thread> + +using android::String16; +using android::sp; +using namespace std::chrono_literals; +using namespace sftest; +using std::setw; + +namespace sftest { + +// clang-format off +inline void printSourceRectAligned(::std::ostream& os, const hwc_frect_t& sourceRect, int align) { + os << std::fixed << std::setprecision(1) << "(" + << setw(align) << sourceRect.left << setw(0) << "," + << setw(align) << sourceRect.top << setw(0) << "," + << setw(align) << sourceRect.right << setw(0) << "," + << setw(align) << sourceRect.bottom << setw(0) << ")"; +} + +inline void printDisplayRectAligned(::std::ostream& os, const hwc_rect_t& displayRect, int align) { + os << "(" + << setw(align) << displayRect.left << setw(0) << "," + << setw(align) << displayRect.top << setw(0) << "," + << setw(align) << displayRect.right << setw(0) << "," + << setw(align) << displayRect.bottom << setw(0) << ")"; +} +// clang-format on + +inline ::std::ostream& operator<<(::std::ostream& os, const sftest::RenderState& state) { + printSourceRectAligned(os, state.mSourceCrop, 7); + os << "->"; + printDisplayRectAligned(os, state.mDisplayFrame, 5); + return os << " Swaps:" << state.mSwapCount << " Alpha:" << std::setprecision(3) + << state.mPlaneAlpha << " Xform:" << state.mTransform; +} + +// Helper for verifying the parts of the RenderState +template <typename T> +bool valuesMatch(::testing::AssertionResult& message, const T& ref, const T& val, + const char* name) { + if (ref != val) { + message = message << "Expected " << name << ":" << ref << ", got:" << val << "."; + return false; + } + return true; +} + +::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val) { + // TODO: Message could start as success and be assigned as failure. + // Only problem is that utility assumes it to be failure and just adds stuff. Would + // need still special case the initial failure in the utility? + // TODO: ... or would it be possible to break this back to gtest primitives? + ::testing::AssertionResult message = ::testing::AssertionFailure(); + bool passes = true; + + // The work here is mostly about providing good log strings for differences + passes &= valuesMatch(message, ref.mDisplayFrame, val.mDisplayFrame, "display frame"); + passes &= valuesMatch(message, ref.mPlaneAlpha, val.mPlaneAlpha, "alpha"); + passes &= valuesMatch(message, ref.mSwapCount, val.mSwapCount, "swap count"); + passes &= valuesMatch(message, ref.mSourceCrop, val.mSourceCrop, "source crop"); + // ... add more + if (passes) { + return ::testing::AssertionSuccess(); + } + return message; +} + +::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref, + const std::vector<RenderState>& val) { + ::testing::AssertionResult message = ::testing::AssertionFailure(); + bool passed = true; + if (ref.size() != val.size()) { + message << "Expected " << ref.size() << " rects, got " << val.size() << "."; + passed = false; + } + for (size_t rectIndex = 0; rectIndex < std::min(ref.size(), val.size()); rectIndex++) { + ::testing::AssertionResult rectResult = rectsAreSame(ref[rectIndex], val[rectIndex]); + if (rectResult == false) { + message << "First different rect at " << rectIndex << ": " << rectResult.message(); + passed = false; + break; + } + } + + if (passed) { + return ::testing::AssertionSuccess(); + } else { + message << "\nReference:"; + for (auto state = ref.begin(); state != ref.end(); ++state) { + message << "\n" << *state; + } + message << "\nActual:"; + for (auto state = val.begin(); state != val.end(); ++state) { + message << "\n" << *state; + } + } + return message; +} + +void startSurfaceFlinger() { + ALOGI("Start SurfaceFlinger"); + system("start surfaceflinger"); + + sp<android::IServiceManager> sm(android::defaultServiceManager()); + sp<android::IBinder> sf; + while (sf == nullptr) { + std::this_thread::sleep_for(10ms); + sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName())); + } + ALOGV("SurfaceFlinger running"); +} + +void stopSurfaceFlinger() { + ALOGI("Stop SurfaceFlinger"); + system("stop surfaceflinger"); + sp<android::IServiceManager> sm(android::defaultServiceManager()); + sp<android::IBinder> sf; + while (sf != nullptr) { + std::this_thread::sleep_for(10ms); + sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName())); + } + ALOGV("SurfaceFlinger stopped"); +} + +//////////////////////////////////////////////// + +void FakeHwcEnvironment::SetUp() { + ALOGI("Test env setup"); + system("setenforce 0"); + system("stop"); + property_set("debug.sf.nobootanimation", "1"); + { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.nobootanimation", value, "0"); + LOG_FATAL_IF(atoi(value) != 1, "boot skip not set"); + } + // TODO: Try registering the mock as the default service instead. + property_set("debug.sf.hwc_service_name", "mock"); + // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files. + property_set("debug.sf.treble_testing_override", "true"); +} + +void FakeHwcEnvironment::TearDown() { + ALOGI("Test env tear down"); + system("stop"); + // Wait for mock call signaling teardown? + property_set("debug.sf.nobootanimation", "0"); + property_set("debug.sf.hwc_service_name", "default"); + ALOGI("Test env tear down - done"); +} + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h new file mode 100644 index 0000000000..74dc0e51bb --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h @@ -0,0 +1,119 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "FakeComposerClient.h" + +#include <gui/SurfaceComposerClient.h> + +#include <hardware/hwcomposer_defs.h> + +#include <log/log.h> + +#include <gtest/gtest.h> + +// clang-format off +// Note: This needs to reside in the global namespace for the GTest to use it +inline ::std::ostream& operator<<(::std::ostream& os, const hwc_rect_t& rect) { + return os << "(" << rect.left << "," + << rect.top << "," + << rect.right << "," + << rect.bottom << ")"; +} + +inline ::std::ostream& operator<<(::std::ostream& os, const hwc_frect_t& rect) { + return os << "(" << rect.left << "," + << rect.top << "," + << rect.right << "," + << rect.bottom << ")"; +} +// clang-format on + +namespace sftest { + +class RenderState; + +// clang-format off +inline bool operator==(const hwc_rect_t& a, const hwc_rect_t& b) { + return a.top == b.top && + a.left == b.left && + a.bottom == b.bottom && + a.right == b.right; +} + +inline bool operator==(const hwc_frect_t& a, const hwc_frect_t& b) { + return a.top == b.top && + a.left == b.left && + a.bottom == b.bottom && + a.right == b.right; +} +// clang-format on + +inline bool operator!=(const hwc_rect_t& a, const hwc_rect_t& b) { + return !(a == b); +} + +inline bool operator!=(const hwc_frect_t& a, const hwc_frect_t& b) { + return !(a == b); +} + +::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val); +::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref, + const std::vector<RenderState>& val); + +void startSurfaceFlinger(); +void stopSurfaceFlinger(); + +class FakeHwcEnvironment : public ::testing::Environment { +public: + virtual ~FakeHwcEnvironment() {} + void SetUp() override; + void TearDown() override; +}; + +/* + * All surface state changes are supposed to happen inside a global + * transaction. GlobalTransactionScope object at the beginning of + * scope automates the process. The resulting scope gives a visual cue + * on the span of the transaction as well. + * + * Closing the transaction is synchronous, i.e., it waits for + * SurfaceFlinger to composite one frame. Now, the FakeComposerClient + * is built to explicitly request vsyncs one at the time. A delayed + * request must be made before closing the transaction or the test + * thread stalls until SurfaceFlinger does an emergency vsync by + * itself. GlobalTransactionScope encapsulates this vsync magic. + */ +class GlobalTransactionScope { +public: + GlobalTransactionScope(FakeComposerClient& composer) : mComposer(composer) { + android::SurfaceComposerClient::openGlobalTransaction(); + } + ~GlobalTransactionScope() { + int frameCount = mComposer.getFrameCount(); + mComposer.runVSyncAfter(1ms); + android::SurfaceComposerClient::closeGlobalTransaction(true); + // Make sure that exactly one frame has been rendered. + mComposer.waitUntilFrame(frameCount + 1); + LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(), + "Unexpected frame advance. Delta: %d", + mComposer.getFrameCount() - frameCount); + } + FakeComposerClient& mComposer; +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h new file mode 100644 index 0000000000..0059289d4f --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/RenderState.h @@ -0,0 +1,44 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <hardware/hwcomposer2.h> + +#include <vector> + +namespace sftest { +// Description of a rendered rectangle. Should only contain +// instructions necessary to rasterize the rectangle. The full scene +// is given as a sorted list of rectangles, bottom layer at index 0. +class RenderState { +public: + RenderState() = default; + // Default copy-ctor + + hwc_rect_t mDisplayFrame = {0, 0, 0, 0}; + hwc_frect_t mSourceCrop = {0.f, 0.f, 0.f, 0.f}; + std::vector<hwc_rect_t> mVisibleRegion; + hwc2_blend_mode_t mBlendMode = HWC2_BLEND_MODE_NONE; + buffer_handle_t mBuffer = 0; + uint32_t mSwapCount = 0; // How many set buffer calls to the layer. + int32_t mAcquireFence = 0; // Probably should not be here. + float mPlaneAlpha = 0.f; + hwc_color_t mLayerColor = {0, 0, 0, 0}; + hwc_transform_t mTransform = static_cast<hwc_transform_t>(0); +}; + +} // namespace sftest diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp new file mode 100644 index 0000000000..8902ede301 --- /dev/null +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -0,0 +1,1306 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "FakeHwcTest" + +#include "FakeComposerClient.h" +#include "FakeComposerService.h" +#include "FakeComposerUtils.h" + +#include <gui/ISurfaceComposer.h> +#include <gui/LayerDebugInfo.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> + +#include <private/gui/ComposerService.h> +#include <private/gui/LayerState.h> + +#include <ui/DisplayInfo.h> + +#include <android/native_window.h> + +#include <android/hidl/manager/1.0/IServiceManager.h> + +#include <hwbinder/ProcessState.h> + +#include <binder/ProcessState.h> + +#include <log/log.h> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <limits> + +using namespace std::chrono_literals; + +using namespace android; +using namespace android::hardware; + +using namespace sftest; + +namespace { + +// Mock test helpers +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::_; + +/////////////////////////////////////////////// + +struct TestColor { +public: + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +constexpr static TestColor RED = {195, 63, 63, 255}; +constexpr static TestColor LIGHT_RED = {255, 177, 177, 255}; +constexpr static TestColor GREEN = {63, 195, 63, 255}; +constexpr static TestColor BLUE = {63, 63, 195, 255}; +constexpr static TestColor DARK_GRAY = {63, 63, 63, 255}; +constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255}; + +// Fill an RGBA_8888 formatted surface with a single color. +static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const TestColor& color, + bool unlock = true) { + ANativeWindow_Buffer outBuffer; + sp<Surface> s = sc->getSurface(); + ASSERT_TRUE(s != nullptr); + ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr)); + uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits); + for (int y = 0; y < outBuffer.height; y++) { + for (int x = 0; x < outBuffer.width; x++) { + uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); + pixel[0] = color.r; + pixel[1] = color.g; + pixel[2] = color.b; + pixel[3] = color.a; + } + } + if (unlock) { + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); + } +} + +inline RenderState makeSimpleRect(int left, int top, int right, int bottom) { + RenderState res; + res.mDisplayFrame = hwc_rect_t{left, top, right, bottom}; + res.mPlaneAlpha = 1.0f; + res.mSwapCount = 0; + res.mSourceCrop = hwc_frect_t{0.f, 0.f, static_cast<float>(right - left), + static_cast<float>(bottom - top)}; + return res; +} + +inline RenderState makeSimpleRect(unsigned int left, unsigned int top, unsigned int right, + unsigned int bottom) { + EXPECT_LE(left, static_cast<unsigned int>(INT_MAX)); + EXPECT_LE(top, static_cast<unsigned int>(INT_MAX)); + EXPECT_LE(right, static_cast<unsigned int>(INT_MAX)); + EXPECT_LE(bottom, static_cast<unsigned int>(INT_MAX)); + return makeSimpleRect(static_cast<int>(left), static_cast<int>(top), static_cast<int>(right), + static_cast<int>(bottom)); +} + +//////////////////////////////////////////////// + +class DisplayTest : public ::testing::Test { +public: + class MockComposerClient : public FakeComposerClient { + public: + MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType)); + MOCK_METHOD4(getDisplayAttribute, + Error(Display display, Config config, IComposerClient::Attribute attribute, + int32_t* outValue)); + + // Re-routing to basic fake implementation + Error getDisplayAttributeFake(Display display, Config config, + IComposerClient::Attribute attribute, int32_t* outValue) { + return FakeComposerClient::getDisplayAttribute(display, config, attribute, outValue); + } + }; + +protected: + void SetUp() override; + void TearDown() override; + + sp<IComposer> mFakeService; + sp<SurfaceComposerClient> mComposerClient; + + MockComposerClient* mMockComposer; +}; + +void DisplayTest::SetUp() { + // TODO: The mMockComposer should be a unique_ptr, but it needs to + // outlive the test class. Currently ComposerClient only dies + // when the service is replaced. The Mock deletes itself when + // removeClient is called on it, which is ugly. This can be + // changed if HIDL ServiceManager allows removing services or + // ComposerClient starts taking the ownership of the contained + // implementation class. Moving the fake class to the HWC2 + // interface instead of the current Composer interface might also + // change the situation. + mMockComposer = new MockComposerClient; + sp<ComposerClient> client = new ComposerClient(*mMockComposer); + mMockComposer->setClient(client.get()); + mFakeService = new FakeComposerService(client); + mFakeService->registerAsService("mock"); + + android::hardware::ProcessState::self()->startThreadPool(); + android::ProcessState::self()->startThreadPool(); + + EXPECT_CALL(*mMockComposer, getDisplayType(1, _)) + .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), + Return(Error::NONE))); + // Seems to be doubled right now, once for display ID 1 and once for 0. This sounds fishy + // but encoding that here exactly. + EXPECT_CALL(*mMockComposer, getDisplayAttribute(1, 1, _, _)) + .Times(5) + .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); + // TODO: Find out what code is generating the ID 0. + EXPECT_CALL(*mMockComposer, getDisplayAttribute(0, 1, _, _)) + .Times(5) + .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); + + startSurfaceFlinger(); + + // Fake composer wants to enable VSync injection + mMockComposer->onSurfaceFlingerStart(); + + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); +} + +void DisplayTest::TearDown() { + mComposerClient->dispose(); + mComposerClient = nullptr; + + // Fake composer needs to release SurfaceComposerClient before the stop. + mMockComposer->onSurfaceFlingerStop(); + stopSurfaceFlinger(); + + mFakeService = nullptr; + // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime + // management. + mMockComposer = nullptr; +} + +TEST_F(DisplayTest, Hotplug) { + ALOGD("DisplayTest::Hotplug"); + + EXPECT_CALL(*mMockComposer, getDisplayType(2, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), + Return(Error::NONE))); + // The attribute queries will get done twice. This is for defaults + EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, _, _)) + .Times(2 * 3) + .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); + // ... and then special handling for dimensions. Specifying this + // rules later means that gmock will try them first, i.e., + // ordering of width/height vs. the default implementation for + // other queries is significant. + EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::WIDTH, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE))); + + EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::HEIGHT, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE))); + + // TODO: Width and height queries are not actually called. Display + // info returns dimensions 0x0 in display info. Why? + + mMockComposer->hotplugDisplay(static_cast<Display>(2), + IComposerCallback::Connection::CONNECTED); + + { + sp<android::IBinder> display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(400u, info.w); + ASSERT_EQ(200u, info.h); + + auto surfaceControl = + mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w, info.h, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(surfaceControl != nullptr); + ASSERT_TRUE(surfaceControl->isValid()); + fillSurfaceRGBA8(surfaceControl, BLUE); + + { + GlobalTransactionScope gts(*mMockComposer); + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, surfaceControl->show()); + } + } + + mMockComposer->hotplugDisplay(static_cast<Display>(2), + IComposerCallback::Connection::DISCONNECTED); + + mMockComposer->clearFrames(); + + mMockComposer->hotplugDisplay(static_cast<Display>(2), + IComposerCallback::Connection::CONNECTED); + + { + sp<android::IBinder> display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(400u, info.w); + ASSERT_EQ(200u, info.h); + + auto surfaceControl = + mComposerClient->createSurface(String8("Display Test Surface Bar"), info.w, info.h, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(surfaceControl != nullptr); + ASSERT_TRUE(surfaceControl->isValid()); + fillSurfaceRGBA8(surfaceControl, BLUE); + + { + GlobalTransactionScope gts(*mMockComposer); + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, surfaceControl->show()); + } + } + mMockComposer->hotplugDisplay(static_cast<Display>(2), + IComposerCallback::Connection::DISCONNECTED); +} + +//////////////////////////////////////////////// + +class TransactionTest : public ::testing::Test { +protected: + // Layer array indexing constants. + constexpr static int BG_LAYER = 0; + constexpr static int FG_LAYER = 1; + + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; + + sp<SurfaceComposerClient> mComposerClient; + sp<SurfaceControl> mBGSurfaceControl; + sp<SurfaceControl> mFGSurfaceControl; + std::vector<RenderState> mBaseFrame; + uint32_t mDisplayWidth; + uint32_t mDisplayHeight; + + static FakeComposerClient* sFakeComposer; +}; + +FakeComposerClient* TransactionTest::sFakeComposer; + +void TransactionTest::SetUpTestCase() { + // TODO: See TODO comment at DisplayTest::SetUp for background on + // the lifetime of the FakeComposerClient. + sFakeComposer = new FakeComposerClient; + sp<ComposerClient> client = new ComposerClient(*sFakeComposer); + sFakeComposer->setClient(client.get()); + sp<IComposer> fakeService = new FakeComposerService(client); + fakeService->registerAsService("mock"); + + android::hardware::ProcessState::self()->startThreadPool(); + android::ProcessState::self()->startThreadPool(); + + startSurfaceFlinger(); + + // Fake composer wants to enable VSync injection + sFakeComposer->onSurfaceFlingerStart(); +} + +void TransactionTest::TearDownTestCase() { + // Fake composer needs to release SurfaceComposerClient before the stop. + sFakeComposer->onSurfaceFlingerStop(); + stopSurfaceFlinger(); + // TODO: This is deleted when the ComposerClient calls + // removeClient. Devise better lifetime control. + sFakeComposer = nullptr; +} + +void TransactionTest::SetUp() { + ALOGI("TransactionTest::SetUp"); + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + + ALOGI("TransactionTest::SetUp - display"); + sp<android::IBinder> display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + + mDisplayWidth = info.w; + mDisplayHeight = info.h; + + // Background surface + mBGSurfaceControl = mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth, + mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mBGSurfaceControl != nullptr); + ASSERT_TRUE(mBGSurfaceControl->isValid()); + fillSurfaceRGBA8(mBGSurfaceControl, BLUE); + + // Foreground surface + mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mFGSurfaceControl != nullptr); + ASSERT_TRUE(mFGSurfaceControl->isValid()); + + fillSurfaceRGBA8(mFGSurfaceControl, RED); + + SurfaceComposerClient::openGlobalTransaction(); + + mComposerClient->setDisplayLayerStack(display, 0); + + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX - 2)); + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); + + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX - 1)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + + // Synchronous transaction will stop this thread, so we set up a + // delayed, off-thread vsync request before closing the + // transaction. In the test code this is usually done with + // GlobalTransactionScope. Leaving here in the 'vanilla' form for + // reference. + ASSERT_EQ(0, sFakeComposer->getFrameCount()); + sFakeComposer->runVSyncAfter(1ms); + SurfaceComposerClient::closeGlobalTransaction(true); + sFakeComposer->waitUntilFrame(1); + + // Reference data. This is what the HWC should see. + static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing"); + mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight)); + mBaseFrame[BG_LAYER].mSwapCount = 1; + mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64)); + mBaseFrame[FG_LAYER].mSwapCount = 1; + + auto frame = sFakeComposer->getFrameRects(0); + ASSERT_TRUE(framesAreSame(mBaseFrame, frame)); +} + +void TransactionTest::TearDown() { + ALOGD("TransactionTest::TearDown"); + + mComposerClient->dispose(); + mBGSurfaceControl = 0; + mFGSurfaceControl = 0; + mComposerClient = 0; + + sFakeComposer->runVSyncAndWait(); + mBaseFrame.clear(); + sFakeComposer->clearFrames(); + ASSERT_EQ(0, sFakeComposer->getFrameCount()); + + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + std::vector<LayerDebugInfo> layers; + status_t result = sf->getLayerDebugInfo(&layers); + if (result != NO_ERROR) { + ALOGE("Failed to get layers %s %d", strerror(-result), result); + } else { + // If this fails, the test being torn down leaked layers. + EXPECT_EQ(0u, layers.size()); + if (layers.size() > 0) { + for (auto layer = layers.begin(); layer != layers.end(); ++layer) { + std::cout << to_string(*layer).c_str(); + } + // To ensure the next test has clean slate, will run the class + // tear down and setup here. + TearDownTestCase(); + SetUpTestCase(); + } + } + ALOGD("TransactionTest::TearDown - complete"); +} + +TEST_F(TransactionTest, LayerMove) { + ALOGD("TransactionTest::LayerMove"); + + // The scope opens and closes a global transaction and, at the + // same time, makes sure the SurfaceFlinger progresses one frame + // after the transaction closes. The results of the transaction + // should be available in the latest frame stored by the fake + // composer. + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); + // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls. + // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?) + // + // sFakeComposer->runVSyncAndWait(); + } + + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + + ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's + // no extra frames. + + // NOTE: Frame 0 is produced in the SetUp. + auto frame1Ref = mBaseFrame; + frame1Ref[FG_LAYER].mDisplayFrame = + hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves. + EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1))); + + auto frame2Ref = frame1Ref; + frame2Ref[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); +} + +TEST_F(TransactionTest, LayerResize) { + ALOGD("TransactionTest::LayerResize"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128)); + } + + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + + ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's + // no extra frames. + + auto frame1Ref = mBaseFrame; + // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size posted. + EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1))); + + auto frame2Ref = frame1Ref; + frame2Ref[FG_LAYER].mSwapCount++; + frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128}; + frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f}; + EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); +} + +TEST_F(TransactionTest, LayerCrop) { + // TODO: Add scaling to confirm that crop happens in buffer space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(16, 16, 32, 32); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f}; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerFinalCrop) { + // TODO: Add scaling to confirm that crop happens in display space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(32, 32, 32 + 64, 32 + 64); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // In display space we are cropping with [32, 32, 96, 96] against display rect + // [64, 64, 128, 128]. Should yield display rect [64, 64, 96, 96] + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f}; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 32, 64 + 32}; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerFinalCropEmpty) { + // TODO: Add scaling to confirm that crop happens in display space? + { + GlobalTransactionScope gts(*sFakeComposer); + Rect cropRect(16, 16, 32, 32); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // In display space we are cropping with [16, 16, 32, 32] against display rect + // [64, 64, 128, 128]. The intersection is empty and only the background layer is composited. + std::vector<RenderState> referenceFrame(1); + referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetLayer) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // The layers will switch order, but both are rendered because the background layer is + // transparent (RGBA8888). + std::vector<RenderState> referenceFrame(2); + referenceFrame[0] = mBaseFrame[FG_LAYER]; + referenceFrame[1] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetLayerOpaque) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); + ASSERT_EQ(NO_ERROR, + mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, + layer_state_t::eLayerOpaque)); + } + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + + // The former foreground layer is now covered with opaque layer - it should have disappeared + std::vector<RenderState> referenceFrame(1); + referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, SetLayerStack) { + ALOGD("TransactionTest::SetLayerStack"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1)); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector<RenderState> refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerShowHide) { + ALOGD("TransactionTest::LayerShowHide"); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide()); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector<RenderState> refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + } + + // Foreground layer should be back + ASSERT_EQ(3, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetAlpha) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f)); + } + + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetFlags) { + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, + mFGSurfaceControl->setFlags(layer_state_t::eLayerHidden, + layer_state_t::eLayerHidden)); + } + + // Foreground layer should have disappeared. + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + std::vector<RenderState> refFrame(1); + refFrame[BG_LAYER] = mBaseFrame[BG_LAYER]; + EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, LayerSetMatrix) { + struct matrixTestData { + float matrix[4]; + hwc_transform_t expectedTransform; + hwc_rect_t expectedDisplayFrame; + }; + + // The matrix operates on the display frame and is applied before + // the position is added. So, the foreground layer rect is (0, 0, + // 64, 64) is first transformed, potentially yielding negative + // coordinates and then the position (64, 64) is added yielding + // the final on-screen rectangles given. + + const matrixTestData MATRIX_TESTS[7] = // clang-format off + {{{-1.f, 0.f, 0.f, 1.f}, HWC_TRANSFORM_FLIP_H, {0, 64, 64, 128}}, + {{1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_FLIP_V, {64, 0, 128, 64}}, + {{0.f, 1.f, -1.f, 0.f}, HWC_TRANSFORM_ROT_90, {0, 64, 64, 128}}, + {{-1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_ROT_180, {0, 0, 64, 64}}, + {{0.f, -1.f, 1.f, 0.f}, HWC_TRANSFORM_ROT_270, {64, 0, 128, 64}}, + {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}}, + {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}}; + // clang-format on + constexpr int TEST_COUNT = sizeof(MATRIX_TESTS)/sizeof(matrixTestData); + + for (int i = 0; i < TEST_COUNT; i++) { + // TODO: How to leverage the HWC2 stringifiers? + const matrixTestData& xform = MATRIX_TESTS[i]; + SCOPED_TRACE(i); + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, + mFGSurfaceControl->setMatrix(xform.matrix[0], xform.matrix[1], + xform.matrix[2], xform.matrix[3])); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mTransform = xform.expectedTransform; + referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + } +} + +#if 0 +TEST_F(TransactionTest, LayerSetMatrix2) { + { + GlobalTransactionScope gts(*sFakeComposer); + // TODO: PLEASE SPEC THE FUNCTION! + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(0.11f, 0.123f, + -2.33f, 0.22f)); + } + auto referenceFrame = mBaseFrame; + // TODO: Is this correct for sure? + //referenceFrame[FG_LAYER].mTransform = HWC_TRANSFORM_FLIP_V & HWC_TRANSFORM_ROT_90; + + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} +#endif + +TEST_F(TransactionTest, DeferredTransaction) { + // Synchronization surface + constexpr static int SYNC_LAYER = 2; + auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(syncSurfaceControl != nullptr); + ASSERT_TRUE(syncSurfaceControl->isValid()); + + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->setLayer(INT32_MAX - 1)); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->setPosition(mDisplayWidth - 2, mDisplayHeight - 2)); + ASSERT_EQ(NO_ERROR, syncSurfaceControl->show()); + } + auto referenceFrame = mBaseFrame; + referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2, + mDisplayWidth - 1, mDisplayHeight - 1)); + referenceFrame[SYNC_LAYER].mSwapCount = 1; + EXPECT_EQ(2, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // set up two deferred transactions on different frames - these should not yield composited + // frames + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75)); + mFGSurfaceControl + ->deferTransactionUntil(syncSurfaceControl->getHandle(), + syncSurfaceControl->getSurface()->getNextFrameNumber()); + } + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); + mFGSurfaceControl + ->deferTransactionUntil(syncSurfaceControl->getHandle(), + syncSurfaceControl->getSurface()->getNextFrameNumber() + 1); + } + EXPECT_EQ(4, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // should trigger the first deferred transaction, but not the second one + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + sFakeComposer->runVSyncAndWait(); + EXPECT_EQ(5, sFakeComposer->getFrameCount()); + + referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f; + referenceFrame[SYNC_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // should show up immediately since it's not deferred + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0)); + } + referenceFrame[FG_LAYER].mPlaneAlpha = 1.f; + EXPECT_EQ(6, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // trigger the second deferred transaction + fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); + sFakeComposer->runVSyncAndWait(); + // TODO: Compute from layer size? + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64}; + referenceFrame[SYNC_LAYER].mSwapCount++; + EXPECT_EQ(7, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(TransactionTest, SetRelativeLayer) { + constexpr int RELATIVE_LAYER = 2; + auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, 64, + PIXEL_FORMAT_RGBA_8888, 0); + fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED); + + // Now we stack the surface above the foreground surface and make sure it is visible. + { + GlobalTransactionScope gts(*sFakeComposer); + relativeSurfaceControl->setPosition(64, 64); + relativeSurfaceControl->show(); + relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1); + } + auto referenceFrame = mBaseFrame; + // NOTE: All three layers will be visible as the surfaces are + // transparent because of the RGBA format. + referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64)); + referenceFrame[RELATIVE_LAYER].mSwapCount = 1; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + // A call to setLayer will override a call to setRelativeLayer + { + GlobalTransactionScope gts(*sFakeComposer); + relativeSurfaceControl->setLayer(0); + } + + // Previous top layer will now appear at the bottom. + auto referenceFrame2 = mBaseFrame; + referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]); + EXPECT_EQ(3, sFakeComposer->getFrameCount()); + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +class ChildLayerTest : public TransactionTest { +protected: + constexpr static int CHILD_LAYER = 2; + + void SetUp() override { + TransactionTest::SetUp(); + mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(mChild, LIGHT_GRAY); + + sFakeComposer->runVSyncAndWait(); + mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10)); + mBaseFrame[CHILD_LAYER].mSwapCount = 1; + ASSERT_EQ(2, sFakeComposer->getFrameCount()); + ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + } + void TearDown() override { + mChild = 0; + TransactionTest::TearDown(); + } + + sp<SurfaceControl> mChild; +}; + +TEST_F(ChildLayerTest, Positioning) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + // Move to the same position as in the original setup. + mFGSurfaceControl->setPosition(64, 64); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0)); + } + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Cropping) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5)); + } + // NOTE: The foreground surface would be occluded by the child + // now, but is included in the stack because the child is + // transparent. + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, FinalCropping) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5)); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Constraints) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mFGSurfaceControl->setPosition(0, 0); + mChild->setPosition(63, 63); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Scaling) { + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setPosition(0, 0); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0); + } + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, LayerAlpha) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5)); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5)); + } + + auto referenceFrame2 = referenceFrame; + referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f; + referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, ReparentChildren) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + mFGSurfaceControl->setPosition(64, 64); + } + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle()); + } + + auto referenceFrame2 = referenceFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, DetachChildren) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(10, 10); + mFGSurfaceControl->setPosition(64, 64); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; + referenceFrame[CHILD_LAYER].mDisplayFrame = + hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->detachChildren(); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->hide(); + } + + // Nothing should have changed. The child control becomes a no-op + // zombie on detach. See comments for detachChildren in the + // SurfaceControl.h file. + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + // We cause scaling by 2. + mFGSurfaceControl->setSize(128, 128); + } + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f}; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20}; + referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +// Regression test for b/37673612 +TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->show(); + mChild->setPosition(0, 0); + mFGSurfaceControl->setPosition(0, 0); + } + + // We set things up as in b/37673612 so that there is a mismatch between the buffer size and + // the WM specified state size. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 64); + } + + sp<Surface> s = mFGSurfaceControl->getSurface(); + auto anw = static_cast<ANativeWindow*>(s.get()); + native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); + native_window_set_buffers_dimensions(anw, 64, 128); + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + + // The child should still be in the same place and not have any strange scaling as in + // b/37673612. + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64}; + referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f}; + referenceFrame[FG_LAYER].mSwapCount++; + referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +TEST_F(ChildLayerTest, Bug36858924) { + // Destroy the child layer + mChild.clear(); + + // Now recreate it as hidden + mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden, + mFGSurfaceControl.get()); + + // Show the child layer in a deferred transaction + { + GlobalTransactionScope gts(*sFakeComposer); + mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(), + mFGSurfaceControl->getSurface()->getNextFrameNumber()); + mChild->show(); + } + + // Render the foreground surface a few times + // + // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third + // frame because SurfaceFlinger would never process the deferred transaction and would therefore + // never acquire/release the first buffer + ALOGI("Filling 1"); + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 2"); + fillSurfaceRGBA8(mFGSurfaceControl, BLUE); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 3"); + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + ALOGI("Filling 4"); + fillSurfaceRGBA8(mFGSurfaceControl, GREEN); + sFakeComposer->runVSyncAndWait(); +} + +class LatchingTest : public TransactionTest { +protected: + void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); } + + void unlockFGBuffer() { + sp<Surface> s = mFGSurfaceControl->getSurface(); + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); + sFakeComposer->runVSyncAndWait(); + } + + void completeFGResize() { + fillSurfaceRGBA8(mFGSurfaceControl, RED); + sFakeComposer->runVSyncAndWait(); + } + void restoreInitialState() { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(64, 64); + mFGSurfaceControl->setPosition(64, 64); + mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64)); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); + } +}; + +TEST_F(LatchingTest, SurfacePositionLatching) { + // By default position can be updated even while + // a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(32, 32); + mFGSurfaceControl->setPosition(100, 100); + } + + // The size should not have updated as we have not provided a new buffer. + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + // Now we repeat with setGeometryAppliesWithResize + // and verify the position DOESN'T latch. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setSize(32, 32); + mFGSurfaceControl->setPosition(100, 100); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32}; + referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, CropLatching) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; + referenceFrame1[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; + referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, FinalCropLatching) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame1[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame2[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)}; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); +} + +// In this test we ensure that setGeometryAppliesWithResize actually demands +// a buffer of the new size, and not just any size. +TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) { + // Normally the crop applies immediately even while a resize is pending. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + auto referenceFrame1 = mBaseFrame; + referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame1[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)}; + EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame())); + + restoreInitialState(); + + // In order to prepare to submit a buffer at the wrong size, we acquire it prior to + // initiating the resize. + lockAndFillFGBuffer(); + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + // We now submit our old buffer, at the old size, and ensure it doesn't + // trigger geometry latching. + unlockFGBuffer(); + + auto referenceFrame2 = mBaseFrame; + referenceFrame2[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame())); + + completeFGResize(); + auto referenceFrame3 = referenceFrame2; + referenceFrame3[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127}; + referenceFrame3[FG_LAYER].mSourceCrop = + hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)}; + referenceFrame3[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame3, sFakeComposer->getLatestFrame())); +} + +TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) { + // In this scenario, we attempt to set the final crop a second time while the resize + // is still pending, and ensure we are successful. Success meaning the second crop + // is the one which eventually latches and not the first. + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setSize(128, 128); + mFGSurfaceControl->setGeometryAppliesWithResize(); + mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + } + + { + GlobalTransactionScope gts(*sFakeComposer); + mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); + } + EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); + + completeFGResize(); + + auto referenceFrame = mBaseFrame; + referenceFrame[FG_LAYER].mSwapCount++; + EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); +} + +} // namespace + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + sftest::FakeHwcEnvironment* fakeEnvironment = new sftest::FakeHwcEnvironment; + ::testing::AddGlobalTestEnvironment(fakeEnvironment); + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp index 062485ea52..4055527b13 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp @@ -382,7 +382,9 @@ public: if (outErr) { *outErr = err; } else { - ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set cursor position"; + ASSERT_TRUE((err == HWC2_ERROR_NONE) || + (err == HWC2_ERROR_BAD_LAYER)) << + "failed to set cursor position"; } } @@ -652,7 +654,7 @@ public: hwc2_layer_request_t request = requests.at(i); EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer), - 0) << "get display requests returned an unknown layer"; + 1) << "get display requests returned an unknown layer"; EXPECT_NE(request, 0) << "returned empty request for layer " << requestedLayer; @@ -1603,9 +1605,10 @@ protected: EXPECT_EQ(layers.size(), fences.size()); for (int32_t fence : fences) { - EXPECT_GE(sync_wait(fence, msWait), 0); - if (fence >= 0) + if (fence >= 0) { + EXPECT_GE(sync_wait(fence, msWait), 0); close(fence); + } } } @@ -1643,8 +1646,9 @@ protected: testLayers->getBlendMode(layer))); EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer, testLayers->getColor(layer))); - EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, cursor.left, - cursor.top)); + if (composition == HWC2_COMPOSITION_CURSOR) + EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, + cursor.left, cursor.top)); EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer, testLayers->getDataspace(layer))); EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer, @@ -2895,7 +2899,6 @@ TEST_F(Hwc2Test, SET_CURSOR_POSITION_composition_type_unset) ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { - const hwc_rect_t cursorPosition = testLayer->getCursorPosition(); EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer, cursorPosition.left, cursorPosition.top, outErr)); @@ -4406,11 +4409,11 @@ TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_display) /* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */ TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter) { - hwc2_display_t display = HWC_DISPLAY_PRIMARY; hwc2_error_t err = HWC2_ERROR_NONE; - - ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err)); - EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code"; + for (auto display : mDisplays) { + ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code"; + } } /* TESTCASE: Tests that the HWC2 can get the max virtual display count. */ diff --git a/services/thermalservice/Android.bp b/services/thermalservice/Android.bp new file mode 100644 index 0000000000..d754560ea5 --- /dev/null +++ b/services/thermalservice/Android.bp @@ -0,0 +1,61 @@ +subdirs = [ + "libthermalcallback" +] + +cc_library { + name: "libthermalservice", + + srcs: [ + "aidl/android/os/IThermalEventListener.aidl", + "aidl/android/os/IThermalService.aidl", + "aidl/android/os/Temperature.cpp", + ], + aidl: { + include_dirs: ["frameworks/native/services/thermalservice/aidl"], + export_aidl_headers: true, + }, + export_include_dirs: ["aidl"], + + shared_libs: [ + "libbinder", + "libutils", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wunused", + "-Wunreachable-code", + ], +} + +cc_binary { + name: "thermalserviced", + + srcs: [ + "ThermalService.cpp", + "thermalserviced.cpp", + ], + + include_dirs: ["frameworks/native"], + + shared_libs: [ + "libthermalservice", + "libbinder", + "libutils", + "libthermalcallback", + "android.hardware.thermal@1.1", + "libhidlbase", + "libhidltransport", + "liblog", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wunused", + "-Wunreachable-code", + ], + + init_rc: ["thermalservice.rc"], +} diff --git a/services/thermalservice/ThermalService.cpp b/services/thermalservice/ThermalService.cpp new file mode 100644 index 0000000000..6e09a83872 --- /dev/null +++ b/services/thermalservice/ThermalService.cpp @@ -0,0 +1,126 @@ +/* + * 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 "ThermalService.h" +#include <android/os/IThermalService.h> +#include <android/os/IThermalEventListener.h> +#include <android/os/Temperature.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <utils/Errors.h> +#include <utils/Mutex.h> +#include <utils/String16.h> + +namespace android { +namespace os { + +/** + * Notify registered listeners of a thermal throttling start/stop event. + * @param temperature the temperature at which the event was generated + */ +binder::Status ThermalService::notifyThrottling( + const bool isThrottling, const Temperature& temperature) { + Mutex::Autolock _l(mListenersLock); + + mThrottled = isThrottling; + mThrottleTemperature = temperature; + + for (size_t i = 0; i < mListeners.size(); i++) { + mListeners[i]->notifyThrottling(isThrottling, temperature); + } + return binder::Status::ok(); +} + +/** + * Query whether the system is currently thermal throttling. + * @return true if currently thermal throttling, else false + */ +binder::Status ThermalService::isThrottling(bool* _aidl_return) { + Mutex::Autolock _l(mListenersLock); + *_aidl_return = mThrottled; + return binder::Status::ok(); +} + +/** + * Register a new thermal event listener. + * @param listener the client's IThermalEventListener instance to which + * notifications are to be sent + */ +binder::Status ThermalService::registerThermalEventListener( + const sp<IThermalEventListener>& listener) { + { + if (listener == NULL) + return binder::Status::ok(); + Mutex::Autolock _l(mListenersLock); + // check whether this is a duplicate + for (size_t i = 0; i < mListeners.size(); i++) { + if (IInterface::asBinder(mListeners[i]) == + IInterface::asBinder(listener)) { + return binder::Status::ok(); + } + } + + mListeners.add(listener); + IInterface::asBinder(listener)->linkToDeath(this); + } + + return binder::Status::ok(); +} + +/** + * Unregister a previously-registered thermal event listener. + * @param listener the client's IThermalEventListener instance to which + * notifications are to no longer be sent + */ +binder::Status ThermalService::unregisterThermalEventListener( + const sp<IThermalEventListener>& listener) { + if (listener == NULL) + return binder::Status::ok(); + Mutex::Autolock _l(mListenersLock); + for (size_t i = 0; i < mListeners.size(); i++) { + if (IInterface::asBinder(mListeners[i]) == + IInterface::asBinder(listener)) { + IInterface::asBinder(mListeners[i])->unlinkToDeath(this); + mListeners.removeAt(i); + break; + } + } + + return binder::Status::ok(); +} + +void ThermalService::binderDied(const wp<IBinder>& who) { + Mutex::Autolock _l(mListenersLock); + + for (size_t i = 0; i < mListeners.size(); i++) { + if (IInterface::asBinder(mListeners[i]) == who) { + mListeners.removeAt(i); + break; + } + } +} + +/** + * Publish the supplied ThermalService to servicemanager. + */ +void ThermalService::publish( + const sp<ThermalService>& service) { + defaultServiceManager()->addService(String16("thermalservice"), + service); +} + +} // namespace os +} // namespace android diff --git a/services/thermalservice/ThermalService.h b/services/thermalservice/ThermalService.h new file mode 100644 index 0000000000..17dfcbcd37 --- /dev/null +++ b/services/thermalservice/ThermalService.h @@ -0,0 +1,55 @@ +/* + * 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_THERMALSERVICE_THERMALSERVICE_H +#define ANDROID_THERMALSERVICE_THERMALSERVICE_H + +#include <android/os/BnThermalService.h> +#include <android/os/IThermalEventListener.h> +#include <android/os/Temperature.h> +#include <utils/Mutex.h> +#include <utils/String16.h> +#include <utils/Vector.h> + +namespace android { +namespace os { + +class ThermalService : public BnThermalService, + public IBinder::DeathRecipient { +public: + ThermalService() : mThrottled(false) {}; + void publish(const sp<ThermalService>& service); + binder::Status notifyThrottling( + const bool isThrottling, const Temperature& temperature); + +private: + Mutex mListenersLock; + Vector<sp<IThermalEventListener> > mListeners; + bool mThrottled; + Temperature mThrottleTemperature; + + binder::Status registerThermalEventListener( + const sp<IThermalEventListener>& listener); + binder::Status unregisterThermalEventListener( + const sp<IThermalEventListener>& listener); + binder::Status isThrottling(bool* _aidl_return); + void binderDied(const wp<IBinder>& who); +}; + +}; // namespace os +}; // namespace android + +#endif // ANDROID_THERMALSERVICE_THERMALSERVICE_H diff --git a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl new file mode 100644 index 0000000000..050325e2fc --- /dev/null +++ b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl @@ -0,0 +1,32 @@ +/** + * 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. + */ + +package android.os; + +import android.os.Temperature; + +/** + * Listener for thermal events. + * {@hide} + */ +oneway interface IThermalEventListener { + /** + * Called when a thermal throttling start/stop event is received. + * @param temperature the temperature at which the event was generated. + */ + void notifyThrottling( + in boolean isThrottling, in Temperature temperature); +} diff --git a/services/thermalservice/aidl/android/os/IThermalService.aidl b/services/thermalservice/aidl/android/os/IThermalService.aidl new file mode 100644 index 0000000000..e699202e64 --- /dev/null +++ b/services/thermalservice/aidl/android/os/IThermalService.aidl @@ -0,0 +1,48 @@ +/** + * 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. + */ + +package android.os; + +import android.os.IThermalEventListener; +import android.os.Temperature; + +/** {@hide} */ +interface IThermalService { + /** + * Register a listener for thermal events. + * @param listener the IThermalEventListener to be notified. + * {@hide} + */ + void registerThermalEventListener(in IThermalEventListener listener); + /** + * Unregister a previously-registered listener for thermal events. + * @param listener the IThermalEventListener to no longer be notified. + * {@hide} + */ + void unregisterThermalEventListener(in IThermalEventListener listener); + /** + * Send a thermal throttling start/stop notification to all listeners. + * @param temperature the temperature at which the event was generated. + * {@hide} + */ + oneway void notifyThrottling( + in boolean isThrottling, in Temperature temperature); + /** + * Return whether system performance is currently thermal throttling. + * {@hide} + */ + boolean isThrottling(); +} diff --git a/services/thermalservice/aidl/android/os/Temperature.aidl b/services/thermalservice/aidl/android/os/Temperature.aidl new file mode 100644 index 0000000000..0293c39fa9 --- /dev/null +++ b/services/thermalservice/aidl/android/os/Temperature.aidl @@ -0,0 +1,5 @@ +package android.os; + +/* Encodes a temperature used by ThermalService. */ + +parcelable Temperature cpp_header "android/os/Temperature.h"; diff --git a/services/thermalservice/aidl/android/os/Temperature.cpp b/services/thermalservice/aidl/android/os/Temperature.cpp new file mode 100644 index 0000000000..df207b7ac3 --- /dev/null +++ b/services/thermalservice/aidl/android/os/Temperature.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "android/os/Temperature.h" + +#include <math.h> +#include <stdint.h> +#include <binder/Parcel.h> +#include <hardware/thermal.h> +#include <sys/types.h> +#include <utils/Errors.h> + +namespace android { +namespace os { + +Temperature::Temperature() : value_(NAN), type_(DEVICE_TEMPERATURE_UNKNOWN) {} + +Temperature::Temperature(const float value, const int type) : + value_(value), type_(type) {} + +Temperature::~Temperature() {} + +/* + * Parcel read/write code must be kept in sync with + * frameworks/base/core/java/android/os/Temperature.java + */ + +status_t Temperature::readFromParcel(const Parcel* p) { + value_ = p->readFloat(); + type_ = p->readInt32(); + return OK; +} + +status_t Temperature::writeToParcel(Parcel* p) const { + p->writeFloat(value_); + p->writeInt32(type_); + return OK; +} + +} // namespace os +} // namespace android diff --git a/services/thermalservice/aidl/android/os/Temperature.h b/services/thermalservice/aidl/android/os/Temperature.h new file mode 100644 index 0000000000..bbc5607f8b --- /dev/null +++ b/services/thermalservice/aidl/android/os/Temperature.h @@ -0,0 +1,33 @@ +#ifndef ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H +#define ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H + +#include <binder/Parcelable.h> + +namespace android { +namespace os { + +class Temperature : public Parcelable { + public: + + Temperature(); + Temperature(const float value, const int type); + ~Temperature() override; + + float getValue() const {return value_;}; + float getType() const {return type_;}; + + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + + private: + // The value of the temperature as a float, or NAN if unknown. + float value_; + // The type of the temperature, an enum temperature_type from + // hardware/thermal.h + int type_; +}; + +} // namespace os +} // namespace android + +#endif // ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H diff --git a/services/thermalservice/libthermalcallback/Android.bp b/services/thermalservice/libthermalcallback/Android.bp new file mode 100644 index 0000000000..e98506e47e --- /dev/null +++ b/services/thermalservice/libthermalcallback/Android.bp @@ -0,0 +1,19 @@ +cc_library_shared { + name: "libthermalcallback", + srcs: [ + "ThermalCallback.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + ], + include_dirs: ["frameworks/native"], + shared_libs: [ + "android.hardware.thermal@1.1", + "libhidlbase", + "libhidltransport", + "liblog", + "libthermalservice", + "libutils", + ], +} diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.cpp b/services/thermalservice/libthermalcallback/ThermalCallback.cpp new file mode 100644 index 0000000000..5e094fa259 --- /dev/null +++ b/services/thermalservice/libthermalcallback/ThermalCallback.cpp @@ -0,0 +1,69 @@ +#define LOG_TAG "android.hardware.thermal.thermalcallback@1.1-impl" +#include <log/log.h> + +#include "ThermalCallback.h" +#include "services/thermalservice/ThermalService.h" +#include <math.h> +#include <android/os/Temperature.h> +#include <hardware/thermal.h> + +namespace android { +namespace hardware { +namespace thermal { +namespace V1_1 { +namespace implementation { + +using ::android::os::ThermalService; +using ::android::hardware::thermal::V1_0::TemperatureType; + +// Register a binder ThermalService object for sending events +void ThermalCallback::registerThermalService(sp<ThermalService> thermalService) +{ + mThermalService = thermalService; +} + +// Methods from IThermalCallback::V1_1 follow. +Return<void> ThermalCallback::notifyThrottling( + bool isThrottling, + const android::hardware::thermal::V1_0::Temperature& temperature) { + + // Convert HIDL IThermal Temperature to binder IThermalService Temperature. + if (mThermalService != nullptr) { + float value = NAN; + int type = DEVICE_TEMPERATURE_UNKNOWN; + + switch(temperature.type) { + case TemperatureType::CPU: + type = DEVICE_TEMPERATURE_CPU; + break; + case TemperatureType::GPU: + type = DEVICE_TEMPERATURE_GPU; + break; + case TemperatureType::BATTERY: + type = DEVICE_TEMPERATURE_BATTERY; + break; + case TemperatureType::SKIN: + type = DEVICE_TEMPERATURE_SKIN; + break; + case TemperatureType::UNKNOWN: + default: + type = DEVICE_TEMPERATURE_UNKNOWN; + break; + } + + value = temperature.currentValue == UNKNOWN_TEMPERATURE ? NAN : + temperature.currentValue; + + android::os::Temperature thermal_svc_temp(value, type); + mThermalService->notifyThrottling(isThrottling, thermal_svc_temp); + } else { + ALOGE("IThermalService binder service not created, drop throttling event"); + } + return Void(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace thermal +} // namespace hardware +} // namespace android diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.h b/services/thermalservice/libthermalcallback/ThermalCallback.h new file mode 100644 index 0000000000..3d72c680b4 --- /dev/null +++ b/services/thermalservice/libthermalcallback/ThermalCallback.h @@ -0,0 +1,43 @@ +#ifndef ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H +#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H + +#include <android/hardware/thermal/1.1/IThermalCallback.h> +#include <android/hardware/thermal/1.0/types.h> +#include <android/os/Temperature.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include "services/thermalservice/ThermalService.h" + +namespace android { +namespace hardware { +namespace thermal { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::os::ThermalService; + +class ThermalCallback : public IThermalCallback { + public: + // Register a binder ThermalService object for sending events + void registerThermalService(sp<ThermalService> thermalService); + + // Methods from IThermalCallback::V1_1 follow. + Return<void> notifyThrottling( + bool isThrottling, + const android::hardware::thermal::V1_0::Temperature& temperature) + override; + + private: + // Our registered binder ThermalService object to use for sending events + sp<android::os::ThermalService> mThermalService; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace thermal +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc new file mode 100644 index 0000000000..b9836cec80 --- /dev/null +++ b/services/thermalservice/thermalservice.rc @@ -0,0 +1,2 @@ +service thermalservice /system/bin/thermalserviced + class core diff --git a/services/thermalservice/thermalserviced.cpp b/services/thermalservice/thermalserviced.cpp new file mode 100644 index 0000000000..b9315b8bc3 --- /dev/null +++ b/services/thermalservice/thermalserviced.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "thermalserviced" +#include <log/log.h> + +#include "thermalserviced.h" +#include "ThermalService.h" +#include "libthermalcallback/ThermalCallback.h" + +#include <android/hardware/thermal/1.1/IThermal.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <hidl/HidlTransportSupport.h> + +using namespace android; +using ::android::hardware::thermal::V1_1::IThermal; +using ::android::hardware::thermal::V1_0::Temperature; +using ::android::hardware::thermal::V1_1::IThermalCallback; +using ::android::hardware::thermal::V1_1::implementation::ThermalCallback; +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::hidl_death_recipient; +using ::android::hidl::base::V1_0::IBase; +using ::android::os::ThermalService; + +template<typename T> +using Return = hardware::Return<T>; + +namespace { + +// Our thermalserviced main object +ThermalServiceDaemon* gThermalServiceDaemon; + +// Thermal HAL client +sp<IThermal> gThermalHal = nullptr; + +// Binder death notifier informing of Thermal HAL death. +struct ThermalServiceDeathRecipient : hidl_death_recipient { + virtual void serviceDied( + uint64_t cookie __unused, const wp<IBase>& who __unused) { + gThermalHal = nullptr; + ALOGE("IThermal HAL died"); + gThermalServiceDaemon->getThermalHal(); + } +}; + +sp<ThermalServiceDeathRecipient> gThermalHalDied = nullptr; + +} // anonymous namespace + +void ThermalServiceDaemon::thermalServiceStartup() { + // Binder IThermalService startup + mThermalService = new android::os::ThermalService; + mThermalService->publish(mThermalService); + // Register IThermalService object with IThermalCallback + if (mThermalCallback != nullptr) + mThermalCallback->registerThermalService(mThermalService); + IPCThreadState::self()->joinThreadPool(); +} + +// Lookup Thermal HAL, register death notifier, register our +// ThermalCallback with the Thermal HAL. +void ThermalServiceDaemon::getThermalHal() { + gThermalHal = IThermal::getService(); + if (gThermalHal == nullptr) { + ALOGW("Unable to get Thermal HAL V1.1, vendor thermal event notification not available"); + return; + } + + // Binder death notifier for Thermal HAL + if (gThermalHalDied == nullptr) + gThermalHalDied = new ThermalServiceDeathRecipient(); + + if (gThermalHalDied != nullptr) + gThermalHal->linkToDeath(gThermalHalDied, 0x451F /* cookie */); + + if (mThermalCallback != nullptr) { + Return<void> ret = gThermalHal->registerThermalCallback( + mThermalCallback); + if (!ret.isOk()) + ALOGE("registerThermalCallback failed, status: %s", + ret.description().c_str()); + } +} + +void ThermalServiceDaemon::thermalCallbackStartup() { + status_t err; + + // HIDL IThermalCallback startup + // Need at least 2 threads in thread pool since we wait for dead HAL + // to come back on the binder death notification thread and we need + // another thread for the incoming service now available call. + configureRpcThreadpool(2, false /* callerWillJoin */); + mThermalCallback = new ThermalCallback(); + err = mThermalCallback->registerAsService(); + ALOGE_IF(err != OK, "Cannot register %s: %d", + IThermalCallback::descriptor, err); + + // Lookup Thermal HAL and register our ThermalCallback. + getThermalHal(); +} + +int main(int /*argc*/, char** /*argv*/) { + gThermalServiceDaemon = new ThermalServiceDaemon(); + gThermalServiceDaemon->thermalCallbackStartup(); + gThermalServiceDaemon->thermalServiceStartup(); + /* NOTREACHED */ +} diff --git a/services/thermalservice/thermalserviced.h b/services/thermalservice/thermalserviced.h new file mode 100644 index 0000000000..309e2fe422 --- /dev/null +++ b/services/thermalservice/thermalserviced.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_THERMALSERVICE_THERMALSERVICED_H +#define ANDROID_THERMALSERVICE_THERMALSERVICED_H + +#include "ThermalService.h" +#include "libthermalcallback/ThermalCallback.h" + +using namespace android; +using ::android::hardware::thermal::V1_0::Temperature; +using ::android::hardware::thermal::V1_1::implementation::ThermalCallback; +using ::android::os::ThermalService; + +class ThermalServiceDaemon { + public: + void thermalServiceStartup(); + void thermalCallbackStartup(); + void getThermalHal(); + ThermalServiceDaemon() {}; + + private: + sp<ThermalService> mThermalService; + sp<ThermalCallback> mThermalCallback; +}; + +#endif // ANDROID_THERMALSERVICE_THERMALSERVICED_H diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp index d4fc540a61..1613821290 100644 --- a/services/vr/bufferhubd/bufferhubd.cpp +++ b/services/vr/bufferhubd/bufferhubd.cpp @@ -4,7 +4,7 @@ #include <log/log.h> #include <dvr/performance_client_api.h> -#include <pdx/default_transport/service_dispatcher.h> +#include <pdx/service_dispatcher.h> #include "buffer_hub.h" @@ -16,7 +16,7 @@ int main(int, char**) { // We need to be able to create endpoints with full perms. umask(0000); - dispatcher = android::pdx::default_transport::ServiceDispatcher::Create(); + dispatcher = android::pdx::ServiceDispatcher::Create(); CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n"); service = android::dvr::BufferHubService::Create(); diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp index c31417bcc7..abe571ae9e 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.cpp +++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp @@ -161,6 +161,10 @@ void VrComposerClient::onHotplug(Display display, client_->onHotplug(display, connected); } +void VrComposerClient::onRefresh(Display display) { + client_->onRefresh(display); +} + Return<void> VrComposerClient::registerCallback( const sp<IComposerCallback>& callback) { return client_->registerCallback(callback); diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h index f492230215..dfc656a0f1 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.h +++ b/services/vr/hardware_composer/impl/vr_composer_client.h @@ -35,6 +35,7 @@ class VrComposerClient : public IVrComposerClient { virtual ~VrComposerClient(); void onHotplug(Display display, IComposerCallback::Connection connected); + void onRefresh(Display display); // IComposerClient Return<void> registerCallback(const sp<IComposerCallback>& callback) override; diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp index 861114dbca..fd271d0fe2 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.cpp +++ b/services/vr/hardware_composer/impl/vr_hwc.cpp @@ -133,13 +133,14 @@ void HwcDisplay::GetChangedCompositionTypes( return lhs.info.z_order < rhs.info.z_order; }); - int first_client_layer = -1, last_client_layer = -1; + const size_t no_layer = std::numeric_limits<size_t>::max(); + size_t first_client_layer = no_layer, last_client_layer = no_layer; for (size_t i = 0; i < layers_.size(); ++i) { switch (layers_[i].composition_type) { case IComposerClient::Composition::SOLID_COLOR: case IComposerClient::Composition::CURSOR: case IComposerClient::Composition::SIDEBAND: - if (first_client_layer < 0) + if (first_client_layer == no_layer) first_client_layer = i; last_client_layer = i; @@ -231,7 +232,7 @@ VrHwc::VrHwc() {} VrHwc::~VrHwc() {} -bool VrHwc::hasCapability(Capability capability) const { return false; } +bool VrHwc::hasCapability(Capability /* capability */) const { return false; } void VrHwc::removeClient() { std::lock_guard<std::mutex> guard(mutex_); @@ -305,13 +306,15 @@ Error VrHwc::getActiveConfig(Display display, Config* outConfig) { return Error::NONE; } -Error VrHwc::getClientTargetSupport(Display display, uint32_t width, - uint32_t height, PixelFormat format, - Dataspace dataspace) { +Error VrHwc::getClientTargetSupport(Display /* display */, uint32_t /* width */, + uint32_t /* height */, + PixelFormat /* format */, + Dataspace /* dataspace */) { return Error::NONE; } -Error VrHwc::getColorModes(Display display, hidl_vec<ColorMode>* outModes) { +Error VrHwc::getColorModes(Display /* display */, + hidl_vec<ColorMode>* outModes) { std::vector<ColorMode> color_modes(1, ColorMode::NATIVE); *outModes = hidl_vec<ColorMode>(color_modes); return Error::NONE; @@ -378,7 +381,7 @@ Error VrHwc::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) { return Error::NONE; } -Error VrHwc::getDisplayName(Display display, hidl_string* outName) { +Error VrHwc::getDisplayName(Display /* display */, hidl_string* outName) { *outName = hidl_string(); return Error::NONE; } @@ -408,7 +411,8 @@ Error VrHwc::getDozeSupport(Display display, bool* outSupport) { return Error::NONE; } -Error VrHwc::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, +Error VrHwc::getHdrCapabilities(Display /* display */, + hidl_vec<Hdr>* /* outTypes */, float* outMaxLuminance, float* outMaxAverageLuminance, float* outMinLuminance) { @@ -472,8 +476,8 @@ Error VrHwc::setColorTransform(Display display, const float* matrix, } Error VrHwc::setClientTarget(Display display, buffer_handle_t target, - int32_t acquireFence, int32_t dataspace, - const std::vector<hwc_rect_t>& damage) { + int32_t acquireFence, int32_t /* dataspace */, + const std::vector<hwc_rect_t>& /* damage */) { base::unique_fd fence(acquireFence); std::lock_guard<std::mutex> guard(mutex_); auto display_ptr = FindDisplay(display); @@ -489,7 +493,7 @@ Error VrHwc::setClientTarget(Display display, buffer_handle_t target, return Error::NONE; } -Error VrHwc::setOutputBuffer(Display display, buffer_handle_t buffer, +Error VrHwc::setOutputBuffer(Display display, buffer_handle_t /* buffer */, int32_t releaseFence) { base::unique_fd fence(releaseFence); std::lock_guard<std::mutex> guard(mutex_); @@ -504,8 +508,9 @@ Error VrHwc::setOutputBuffer(Display display, buffer_handle_t buffer, Error VrHwc::validateDisplay( Display display, std::vector<Layer>* outChangedLayers, std::vector<IComposerClient::Composition>* outCompositionTypes, - uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers, - std::vector<uint32_t>* outRequestMasks) { + uint32_t* /* outDisplayRequestMask */, + std::vector<Layer>* /* outRequestedLayers */, + std::vector<uint32_t>* /* outRequestMasks */) { std::lock_guard<std::mutex> guard(mutex_); auto display_ptr = FindDisplay(display); if (!display_ptr) @@ -516,7 +521,7 @@ Error VrHwc::validateDisplay( return Error::NONE; } -Error VrHwc::acceptDisplayChanges(Display display) { return Error::NONE; } +Error VrHwc::acceptDisplayChanges(Display /* display */) { return Error::NONE; } Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers, @@ -708,8 +713,8 @@ Error VrHwc::setLayerPlaneAlpha(Display display, Layer layer, float alpha) { return Error::NONE; } -Error VrHwc::setLayerSidebandStream(Display display, Layer layer, - buffer_handle_t stream) { +Error VrHwc::setLayerSidebandStream(Display display, Layer /* layer */, + buffer_handle_t /* stream */) { std::lock_guard<std::mutex> guard(mutex_); if (!FindDisplay(display)) return Error::BAD_DISPLAY; @@ -850,6 +855,14 @@ Return<void> VrHwc::createClient(createClient_cb hidl_cb) { return Void(); } +void VrHwc::ForceDisplaysRefresh() { + std::lock_guard<std::mutex> guard(mutex_); + if (client_ != nullptr) { + for (const auto& pair : displays_) + client_.promote()->onRefresh(pair.first); + } +} + void VrHwc::RegisterObserver(Observer* observer) { std::lock_guard<std::mutex> guard(mutex_); if (observer_) diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h index 523cda3f69..fce9a063e0 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.h +++ b/services/vr/hardware_composer/impl/vr_hwc.h @@ -103,6 +103,7 @@ class ComposerView { virtual ~ComposerView() {} + virtual void ForceDisplaysRefresh() = 0; virtual void RegisterObserver(Observer* observer) = 0; virtual void UnregisterObserver(Observer* observer) = 0; }; @@ -288,6 +289,7 @@ class VrHwc : public IComposer, public ComposerBase, public ComposerView { Return<void> createClient(createClient_cb hidl_cb) override; // ComposerView: + void ForceDisplaysRefresh() override; void RegisterObserver(Observer* observer) override; void UnregisterObserver(Observer* observer) override; @@ -295,7 +297,6 @@ class VrHwc : public IComposer, public ComposerBase, public ComposerView { HwcDisplay* FindDisplay(Display display); wp<VrComposerClient> client_; - sp<IComposerCallback> callbacks_; // Guard access to internal state from binder threads. std::mutex mutex_; diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp index d082f4bc92..2e70928662 100644 --- a/services/vr/hardware_composer/tests/vr_composer_test.cpp +++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp @@ -10,6 +10,24 @@ namespace { const char kVrDisplayName[] = "VrDisplay_Test"; +class TestComposerView : public ComposerView { + public: + TestComposerView() {} + ~TestComposerView() override = default; + + size_t display_refresh_count() const { return display_refresh_count_; } + + void ForceDisplaysRefresh() override { display_refresh_count_++; } + void RegisterObserver(Observer* observer) override {} + void UnregisterObserver(Observer* observer) override {} + + TestComposerView(const TestComposerView&) = delete; + void operator=(const TestComposerView&) = delete; + + private: + size_t display_refresh_count_ = 0; +}; + class TestComposerCallback : public BnVrComposerCallback { public: TestComposerCallback() {} @@ -57,7 +75,7 @@ sp<GraphicBuffer> CreateBuffer() { class VrComposerTest : public testing::Test { public: - VrComposerTest() : composer_(new VrComposer()) {} + VrComposerTest() : composer_(new VrComposer(&composer_view_)) {} ~VrComposerTest() override = default; sp<IVrComposer> GetComposerProxy() const { @@ -72,6 +90,7 @@ class VrComposerTest : public testing::Test { } protected: + TestComposerView composer_view_; sp<VrComposer> composer_; VrComposerTest(const VrComposerTest&) = delete; @@ -89,7 +108,9 @@ TEST_F(VrComposerTest, TestWithoutObserver) { TEST_F(VrComposerTest, TestWithObserver) { sp<IVrComposer> composer = GetComposerProxy(); sp<TestComposerCallback> callback = new TestComposerCallback(); + ASSERT_EQ(0, composer_view_.display_refresh_count()); ASSERT_TRUE(composer->registerObserver(callback).isOk()); + ASSERT_EQ(1, composer_view_.display_refresh_count()); ComposerView::Frame frame; base::unique_fd fence = composer_->OnNewFrame(frame); diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp index 36a313ae24..d93f370945 100644 --- a/services/vr/hardware_composer/vr_composer.cpp +++ b/services/vr/hardware_composer/vr_composer.cpp @@ -21,24 +21,36 @@ bool CheckPermission() { } // namespace -VrComposer::VrComposer() {} +VrComposer::VrComposer(ComposerView* composer_view) + : composer_view_(composer_view) { + composer_view_->RegisterObserver(this); +} -VrComposer::~VrComposer() {} +VrComposer::~VrComposer() { + composer_view_->UnregisterObserver(this); +} binder::Status VrComposer::registerObserver( const sp<IVrComposerCallback>& callback) { - std::lock_guard<std::mutex> guard(mutex_); + { + std::lock_guard<std::mutex> guard(mutex_); + + if (!CheckPermission()) + return binder::Status::fromStatusT(PERMISSION_DENIED); - if (!CheckPermission()) - return binder::Status::fromStatusT(PERMISSION_DENIED); + if (callback_.get()) { + ALOGE("Failed to register callback, already registered"); + return binder::Status::fromStatusT(ALREADY_EXISTS); + } - if (callback_.get()) { - ALOGE("Failed to register callback, already registered"); - return binder::Status::fromStatusT(ALREADY_EXISTS); + callback_ = callback; + IInterface::asBinder(callback_)->linkToDeath(this); } - callback_ = callback; - IInterface::asBinder(callback_)->linkToDeath(this); + // Don't take the lock to force display refresh otherwise it could end in a + // deadlock since HWC calls this with new frames and it has a lock of its own + // to serialize access to the display information. + composer_view_->ForceDisplaysRefresh(); return binder::Status::ok(); } diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h index 7b580c6cba..1273352ad0 100644 --- a/services/vr/hardware_composer/vr_composer.h +++ b/services/vr/hardware_composer/vr_composer.h @@ -20,7 +20,7 @@ class VrComposer public ComposerView::Observer, public IBinder::DeathRecipient { public: - VrComposer(); + explicit VrComposer(ComposerView* composer_view); ~VrComposer() override; // BnVrComposer: @@ -40,6 +40,8 @@ class VrComposer sp<IVrComposerCallback> callback_; + ComposerView* composer_view_; // Not owned. + VrComposer(const VrComposer&) = delete; void operator=(const VrComposer&) = delete; }; diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp index e36b0ae3f1..7701847120 100644 --- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp +++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp @@ -36,8 +36,7 @@ int main() { "Failed to register service"); android::sp<android::dvr::VrComposer> composer = - new android::dvr::VrComposer(); - service->RegisterObserver(composer.get()); + new android::dvr::VrComposer(service.get()); android::sp<android::IServiceManager> sm(android::defaultServiceManager()); @@ -52,7 +51,5 @@ int main() { android::hardware::ProcessState::self()->startThreadPool(); android::hardware::IPCThreadState::self()->joinThreadPool(); - service->UnregisterObserver(composer.get()); - return 0; } diff --git a/services/vr/performanced/main.cpp b/services/vr/performanced/main.cpp index ca66c710d7..d7dc8f6afe 100644 --- a/services/vr/performanced/main.cpp +++ b/services/vr/performanced/main.cpp @@ -9,7 +9,7 @@ #include <sys/resource.h> #include <utils/threads.h> -#include <pdx/default_transport/service_dispatcher.h> +#include <pdx/service_dispatcher.h> #include <private/android_filesystem_config.h> #include "performance_service.h" @@ -58,7 +58,7 @@ int main(int /*argc*/, char** /*argv*/) { CHECK_ERROR(ret < 0, error, "Could not set capabilities: %s", strerror(errno)); - dispatcher = android::pdx::default_transport::ServiceDispatcher::Create(); + dispatcher = android::pdx::ServiceDispatcher::Create(); CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher."); service = android::dvr::PerformanceService::Create(); diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp index 4b9fbe047d..4c26671b11 100644 --- a/services/vr/performanced/performance_service.cpp +++ b/services/vr/performanced/performance_service.cpp @@ -22,13 +22,15 @@ using android::dvr::Task; using android::pdx::ErrorStatus; using android::pdx::Message; using android::pdx::Status; -using android::pdx::rpc::DispatchRemoteMethod; using android::pdx::default_transport::Endpoint; +using android::pdx::rpc::DispatchRemoteMethod; namespace { const char kCpuSetBasePath[] = "/dev/cpuset"; +const char kRootCpuSet[] = "/"; + constexpr unsigned long kTimerSlackForegroundNs = 50000; constexpr unsigned long kTimerSlackBackgroundNs = 40000000; @@ -123,22 +125,22 @@ PerformanceService::PerformanceService() // hack for now to put some form of permission logic in place while a longer // term solution is developed. using AllowRootSystem = - CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>, - GroupId<AID_SYSTEM>>>; + CheckAnd<SameProcess, + CheckOr<UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>>; using AllowRootSystemGraphics = CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>, GroupId<AID_SYSTEM, AID_GRAPHICS>>>; using AllowRootSystemAudio = CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>, GroupId<AID_SYSTEM, AID_AUDIO>>>; - using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, - GroupId<AID_SYSTEM>>; + using AllowRootSystemTrusted = + CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>; partition_permission_check_ = AllowRootSystemTrusted::Check; // Setup the scheduler classes. // TODO(eieio): Replace this with a device-specific config file. - scheduler_classes_ = { + scheduler_policies_ = { {"audio:low", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, @@ -183,12 +185,14 @@ PerformanceService::PerformanceService() {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, .priority = fifo_medium + 2, - .permission_check = AllowRootSystemTrusted::Check}}, + .permission_check = AllowRootSystemTrusted::Check, + "/system/performance"}}, {"vr:app:render", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, .priority = fifo_medium + 1, - .permission_check = AllowRootSystemTrusted::Check}}, + .permission_check = AllowRootSystemTrusted::Check, + "/application/performance"}}, {"normal", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_NORMAL, @@ -219,14 +223,80 @@ std::string PerformanceService::DumpState(size_t /*max_length*/) { Status<void> PerformanceService::OnSetSchedulerPolicy( Message& message, pid_t task_id, const std::string& scheduler_policy) { - // Forward to scheduler class handler for now. In the future this method will - // subsume the others by unifying both scheduler class and cpu partiton into a - // single policy concept. ALOGI( "PerformanceService::OnSetSchedulerPolicy: task_id=%d " "scheduler_policy=%s", task_id, scheduler_policy.c_str()); - return OnSetSchedulerClass(message, task_id, scheduler_policy); + + Task task(task_id); + if (!task) { + ALOGE( + "PerformanceService::OnSetSchedulerPolicy: Unable to access /proc/%d " + "to gather task information.", + task_id); + return ErrorStatus(EINVAL); + } + + auto search = scheduler_policies_.find(scheduler_policy); + if (search != scheduler_policies_.end()) { + auto config = search->second; + + // Make sure the sending process is allowed to make the requested change to + // this task. + if (!config.IsAllowed(message, task)) + return ErrorStatus(EINVAL); + + // Get the thread group's cpu set. Policies that do not specify a cpuset + // should default to this cpuset. + std::string thread_group_cpuset; + Task thread_group{task.thread_group_id()}; + if (thread_group) { + thread_group_cpuset = thread_group.GetCpuSetPath(); + } else { + ALOGE( + "PerformanceService::OnSetSchedulerPolicy: Failed to get thread " + "group tgid=%d for task_id=%d", + task.thread_group_id(), task_id); + thread_group_cpuset = kRootCpuSet; + } + + std::string target_cpuset; + if (config.cpuset.empty()) { + target_cpuset = thread_group_cpuset; + } else { + target_cpuset = config.cpuset; + } + ALOGI("PerformanceService::OnSetSchedulerPolicy: Using cpuset=%s", + target_cpuset.c_str()); + + auto target_set = cpuset_.Lookup(target_cpuset); + if (target_set) { + auto attach_status = target_set->AttachTask(task_id); + ALOGW_IF(!attach_status, + "PerformanceService::OnSetSchedulerPolicy: Failed to attach " + "task=%d to cpuset=%s: %s", + task_id, target_cpuset.c_str(), + attach_status.GetErrorMessage().c_str()); + } else { + ALOGW( + "PerformanceService::OnSetSchedulerPolicy: Failed to lookup " + "cpuset=%s", + target_cpuset.c_str()); + } + + struct sched_param param; + param.sched_priority = config.priority; + + sched_setscheduler(task_id, config.scheduler_policy, ¶m); + prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id); + return {}; + } else { + ALOGE( + "PerformanceService::OnSetSchedulerPolicy: Invalid scheduler_policy=%s " + "requested by task=%d.", + scheduler_policy.c_str(), task_id); + return ErrorStatus(EINVAL); + } } Status<void> PerformanceService::OnSetCpuPartition( @@ -259,8 +329,8 @@ Status<void> PerformanceService::OnSetSchedulerClass( if (!task) return ErrorStatus(EINVAL); - auto search = scheduler_classes_.find(scheduler_class); - if (search != scheduler_classes_.end()) { + auto search = scheduler_policies_.find(scheduler_class); + if (search != scheduler_policies_.end()) { auto config = search->second; // Make sure the sending process is allowed to make the requested change to diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h index b28d94addb..6b519abac3 100644 --- a/services/vr/performanced/performance_service.h +++ b/services/vr/performanced/performance_service.h @@ -44,13 +44,13 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { int sched_fifo_min_priority_; int sched_fifo_max_priority_; - // Scheduler class config type. - struct SchedulerClassConfig { + struct SchedulerPolicyConfig { unsigned long timer_slack; int scheduler_policy; int priority; std::function<bool(const pdx::Message& message, const Task& task)> permission_check; + std::string cpuset; // Check the permisison of the given task to use this scheduler class. If a // permission check function is not set then operations are only allowed on @@ -65,7 +65,7 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { } }; - std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_; + std::unordered_map<std::string, SchedulerPolicyConfig> scheduler_policies_; std::function<bool(const pdx::Message& message, const Task& task)> partition_permission_check_; diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp index 274a1b36d4..4065785426 100644 --- a/services/vr/performanced/performance_service_tests.cpp +++ b/services/vr/performanced/performance_service_tests.cpp @@ -1,24 +1,65 @@ #include <errno.h> #include <sched.h> +#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <condition_variable> #include <cstdlib> +#include <iostream> #include <mutex> +#include <sstream> #include <thread> +#include <utility> +#include <android-base/unique_fd.h> #include <dvr/performance_client_api.h> #include <gtest/gtest.h> #include <private/android_filesystem_config.h> +#include "stdio_filebuf.h" +#include "string_trim.h" +#include "unique_file.h" + +using android::dvr::Trim; +using android::dvr::UniqueFile; +using android::dvr::stdio_filebuf; + namespace { const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID"; +const char kProcBase[] = "/proc"; + +std::pair<UniqueFile, int> OpenTaskFile(pid_t task_id, + const std::string& name) { + std::ostringstream stream; + stream << kProcBase << "/" << task_id << "/" << name; + + UniqueFile file{fopen(stream.str().c_str(), "r")}; + const int error = file ? 0 : errno; + return {std::move(file), error}; +} + +std::string GetTaskCpuSet(pid_t task_id) { + int error; + UniqueFile file; + + std::tie(file, error) = OpenTaskFile(task_id, "cpuset"); + if (!file) + return std::string("errno:") + strerror(error); + + stdio_filebuf<char> filebuf(file.get()); + std::istream file_stream(&filebuf); + + std::string line; + std::getline(file_stream, line); + return Trim(line); +} + } // anonymous namespace -TEST(DISABLED_PerformanceTest, SetCpuPartition) { +TEST(PerformanceTest, SetCpuPartition) { int error; // Test setting the the partition for the current task. @@ -59,13 +100,6 @@ TEST(DISABLED_PerformanceTest, SetCpuPartition) { } thread.join(); - // Test setting the partition for a task that isn't valid using - // the task id of the thread that we just joined. Technically the - // id could wrap around by the time we get here, but this is - // extremely unlikely. - error = dvrSetCpuPartition(task_id, "/application"); - EXPECT_EQ(-EINVAL, error); - // Test setting the partition for a task that doesn't belong to us. error = dvrSetCpuPartition(1, "/application"); EXPECT_EQ(-EINVAL, error); @@ -73,6 +107,10 @@ TEST(DISABLED_PerformanceTest, SetCpuPartition) { // Test setting the partition to one that doesn't exist. error = dvrSetCpuPartition(0, "/foobar"); EXPECT_EQ(-ENOENT, error); + + // Set the test back to the root partition. + error = dvrSetCpuPartition(0, "/"); + EXPECT_EQ(0, error); } TEST(PerformanceTest, SetSchedulerClass) { @@ -96,8 +134,6 @@ TEST(PerformanceTest, SetSchedulerClass) { EXPECT_EQ(-EINVAL, error); } -// This API mirrors SetSchedulerClass for now. Replace with with a more specific -// test once the policy API is fully implemented. TEST(PerformanceTest, SetSchedulerPolicy) { int error; @@ -115,6 +151,50 @@ TEST(PerformanceTest, SetSchedulerPolicy) { error = dvrSetSchedulerPolicy(0, "foobar"); EXPECT_EQ(-EINVAL, error); + + // Set the test back to the root partition. + error = dvrSetCpuPartition(0, "/"); + EXPECT_EQ(0, error); + + const std::string original_cpuset = GetTaskCpuSet(gettid()); + EXPECT_EQ("/", original_cpuset); + + error = dvrSetSchedulerPolicy(0, "vr:system:arp"); + EXPECT_EQ(0, error); + EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0)); + + const std::string new_cpuset = GetTaskCpuSet(gettid()); + EXPECT_NE(original_cpuset, new_cpuset); + + // The cpuset for the thread group is now new_cpuset. Scheduler profiles that + // do not specify a cpuset should not change the cpuset of a thread, except to + // restore it to the thread group cpuset. + std::string thread_original_cpuset; + std::string thread_new_cpuset; + std::string thread_final_cpuset; + + std::thread thread{ + [&thread_original_cpuset, &thread_new_cpuset, &thread_final_cpuset]() { + thread_original_cpuset = GetTaskCpuSet(gettid()); + + int error = dvrSetSchedulerPolicy(0, "vr:app:render"); + EXPECT_EQ(0, error); + + thread_new_cpuset = GetTaskCpuSet(gettid()); + + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + + thread_final_cpuset = GetTaskCpuSet(gettid()); + }}; + thread.join(); + + EXPECT_EQ(new_cpuset, thread_original_cpuset); + EXPECT_NE(new_cpuset, thread_new_cpuset); + EXPECT_EQ(new_cpuset, thread_final_cpuset); + + error = dvrSetCpuPartition(0, original_cpuset.c_str()); + EXPECT_EQ(0, error); } TEST(PerformanceTest, SchedulerClassResetOnFork) { @@ -424,11 +504,11 @@ TEST(PerformanceTest, Permissions) { error = dvrSetSchedulerPolicy(0, "audio:high"); EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "graphics"); - EXPECT_EQ(0, error); + EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "graphics:low"); - EXPECT_EQ(0, error); + EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "graphics:high"); - EXPECT_EQ(0, error); + EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "sensors"); EXPECT_EQ(-EINVAL, error); error = dvrSetSchedulerPolicy(0, "sensors:low"); diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp index 1175a7b12b..c2f078efb4 100644 --- a/services/vr/performanced/task.cpp +++ b/services/vr/performanced/task.cpp @@ -48,15 +48,18 @@ Task::Task(pid_t task_id) thread_count_(0), cpus_allowed_mask_(0) { task_fd_ = OpenTaskDirectory(task_id_); - ALOGE_IF(task_fd_.get() < 0, + const int error = errno; + ALOGE_IF(task_fd_.get() < 0 && error != EACCES, "Task::Task: Failed to open task directory for task_id=%d: %s", - task_id, strerror(errno)); - - ReadStatusFields(); - - ALOGD_IF(TRACE, "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x", - task_id_, name_.c_str(), thread_group_id_, parent_process_id_, - cpus_allowed_mask_); + task_id, strerror(error)); + + if (IsValid()) { + ReadStatusFields(); + ALOGD_IF(TRACE, + "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x", + task_id_, name_.c_str(), thread_group_id_, parent_process_id_, + cpus_allowed_mask_); + } } base::unique_fd Task::OpenTaskFile(const std::string& name) const { diff --git a/vulkan/Android.bp b/vulkan/Android.bp index 91c270e02b..26d3c6a269 100644 --- a/vulkan/Android.bp +++ b/vulkan/Android.bp @@ -25,8 +25,16 @@ ndk_headers { cc_library_headers { name: "vulkan_headers", - export_include_dirs: ["include"], vendor_available: true, + header_libs: [ + "libcutils_headers", + "libhardware_headers", + ], + export_header_lib_headers: [ + "libcutils_headers", + "libhardware_headers", + ], + export_include_dirs: ["include"], } subdirs = [ diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp index 67147791f3..a3da651142 100644 --- a/vulkan/nulldrv/null_driver.cpp +++ b/vulkan/nulldrv/null_driver.cpp @@ -19,12 +19,12 @@ #include <inttypes.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <algorithm> #include <array> #include <log/log.h> -#include <utils/Errors.h> #include "null_driver_gen.h" |