diff options
127 files changed, 2592 insertions, 736 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 3ec016385b..cb6d0c6e37 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -82,6 +82,28 @@ on post-fs chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/enable chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/enable + # disk + chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter/enable + chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable + chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit/enable + chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable + chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_begin/enable + chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable + chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_end/enable + chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable + chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_begin/enable + chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable + chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_end/enable + chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable + chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter/enable + chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable + chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit/enable + chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable + chmod 0666 /sys/kernel/tracing/events/block/block_rq_issue/enable + chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable + chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable + chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable + # Tracing disabled by default write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0 diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc index 9d632ccbad..93a29bab73 100644 --- a/cmds/atrace/atrace_userdebug.rc +++ b/cmds/atrace/atrace_userdebug.rc @@ -19,25 +19,3 @@ on post-fs chmod 0666 /sys/kernel/debug/tracing/events/irq/enable chmod 0666 /sys/kernel/tracing/events/ipi/enable chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable - - # disk - chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter/enable - chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable - chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit/enable - chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable - chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_begin/enable - chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable - chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_end/enable - chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable - chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_begin/enable - chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable - chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_end/enable - chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable - chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter/enable - chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable - chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit/enable - chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable - chmod 0666 /sys/kernel/tracing/events/block/block_rq_issue/enable - chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable - chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable - chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 9648edefe9..9d0c30b8b5 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -32,14 +32,20 @@ #include <sys/time.h> #include <sys/wait.h> #include <unistd.h> + +#include <chrono> +#include <functional> +#include <future> #include <memory> #include <regex> #include <set> #include <string> +#include <utility> #include <vector> #include <android-base/file.h> #include <android-base/properties.h> +#include <android-base/scopeguard.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> @@ -53,6 +59,7 @@ #include <private/android_filesystem_config.h> #include <private/android_logger.h> #include <serviceutils/PriorityDumper.h> +#include <utils/StrongPointer.h> #include "DumpstateInternal.h" #include "DumpstateSectionReporter.h" #include "DumpstateService.h" @@ -1533,77 +1540,101 @@ void Dumpstate::DumpstateBoard() { printf("== Board\n"); printf("========================================================\n"); - ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService()); - if (dumpstate_device == nullptr) { - MYLOGE("No IDumpstateDevice implementation\n"); - return; - } - if (!IsZipping()) { MYLOGD("Not dumping board info because it's not a zipped bugreport\n"); return; } - std::string path[NUM_OF_DUMPS]; - android::base::unique_fd fd[NUM_OF_DUMPS]; - int numFds = 0; - + std::vector<std::string> paths; + std::vector<android::base::ScopeGuard<std::function<void()>>> remover; for (int i = 0; i < NUM_OF_DUMPS; i++) { - path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i]; - MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str()); - - fd[i] = android::base::unique_fd( - TEMP_FAILURE_RETRY(open(path[i].c_str(), - O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))); - if (fd[i] < 0) { - MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno)); - return; - } else { - numFds++; - } - } + paths.emplace_back(kDumpstateBoardPath + kDumpstateBoardFiles[i]); + remover.emplace_back(android::base::make_scope_guard(std::bind( + [](std::string path) { + if (remove(path.c_str()) != 0 && errno != ENOENT) { + MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno)); + } + }, + paths[i]))); + } + + // Given that bugreport is required to diagnose failures, it's better to + // drop the result of IDumpstateDevice than to block the rest of bugreport + // for an arbitrary amount of time. + std::packaged_task<std::unique_ptr<ssize_t[]>()> + dumpstate_task([paths]() -> std::unique_ptr<ssize_t[]> { + ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService()); + if (dumpstate_device == nullptr) { + MYLOGE("No IDumpstateDevice implementation\n"); + return nullptr; + } - native_handle_t *handle = native_handle_create(numFds, 0); - if (handle == nullptr) { - MYLOGE("Could not create native_handle\n"); - return; - } + using ScopedNativeHandle = + std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>; + ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0), + [](native_handle_t* handle) { + native_handle_close(handle); + native_handle_delete(handle); + }); + if (handle == nullptr) { + MYLOGE("Could not create native_handle\n"); + return nullptr; + } - for (int i = 0; i < numFds; i++) { - handle->data[i] = fd[i].release(); - } + for (size_t i = 0; i < paths.size(); i++) { + MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str()); + + android::base::unique_fd fd(TEMP_FAILURE_RETRY( + open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))); + if (fd < 0) { + MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno)); + return nullptr; + } + handle.get()->data[i] = fd.release(); + } - // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call. - android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle); - if (!status.isOk()) { - MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str()); - native_handle_close(handle); - native_handle_delete(handle); + android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get()); + if (!status.isOk()) { + MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str()); + return nullptr; + } + auto file_sizes = std::make_unique<ssize_t[]>(paths.size()); + for (size_t i = 0; i < paths.size(); i++) { + struct stat s; + if (fstat(handle.get()->data[i], &s) == -1) { + MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(), + strerror(errno)); + file_sizes[i] = -1; + continue; + } + file_sizes[i] = s.st_size; + } + return file_sizes; + }); + auto result = dumpstate_task.get_future(); + std::thread(std::move(dumpstate_task)).detach(); + if (result.wait_for(30s) != std::future_status::ready) { + MYLOGE("dumpstateBoard timed out after 30s\n"); + return; + } + std::unique_ptr<ssize_t[]> file_sizes = result.get(); + if (file_sizes == nullptr) { return; } - for (int i = 0; i < numFds; i++) { - struct stat s; - if (fstat(handle->data[i], &s) == -1) { - MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno); - } else if (s.st_size > 0) { - AddZipEntry(kDumpstateBoardFiles[i], path[i]); - } else { + for (size_t i = 0; i < paths.size(); i++) { + if (file_sizes[i] == -1) { + continue; + } + if (file_sizes[i] == 0) { MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str()); + continue; } + AddZipEntry(kDumpstateBoardFiles[i], paths[i]); } printf("*** See dumpstate-board.txt entry ***\n"); - - native_handle_close(handle); - native_handle_delete(handle); - - for (int i = 0; i < numFds; i++) { - if (remove(path[i].c_str()) != 0) { - MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno)); - } - } } static void ShowUsageAndExit(int exitCode = 1) { diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index e53a2230eb..833ffbfc5c 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -22,6 +22,7 @@ #include <errno.h> #include <fstream> #include <fts.h> +#include <functional> #include <inttypes.h> #include <regex> #include <stdlib.h> @@ -2412,27 +2413,25 @@ binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath, // This kernel feature is experimental. // TODO: remove local definition once upstreamed -#ifndef FS_IOC_SET_FSVERITY -struct fsverity_set { - __u64 offset; - __u64 flags; -}; +#ifndef FS_IOC_ENABLE_VERITY -struct fsverity_root_hash { - short root_hash_algorithm; - short flags; - __u8 reserved[4]; - __u8 root_hash[64]; -}; +#define FS_IOC_ENABLE_VERITY _IO('f', 133) +#define FS_IOC_SET_VERITY_MEASUREMENT _IOW('f', 134, struct fsverity_measurement) -#define FS_IOC_MEASURE_FSVERITY _IOW('f', 133, struct fsverity_root_hash) -#define FS_IOC_SET_FSVERITY _IOW('f', 134, struct fsverity_set) +#define FS_VERITY_ALG_SHA256 1 + +struct fsverity_measurement { + __u16 digest_algorithm; + __u16 digest_size; + __u32 reserved1; + __u64 reserved2[3]; + __u8 digest[]; +}; -#define FSVERITY_FLAG_ENABLED 0x0001 #endif binder::Status InstalldNativeService::installApkVerity(const std::string& filePath, - const ::android::base::unique_fd& verityInputAshmem) { + const ::android::base::unique_fd& verityInputAshmem, int32_t contentSize) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PATH(filePath); std::lock_guard<std::recursive_mutex> lock(mLock); @@ -2440,7 +2439,7 @@ binder::Status InstalldNativeService::installApkVerity(const std::string& filePa if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) { return ok(); } -#if DEBUG +#ifndef NDEBUG ASSERT_PAGE_SIZE_4K(); #endif // TODO: also check fsverity support in the current file system if compiled with DEBUG. @@ -2449,15 +2448,14 @@ binder::Status InstalldNativeService::installApkVerity(const std::string& filePa return error("FD is not an ashmem"); } - // TODO(71871109): Validate filePath. // 1. Seek to the next page boundary beyond the end of the file. ::android::base::unique_fd wfd(open(filePath.c_str(), O_WRONLY)); if (wfd.get() < 0) { - return error("Failed to open " + filePath + ": " + strerror(errno)); + return error("Failed to open " + filePath); } struct stat st; if (fstat(wfd.get(), &st) < 0) { - return error("Failed to stat " + filePath + ": " + strerror(errno)); + return error("Failed to stat " + filePath); } // fsverity starts from the block boundary. off_t padding = kVerityPageSize - st.st_size % kVerityPageSize; @@ -2465,38 +2463,51 @@ binder::Status InstalldNativeService::installApkVerity(const std::string& filePa padding = 0; } if (lseek(wfd.get(), st.st_size + padding, SEEK_SET) < 0) { - return error("Failed to lseek " + filePath + ": " + strerror(errno)); + return error("Failed to lseek " + filePath); } - // 2. Write everything in the ashmem to the file. - int size = ashmem_get_size_region(verityInputAshmem.get()); - if (size < 0) { - return error("Failed to get ashmem size: " + std::to_string(size)); + // 2. Write everything in the ashmem to the file. Note that allocated + // ashmem size is multiple of page size, which is different from the + // actual content size. + int shmSize = ashmem_get_size_region(verityInputAshmem.get()); + if (shmSize < 0) { + return error("Failed to get ashmem size: " + std::to_string(shmSize)); } - void* data = mmap(NULL, size, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0); - if (data == MAP_FAILED) { - return error("Failed to mmap the ashmem: " + std::string(strerror(errno))); + if (contentSize < 0) { + return error("Invalid content size: " + std::to_string(contentSize)); } - char* cursor = reinterpret_cast<char*>(data); - int remaining = size; + if (contentSize > shmSize) { + return error("Content size overflow: " + std::to_string(contentSize) + " > " + + std::to_string(shmSize)); + } + auto data = std::unique_ptr<void, std::function<void (void *)>>( + mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0), + [contentSize] (void* ptr) { + if (ptr != MAP_FAILED) { + munmap(ptr, contentSize); + } + }); + + if (data.get() == MAP_FAILED) { + return error("Failed to mmap the ashmem"); + } + char* cursor = reinterpret_cast<char*>(data.get()); + int remaining = contentSize; while (remaining > 0) { int ret = TEMP_FAILURE_RETRY(write(wfd.get(), cursor, remaining)); if (ret < 0) { - munmap(data, size); return error("Failed to write to " + filePath + " (" + std::to_string(remaining) + - + "/" + std::to_string(size) + "): " + strerror(errno)); + + "/" + std::to_string(contentSize) + ")"); } cursor += ret; remaining -= ret; } - munmap(data, size); + wfd.reset(); - // 3. Enable fsverity. Once it's done, the file becomes immutable. - struct fsverity_set config; - config.offset = st.st_size; - config.flags = FSVERITY_FLAG_ENABLED; - if (ioctl(wfd.get(), FS_IOC_SET_FSVERITY, &config) < 0) { - return error("Failed to enable fsverity on " + filePath + ": " + strerror(errno)); + // 3. Enable fsverity (needs readonly fd. Once it's done, the file becomes immutable. + ::android::base::unique_fd rfd(open(filePath.c_str(), O_RDONLY)); + if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) { + return error("Failed to enable fsverity on " + filePath); } return ok(); } @@ -2516,17 +2527,19 @@ binder::Status InstalldNativeService::assertFsverityRootHashMatches(const std::s std::to_string(expectedHash.size())); } - // TODO(71871109): Validate filePath. ::android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY)); if (fd.get() < 0) { return error("Failed to open " + filePath + ": " + strerror(errno)); } - struct fsverity_root_hash config; - memset(&config, 0, sizeof(config)); - config.root_hash_algorithm = 0; // SHA256 - memcpy(config.root_hash, expectedHash.data(), std::min(sizeof(config.root_hash), kSha256Size)); - if (ioctl(fd.get(), FS_IOC_MEASURE_FSVERITY, &config) < 0) { + unsigned int buffer_size = sizeof(fsverity_measurement) + kSha256Size; + std::vector<char> buffer(buffer_size, 0); + + fsverity_measurement* config = reinterpret_cast<fsverity_measurement*>(buffer.data()); + config->digest_algorithm = FS_VERITY_ALG_SHA256; + config->digest_size = kSha256Size; + memcpy(config->digest, expectedHash.data(), kSha256Size); + if (ioctl(fd.get(), FS_IOC_SET_VERITY_MEASUREMENT, config) < 0) { // This includes an expected failure case with no FSVerity setup. It normally happens when // the apk does not contains the Merkle tree root hash. return error("Failed to measure fsverity on " + filePath + ": " + strerror(errno)); diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 2a3196761f..cebd3f90d3 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -123,7 +123,7 @@ public: binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet, const std::unique_ptr<std::string>& outputPath); binder::Status installApkVerity(const std::string& filePath, - const ::android::base::unique_fd& verityInput); + const ::android::base::unique_fd& verityInput, int32_t contentSize); binder::Status assertFsverityRootHashMatches(const std::string& filePath, const std::vector<uint8_t>& expectedHash); binder::Status reconcileSecondaryDexFile(const std::string& dexPath, diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 0c364bd905..91e20b75ae 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -85,7 +85,8 @@ interface IInstalld { @utf8InCpp String outputPath); void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath); - void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput); + void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput, + int contentSize); void assertFsverityRootHashMatches(@utf8InCpp String filePath, in byte[] expectedHash); boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName, diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index e1e73c7a61..27776629de 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -1264,8 +1264,8 @@ 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) { +Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, + bool generate_app_image, bool is_public, int uid, bool is_secondary_dex) { // We don't create an image for secondary dex files. if (is_secondary_dex) { @@ -1278,11 +1278,11 @@ Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_g 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()); + // In case there is a stale image, remove it now. Ignore any error. + unlink(image_path.c_str()); + + // Not enabled, exit. + if (!generate_app_image) { return Dex2oatFileWrapper(); } char app_image_format[kPropertyValueMax]; @@ -1959,6 +1959,7 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins bool background_job_compile = (dexopt_flags & DEXOPT_IDLE_BACKGROUND_JOB) != 0; bool enable_hidden_api_checks = (dexopt_flags & DEXOPT_ENABLE_HIDDEN_API_CHECKS) != 0; bool generate_compact_dex = (dexopt_flags & DEXOPT_GENERATE_COMPACT_DEX) != 0; + bool generate_app_image = (dexopt_flags & DEXOPT_GENERATE_APP_IMAGE) != 0; // Check if we're dealing with a secondary dex file and if we need to compile it. std::string oat_dir_str; @@ -2027,8 +2028,8 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path); // Create the app image file if needed. - Dex2oatFileWrapper image_fd = - maybe_open_app_image(out_oat_path, profile_guided, is_public, uid, is_secondary_dex); + Dex2oatFileWrapper image_fd = maybe_open_app_image( + out_oat_path, generate_app_image, is_public, uid, is_secondary_dex); // Open the reference profile if needed. Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile( diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h index 26aa443d4e..c928631d8f 100644 --- a/cmds/installd/installd_constants.h +++ b/cmds/installd/installd_constants.h @@ -54,6 +54,7 @@ constexpr int DEXOPT_STORAGE_DE = 1 << 8; constexpr int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; constexpr int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10; constexpr int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11; +constexpr int DEXOPT_GENERATE_APP_IMAGE = 1 << 12; /* all known values for dexopt flags */ constexpr int DEXOPT_MASK = @@ -67,7 +68,8 @@ constexpr int DEXOPT_MASK = | DEXOPT_STORAGE_DE | DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_ENABLE_HIDDEN_API_CHECKS - | DEXOPT_GENERATE_COMPACT_DEX; + | DEXOPT_GENERATE_COMPACT_DEX + | DEXOPT_GENERATE_APP_IMAGE; // NOTE: keep in sync with StorageManager constexpr int FLAG_STORAGE_DE = 1 << 0; diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 58355f9db0..96d8c47a8a 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -82,8 +82,9 @@ static_assert(DEXOPT_STORAGE_DE == 1 << 8, "DEXOPT_STORAGE_DE unexpected."); static_assert(DEXOPT_ENABLE_HIDDEN_API_CHECKS == 1 << 10, "DEXOPT_ENABLE_HIDDEN_API_CHECKS unexpected"); static_assert(DEXOPT_GENERATE_COMPACT_DEX == 1 << 11, "DEXOPT_GENERATE_COMPACT_DEX unexpected"); +static_assert(DEXOPT_GENERATE_APP_IMAGE == 1 << 12, "DEXOPT_GENERATE_APP_IMAGE unexpected"); -static_assert(DEXOPT_MASK == (0xdfe | DEXOPT_IDLE_BACKGROUND_JOB), +static_assert(DEXOPT_MASK == (0x1dfe | DEXOPT_IDLE_BACKGROUND_JOB), "DEXOPT_MASK unexpected."); diff --git a/cmds/installd/otapreopt_parameters.cpp b/cmds/installd/otapreopt_parameters.cpp index d56aec9e2b..cf3de018c0 100644 --- a/cmds/installd/otapreopt_parameters.cpp +++ b/cmds/installd/otapreopt_parameters.cpp @@ -246,6 +246,8 @@ bool OTAPreoptParameters::ReadArgumentsPostV1(uint32_t version, const char** arg case 7: // Version 8 adds a new dexopt flag: DEXOPT_GENERATE_COMPACT_DEX case 8: num_args_expected = 16; break; + // Version 9 adds a new dexopt flag: DEXOPT_GENERATE_APP_IMAGE + case 9: num_args_expected = 16; break; default: LOG(ERROR) << "Don't know how to read arguments for version " << version; return false; diff --git a/cmds/installd/tests/installd_otapreopt_test.cpp b/cmds/installd/tests/installd_otapreopt_test.cpp index 63426cb4e0..b5185073d2 100644 --- a/cmds/installd/tests/installd_otapreopt_test.cpp +++ b/cmds/installd/tests/installd_otapreopt_test.cpp @@ -113,6 +113,7 @@ protected: case 6: return "6"; case 7: return "7"; case 8: return "8"; + case 9: return "9"; } return nullptr; } diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h index 80741c0442..b36728e934 100644 --- a/libs/arect/include/android/rect.h +++ b/libs/arect/include/android/rect.h @@ -33,23 +33,26 @@ extern "C" { #endif /** - * {@link ARect} is a struct that represents a rectangular window area. + * Rectangular window area. * - * It is used with {@link - * ANativeActivityCallbacks::onContentRectChanged} event callback and - * ANativeWindow_lock() function. + * This is the NDK equivalent of the android.graphics.Rect class in Java. It is + * used with {@link ANativeActivityCallbacks::onContentRectChanged} event + * callback and the ANativeWindow_lock() function. + * + * In a valid ARect, left <= right and top <= bottom. ARect with left=0, top=10, + * right=1, bottom=11 contains only one pixel at x=0, y=10. */ typedef struct ARect { #ifdef __cplusplus typedef int32_t value_type; #endif - /** left position */ + /// Minimum X coordinate of the rectangle. int32_t left; - /** top position */ + /// Minimum Y coordinate of the rectangle. int32_t top; - /** left position */ + /// Maximum X coordinate of the rectangle. int32_t right; - /** bottom position */ + /// Maximum Y coordinate of the rectangle. int32_t bottom; } ARect; diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp index 9adac26a31..2728f35408 100644 --- a/libs/binder/ActivityManager.cpp +++ b/libs/binder/ActivityManager.cpp @@ -80,6 +80,15 @@ void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer) } } +bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage) +{ + sp<IActivityManager> service = getService(); + if (service != NULL) { + return service->isUidActive(uid, callingPackage); + } + return false; +} + status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) { sp<IActivityManager> service = getService(); if (service != NULL) { diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index b7a5fd99f6..428db4d579 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -78,6 +78,18 @@ public: data.writeStrongBinder(IInterface::asBinder(observer)); remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply); } + + virtual bool isUidActive(const uid_t uid, const String16& callingPackage) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeInt32(uid); + data.writeString16(callingPackage); + remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32() == 1; + } }; // ------------------------------------------------------------------------------------ diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h index 397382f825..3090cae12a 100644 --- a/libs/binder/include/binder/ActivityManager.h +++ b/libs/binder/include/binder/ActivityManager.h @@ -50,6 +50,7 @@ public: const int32_t cutpoint, const String16& callingPackage); void unregisterUidObserver(const sp<IUidObserver>& observer); + bool isUidActive(const uid_t uid, const String16& callingPackage); status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient); status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient); diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index bac2a99a8f..6607c0e8e6 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -35,11 +35,13 @@ public: const int32_t cutpoint, const String16& callingPackage) = 0; virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0; + virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0; enum { OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, REGISTER_UID_OBSERVER_TRANSACTION, - UNREGISTER_UID_OBSERVER_TRANSACTION + UNREGISTER_UID_OBSERVER_TRANSACTION, + IS_UID_ACTIVE_TRANSACTION }; }; diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 788a6eb8f0..885efec9b9 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -984,7 +984,8 @@ status_t GLConsumer::doGLFenceWaitLocked() const { } if (mCurrentFence->isValid()) { - if (SyncFeatures::getInstance().useWaitSync()) { + if (SyncFeatures::getInstance().useWaitSync() && + SyncFeatures::getInstance().useNativeFenceSync()) { // Create an EGLSyncKHR from the current fence. int fenceFd = mCurrentFence->dup(); if (fenceFd == -1) { diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0244bb512e..e22bc708c9 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -43,6 +43,8 @@ namespace android { +using ui::ColorMode; + class BpSurfaceComposer : public BpInterface<ISurfaceComposer> { public: diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2e1c24b755..339bd0fa4e 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -44,6 +44,9 @@ namespace android { +using ui::ColorMode; +using ui::Dataspace; + Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), @@ -78,7 +81,7 @@ Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controll mReqFormat = 0; mReqUsage = 0; mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mDataSpace = HAL_DATASPACE_UNKNOWN; + mDataSpace = Dataspace::UNKNOWN; mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; @@ -664,8 +667,9 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, - mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, - fence, mStickyTransform, mEnableFrameTimestamps); + static_cast<android_dataspace>(mDataSpace), crop, mScalingMode, + mTransform ^ mStickyTransform, fence, mStickyTransform, + mEnableFrameTimestamps); // we should send HDR metadata as needed if this becomes a bottleneck input.setHdrMetadata(mHdrMetadata); @@ -1096,8 +1100,7 @@ int Surface::dispatchSetSidebandStream(va_list args) { } int Surface::dispatchSetBuffersDataSpace(va_list args) { - android_dataspace dataspace = - static_cast<android_dataspace>(va_arg(args, int)); + Dataspace dataspace = static_cast<Dataspace>(va_arg(args, int)); return setBuffersDataSpace(dataspace); } @@ -1529,7 +1532,7 @@ int Surface::setBuffersTimestamp(int64_t timestamp) return NO_ERROR; } -int Surface::setBuffersDataSpace(android_dataspace dataSpace) +int Surface::setBuffersDataSpace(Dataspace dataSpace) { ALOGV("Surface::setBuffersDataSpace"); Mutex::Autolock lock(mMutex); @@ -1561,7 +1564,7 @@ int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata return NO_ERROR; } -android_dataspace_t Surface::getBuffersDataSpace() { +Dataspace Surface::getBuffersDataSpace() { ALOGV("Surface::getBuffersDataSpace"); Mutex::Autolock lock(mMutex); return mDataSpace; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3cf49d6723..bbf681ea90 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -43,6 +43,8 @@ #include <private/gui/ComposerService.h> namespace android { + +using ui::ColorMode; // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); @@ -629,7 +631,7 @@ status_t SurfaceComposerClient::createSurfaceChecked( int32_t ownerUid) { sp<SurfaceControl> sur; - status_t err = NO_ERROR; + status_t err = mStatus; if (mStatus == NO_ERROR) { sp<IBinder> handle; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index afe9358c0a..3591090172 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -30,7 +30,7 @@ #include <ui/FrameStats.h> #include <ui/PixelFormat.h> #include <ui/GraphicBuffer.h> -#include <ui/GraphicsTypes.h> +#include <ui/GraphicTypes.h> #include <vector> @@ -161,10 +161,10 @@ public: virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0; virtual status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<ColorMode>* outColorModes) = 0; - virtual ColorMode getActiveColorMode(const sp<IBinder>& display) = 0; + Vector<ui::ColorMode>* outColorModes) = 0; + virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0; virtual status_t setActiveColorMode(const sp<IBinder>& display, - ColorMode colorMode) = 0; + ui::ColorMode colorMode) = 0; /* Capture the specified screen. requires READ_FRAME_BUFFER permission * This function will fail if there is a secure window on screen. diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 641d62cd4d..9aeafae198 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -22,6 +22,7 @@ #include <gui/IGraphicBufferProducer.h> #include <ui/ANativeObjectBase.h> +#include <ui/GraphicTypes.h> #include <ui/Region.h> #include <utils/Condition.h> @@ -245,7 +246,7 @@ protected: virtual int setBuffersTransform(uint32_t transform); virtual int setBuffersStickyTransform(uint32_t transform); virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setBuffersDataSpace(android_dataspace dataSpace); + virtual int setBuffersDataSpace(ui::Dataspace dataSpace); virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata); virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata); virtual int setCrop(Rect const* rect); @@ -286,7 +287,7 @@ public: // detachNextBuffer, or attachBuffer call. status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out); - android_dataspace_t getBuffersDataSpace(); + ui::Dataspace getBuffersDataSpace(); static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer); @@ -340,9 +341,9 @@ protected: int64_t mTimestamp; // mDataSpace is the buffer dataSpace that will be used for the next buffer - // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which + // queue operation. It defaults to Dataspace::UNKNOWN, which // means that the buffer contains some type of color data. - android_dataspace mDataSpace; + ui::Dataspace mDataSpace; // mHdrMetadata is the HDR metadata that will be used for the next buffer // queue operation. There is no HDR metadata by default. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index b45ce4f86c..ffc22f6437 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -29,7 +29,7 @@ #include <utils/threads.h> #include <ui/FrameStats.h> -#include <ui/GraphicsTypes.h> +#include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> #include <gui/CpuConsumer.h> @@ -89,13 +89,14 @@ public: // Gets the list of supported color modes for the given display static status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<ColorMode>* outColorModes); + Vector<ui::ColorMode>* outColorModes); // Gets the active color mode for the given display - static ColorMode getActiveColorMode(const sp<IBinder>& display); + static ui::ColorMode getActiveColorMode(const sp<IBinder>& display); // Sets the active color mode for the given display - static status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode); + static status_t setActiveColorMode(const sp<IBinder>& display, + ui::ColorMode colorMode); /* Triggers screen on/off or low power mode and waits for it to complete */ static void setDisplayPowerMode(const sp<IBinder>& display, int mode); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 66d5595fb9..2c02ba657d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -42,6 +42,7 @@ using namespace std::chrono_literals; // retrieve wide-color and hdr settings from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +using ui::ColorMode; using Transaction = SurfaceComposerClient::Transaction; @@ -58,7 +59,6 @@ static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max(); class SurfaceTest : public ::testing::Test { protected: - SurfaceTest() { ProcessState::self()->startThreadPool(); } @@ -93,6 +93,16 @@ protected: sp<SurfaceControl> mSurfaceControl; }; +TEST_F(SurfaceTest, CreateSurfaceReturnsErrorBadClient) { + mComposerClient->dispose(); + ASSERT_EQ(NO_INIT, mComposerClient->initCheck()); + + sp<SurfaceControl> sc; + status_t err = mComposerClient->createSurfaceChecked( + String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, &sc, 0); + ASSERT_EQ(NO_INIT, err); +} + TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) { sp<ANativeWindow> anw(mSurface); int result = -123; diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index a477bf2f3f..cc67aca3e4 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -41,9 +41,11 @@ enum { AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1, /** + * 32 bits per pixel, 8 bits per channel format where alpha values are + * ignored (always opaque). * Corresponding formats: * Vulkan: VK_FORMAT_R8G8B8A8_UNORM - * OpenGL ES: GL_RGBA8 + * OpenGL ES: GL_RGB8 */ AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2, @@ -124,40 +126,49 @@ enum { AHARDWAREBUFFER_FORMAT_S8_UINT = 0x35, }; +/** + * Buffer usage flags, specifying how the buffer will be accessed. + */ enum { - /* The buffer will never be read by the CPU */ + /// The buffer will never be read by the CPU. AHARDWAREBUFFER_USAGE_CPU_READ_NEVER = 0UL, - /* The buffer will sometimes be read by the CPU */ + /// The buffer will sometimes be read by the CPU. AHARDWAREBUFFER_USAGE_CPU_READ_RARELY = 2UL, - /* The buffer will often be read by the CPU */ + /// The buffer will often be read by the CPU. AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN = 3UL, - /* CPU read value mask */ + /// CPU read value mask. AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL, - /* The buffer will never be written by the CPU */ + /// The buffer will never be written by the CPU. AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER = 0UL << 4, - /* The buffer will sometimes be written to by the CPU */ + /// The buffer will sometimes be written to by the CPU. AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY = 2UL << 4, - /* The buffer will often be written to by the CPU */ + /// The buffer will often be written to by the CPU. AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN = 3UL << 4, - /* CPU write value mask */ + /// CPU write value mask. AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4, - /* The buffer will be read from by the GPU */ + /// The buffer will be read from by the GPU as a texture. AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8, - /* The buffer will be written to by the GPU */ + /** + * The buffer will be written to by the GPU as a framebuffer attachment. + * Note that the name of this flag is somewhat misleading: it does not imply + * that the buffer contains a color format. A buffer with depth or stencil + * format that will be used as a framebuffer attachment should also have + * this flag. + */ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = 1UL << 9, - /* The buffer must not be used outside of a protected hardware path */ + /// The buffer must not be used outside of a protected hardware path. AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14, - /* The buffer will be read by a hardware video encoder */ + /// The buffer will be read by a hardware video encoder. AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16, - /* The buffer will be used for sensor direct data */ + /// The buffer will be used for direct writes from sensors. AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23, - /* The buffer will be used as a shader storage or uniform buffer object */ + /// The buffer will be used as a shader storage or uniform buffer object. AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24, - /* The buffer will be used as a cube map texture */ + /// The buffer will be used as a cube map texture. AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25, - /* The buffer contains a complete mipmap hierarchy */ + /// The buffer contains a complete mipmap hierarchy. AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26, AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28, @@ -182,15 +193,19 @@ enum { AHARDWAREBUFFER_USAGE_VENDOR_19 = 1ULL << 63, }; +/** + * Buffer description. Used for allocating new buffers and querying parameters + * of existing ones. + */ typedef struct AHardwareBuffer_Desc { - uint32_t width; // width in pixels - uint32_t height; // height in pixels - uint32_t layers; // number of images - uint32_t format; // One of AHARDWAREBUFFER_FORMAT_* - uint64_t usage; // Combination of AHARDWAREBUFFER_USAGE_* - uint32_t stride; // Stride in pixels, ignored for AHardwareBuffer_allocate() - uint32_t rfu0; // Initialize to zero, reserved for future use - uint64_t rfu1; // Initialize to zero, reserved for future use + uint32_t width; ///< Width in pixels. + uint32_t height; ///< Height in pixels. + uint32_t layers; ///< Number of images in an image array. + uint32_t format; ///< One of AHARDWAREBUFFER_FORMAT_* + uint64_t usage; ///< Combination of AHARDWAREBUFFER_USAGE_* + uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate() + uint32_t rfu0; ///< Initialize to zero, reserved for future use. + uint64_t rfu1; ///< Initialize to zero, reserved for future use. } AHardwareBuffer_Desc; typedef struct AHardwareBuffer AHardwareBuffer; @@ -199,8 +214,8 @@ typedef struct AHardwareBuffer AHardwareBuffer; * Allocates a buffer that backs an AHardwareBuffer using the passed * AHardwareBuffer_Desc. * - * Returns NO_ERROR on success, or an error number of the allocation fails for - * any reason. + * \return NO_ERROR on success, or an error number of the allocation fails for + * any reason. The returned buffer has a reference count of 1. */ int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer); @@ -223,7 +238,7 @@ void AHardwareBuffer_release(AHardwareBuffer* buffer); void AHardwareBuffer_describe(const AHardwareBuffer* buffer, AHardwareBuffer_Desc* outDesc); -/* +/** * Lock the AHardwareBuffer for reading or writing, depending on the usage flags * passed. This call may block if the hardware needs to finish rendering or if * CPU caches need to be synchronized, or possibly for other implementation- @@ -231,16 +246,16 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, * descriptor that will be signaled when the buffer is locked, otherwise the * caller will block until the buffer is available. * - * If rect is not NULL, the caller promises to modify only data in the area + * If \a rect is not NULL, the caller promises to modify only data in the area * specified by rect. If rect is NULL, the caller may modify the contents of the * entire buffer. * * The content of the buffer outside of the specified rect is NOT modified * by this call. * - * The buffer usage may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set, then - * outVirtualAddress is filled with the address of the buffer in virtual memory, - * otherwise this function will fail. + * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set, + * then outVirtualAddress is filled with the address of the buffer in virtual + * memory. * * THREADING CONSIDERATIONS: * @@ -252,38 +267,38 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, * may return an error or leave the buffer's content into an indeterminate * state. * - * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL or if the usage + * \return NO_ERROR on success, BAD_VALUE if \a buffer is NULL or if the usage * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error * number of the lock fails for any reason. */ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, int32_t fence, const ARect* rect, void** outVirtualAddress); -/* +/** * Unlock the AHardwareBuffer; must be called after all changes to the buffer * are completed by the caller. If fence is not NULL then it will be set to a * file descriptor that is signaled when all pending work on the buffer is * completed. The caller is responsible for closing the fence when it is no * longer needed. * - * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error - * number of the lock fails for any reason. + * \return NO_ERROR on success, BAD_VALUE if \a buffer is NULL, or an error + * number if the unlock fails for any reason. */ int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence); -/* +/** * Send the AHardwareBuffer to an AF_UNIX socket. * - * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error - * number of the lock fails for any reason. + * \return NO_ERROR on success, BAD_VALUE if \a buffer is NULL, or an error + * number if the operation fails for any reason. */ int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd); -/* +/** * Receive the AHardwareBuffer from an AF_UNIX socket. * - * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error - * number of the lock fails for any reason. + * \return NO_ERROR on success, BAD_VALUE if \a outBuffer is NULL, or an error + * number if the operation fails for any reason. */ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer); diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index f2d6f7a69b..d5e5e9dd24 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -85,23 +85,23 @@ typedef struct ANativeWindow ANativeWindow; * A pointer can be obtained using {@link ANativeWindow_lock()}. */ typedef struct ANativeWindow_Buffer { - // The number of pixels that are show horizontally. + /// The number of pixels that are shown horizontally. int32_t width; - // The number of pixels that are shown vertically. + /// The number of pixels that are shown vertically. int32_t height; - // The number of *pixels* that a line in the buffer takes in - // memory. This may be >= width. + /// The number of *pixels* that a line in the buffer takes in + /// memory. This may be >= width. int32_t stride; - // The format of the buffer. One of AHARDWAREBUFFER_FORMAT_* + /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_* int32_t format; - // The actual bits. + /// The actual bits. void* bits; - // Do not touch. + /// Do not touch. uint32_t reserved[6]; } ANativeWindow_Buffer; diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index f71f814f55..e477a830c9 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -83,6 +83,7 @@ cc_library_shared { "libhidlbase", "libhidltransport", "libhwbinder", + "libpdx_default_transport", "libsync", "libutils", "libutilscallstack", @@ -99,10 +100,9 @@ cc_library_shared { "libbase_headers", "libnativebase_headers", "libhardware_headers", + "libui_headers", ], - export_include_dirs: ["include"], - export_static_lib_headers: [ "libarect", "libmath", @@ -112,6 +112,7 @@ cc_library_shared { "libbase_headers", "libnativebase_headers", "libhardware_headers", + "libui_headers", ], } @@ -119,6 +120,11 @@ cc_library_headers { name: "libui_headers", export_include_dirs: ["include"], vendor_available: true, + target: { + vendor: { + override_export_include_dirs: ["include_vndk"], + }, + }, } subdirs = [ diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index d7e191db89..58fed84ea8 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -22,7 +22,7 @@ #include <string> using android::base::StringPrintf; -using android::ColorMode; +using android::ui::ColorMode; std::string decodeStandard(android_dataspace dataspace) { const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK); @@ -234,6 +234,33 @@ std::string decodeColorMode(ColorMode colorMode) { return android::base::StringPrintf("Unknown color mode %d", colorMode); } +std::string decodeColorTransform(android_color_transform colorTransform) { + switch (colorTransform) { + case HAL_COLOR_TRANSFORM_IDENTITY: + return std::string("Identity"); + + case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX: + return std::string("Arbitrary matrix"); + + case HAL_COLOR_TRANSFORM_VALUE_INVERSE: + return std::string("Inverse value"); + + case HAL_COLOR_TRANSFORM_GRAYSCALE: + return std::string("Grayscale"); + + case HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA: + return std::string("Correct protanopia"); + + case HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA: + return std::string("Correct deuteranopia"); + + case HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA: + return std::string("Correct tritanopia"); + } + + return android::base::StringPrintf("Unknown color transform %d", colorTransform); +} + // Converts a PixelFormat to a human-readable string. Max 11 chars. // (Could use a table of prefab String8 objects.) std::string decodePixelFormat(android::PixelFormat format) { diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 4ed2aa42fc..254038b0ad 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -22,6 +22,7 @@ #include <grallocusage/GrallocUsageConversion.h> +#include <ui/DetachedBufferHandle.h> #include <ui/Gralloc2.h> #include <ui/GraphicBufferAllocator.h> #include <ui/GraphicBufferMapper.h> @@ -486,6 +487,24 @@ status_t GraphicBuffer::unflatten( return NO_ERROR; } +bool GraphicBuffer::isDetachedBuffer() const { + return mDetachedBufferHandle && mDetachedBufferHandle->isValid(); +} + +status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) { + if (isDetachedBuffer()) { + ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this " + "GraphicBuffer. Replacing the old one."); + } + + mDetachedBufferHandle = std::move(channel); + return NO_ERROR; +} + +std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() { + return std::move(mDetachedBufferHandle); +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h index 33701070a9..5e5df43740 100644 --- a/libs/ui/include/ui/DebugUtils.h +++ b/libs/ui/include/ui/DebugUtils.h @@ -16,7 +16,7 @@ #pragma once -#include <ui/GraphicsTypes.h> +#include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> #include <string> @@ -29,6 +29,7 @@ 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::ColorMode colormode); +std::string decodeColorMode(android::ui::ColorMode colormode); +std::string decodeColorTransform(android_color_transform colorTransform); std::string decodePixelFormat(android::PixelFormat format); std::string to_string(const android::Rect& rect); diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h new file mode 100644 index 0000000000..f3c328d52b --- /dev/null +++ b/libs/ui/include/ui/DetachedBufferHandle.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 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_DETACHED_BUFFER_HUB_HANDLE_H +#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H + +#include <pdx/channel_handle.h> + +#include <memory> + +namespace android { + +// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be +// created. Current implementation assumes that the underlying transport is using libpdx (thus +// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder +// backend if ever needed. +class DetachedBufferHandle { +public: + static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) { + return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle))); + } + + // Accessors to get or take the internal pdx::LocalChannelHandle. + pdx::LocalChannelHandle& handle() { return mHandle; } + const pdx::LocalChannelHandle& handle() const { return mHandle; } + + // Returns whether the DetachedBufferHandle holds a BufferHub channel. + bool isValid() const { return mHandle.valid(); } + +private: + // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle. + explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {} + + pdx::LocalChannelHandle mHandle; +}; + +} // namespace android + +#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index e794462f60..cc38982e64 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -34,6 +34,7 @@ namespace android { +class DetachedBufferHandle; class GraphicBufferMapper; // =========================================================================== @@ -190,6 +191,11 @@ public: status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + // Sets and takes DetachedBuffer. Should only be called from BufferHub. + bool isDetachedBuffer() const; + status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer); + std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle(); + private: ~GraphicBuffer(); @@ -240,6 +246,17 @@ private: // match the BufferQueue's internal generation number (set through // IGBP::setGenerationNumber), attempts to attach the buffer will fail. uint32_t mGenerationNumber; + + // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a + // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub, + // there are three different modes: + // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be + // invalid. + // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer + // set. In this mode, mDetachedBufferHandle must be valid. + // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer + // set. In this mode, mDetachedBufferHandle must be invalid. + std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle; }; }; // namespace android diff --git a/libs/ui/include/ui/GraphicsTypes.h b/libs/ui/include/ui/GraphicTypes.h index fa9a812d97..92a5519898 100644 --- a/libs/ui/include/ui/GraphicsTypes.h +++ b/libs/ui/include/ui/GraphicTypes.h @@ -19,8 +19,14 @@ #include <android/hardware/graphics/common/1.1/types.h> #include <system/graphics.h> +// android::ui::* in this header file will alias different types as +// the HIDL interface is updated. namespace android { +namespace ui { using android::hardware::graphics::common::V1_0::ColorMode; +using android::hardware::graphics::common::V1_1::Dataspace; +using android::hardware::graphics::common::V1_1::PixelFormat; +} // namespace ui } // namespace android diff --git a/libs/ui/include_vndk/ui/ANativeObjectBase.h b/libs/ui/include_vndk/ui/ANativeObjectBase.h new file mode 120000 index 0000000000..4dab8d8b8b --- /dev/null +++ b/libs/ui/include_vndk/ui/ANativeObjectBase.h @@ -0,0 +1 @@ +../../include/ui/ANativeObjectBase.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/BufferQueueDefs.h b/libs/ui/include_vndk/ui/BufferQueueDefs.h new file mode 120000 index 0000000000..c886ed858e --- /dev/null +++ b/libs/ui/include_vndk/ui/BufferQueueDefs.h @@ -0,0 +1 @@ +../../include/ui/BufferQueueDefs.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/ColorSpace.h b/libs/ui/include_vndk/ui/ColorSpace.h new file mode 120000 index 0000000000..ddf70d5bdf --- /dev/null +++ b/libs/ui/include_vndk/ui/ColorSpace.h @@ -0,0 +1 @@ +../../include/ui/ColorSpace.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/DebugUtils.h b/libs/ui/include_vndk/ui/DebugUtils.h new file mode 120000 index 0000000000..8461bb39c3 --- /dev/null +++ b/libs/ui/include_vndk/ui/DebugUtils.h @@ -0,0 +1 @@ +../../include/ui/DebugUtils.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/DisplayInfo.h b/libs/ui/include_vndk/ui/DisplayInfo.h new file mode 120000 index 0000000000..75f14cf66d --- /dev/null +++ b/libs/ui/include_vndk/ui/DisplayInfo.h @@ -0,0 +1 @@ +../../include/ui/DisplayInfo.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/DisplayStatInfo.h b/libs/ui/include_vndk/ui/DisplayStatInfo.h new file mode 120000 index 0000000000..6689ad3162 --- /dev/null +++ b/libs/ui/include_vndk/ui/DisplayStatInfo.h @@ -0,0 +1 @@ +../../include/ui/DisplayStatInfo.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Fence.h b/libs/ui/include_vndk/ui/Fence.h new file mode 120000 index 0000000000..b110201354 --- /dev/null +++ b/libs/ui/include_vndk/ui/Fence.h @@ -0,0 +1 @@ +../../include/ui/Fence.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/FenceTime.h b/libs/ui/include_vndk/ui/FenceTime.h new file mode 120000 index 0000000000..01a6ff21d1 --- /dev/null +++ b/libs/ui/include_vndk/ui/FenceTime.h @@ -0,0 +1 @@ +../../include/ui/FenceTime.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/FloatRect.h b/libs/ui/include_vndk/ui/FloatRect.h new file mode 120000 index 0000000000..a5262118f7 --- /dev/null +++ b/libs/ui/include_vndk/ui/FloatRect.h @@ -0,0 +1 @@ +../../include/ui/FloatRect.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/FrameStats.h b/libs/ui/include_vndk/ui/FrameStats.h new file mode 120000 index 0000000000..e68e5c843f --- /dev/null +++ b/libs/ui/include_vndk/ui/FrameStats.h @@ -0,0 +1 @@ +../../include/ui/FrameStats.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Gralloc2.h b/libs/ui/include_vndk/ui/Gralloc2.h new file mode 120000 index 0000000000..66098c4edb --- /dev/null +++ b/libs/ui/include_vndk/ui/Gralloc2.h @@ -0,0 +1 @@ +../../include/ui/Gralloc2.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/GraphicBuffer.h b/libs/ui/include_vndk/ui/GraphicBuffer.h new file mode 120000 index 0000000000..445eae5395 --- /dev/null +++ b/libs/ui/include_vndk/ui/GraphicBuffer.h @@ -0,0 +1 @@ +../../include/ui/GraphicBuffer.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/GraphicBufferAllocator.h b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h new file mode 120000 index 0000000000..96345330f1 --- /dev/null +++ b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h @@ -0,0 +1 @@ +../../include/ui/GraphicBufferAllocator.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/GraphicBufferMapper.h b/libs/ui/include_vndk/ui/GraphicBufferMapper.h new file mode 120000 index 0000000000..c3b3a7c61d --- /dev/null +++ b/libs/ui/include_vndk/ui/GraphicBufferMapper.h @@ -0,0 +1 @@ +../../include/ui/GraphicBufferMapper.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/GraphicTypes.h b/libs/ui/include_vndk/ui/GraphicTypes.h new file mode 120000 index 0000000000..b1859e0f51 --- /dev/null +++ b/libs/ui/include_vndk/ui/GraphicTypes.h @@ -0,0 +1 @@ +../../include/ui/GraphicTypes.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/HdrCapabilities.h b/libs/ui/include_vndk/ui/HdrCapabilities.h new file mode 120000 index 0000000000..a240828c8c --- /dev/null +++ b/libs/ui/include_vndk/ui/HdrCapabilities.h @@ -0,0 +1 @@ +../../include/ui/HdrCapabilities.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/PixelFormat.h b/libs/ui/include_vndk/ui/PixelFormat.h new file mode 120000 index 0000000000..0aba056f58 --- /dev/null +++ b/libs/ui/include_vndk/ui/PixelFormat.h @@ -0,0 +1 @@ +../../include/ui/PixelFormat.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Point.h b/libs/ui/include_vndk/ui/Point.h new file mode 120000 index 0000000000..0aeda3e97e --- /dev/null +++ b/libs/ui/include_vndk/ui/Point.h @@ -0,0 +1 @@ +../../include/ui/Point.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Rect.h b/libs/ui/include_vndk/ui/Rect.h new file mode 120000 index 0000000000..01ed6891e9 --- /dev/null +++ b/libs/ui/include_vndk/ui/Rect.h @@ -0,0 +1 @@ +../../include/ui/Rect.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/Region.h b/libs/ui/include_vndk/ui/Region.h new file mode 120000 index 0000000000..3f829bfad0 --- /dev/null +++ b/libs/ui/include_vndk/ui/Region.h @@ -0,0 +1 @@ +../../include/ui/Region.h
\ No newline at end of file diff --git a/libs/ui/include_vndk/ui/UiConfig.h b/libs/ui/include_vndk/ui/UiConfig.h new file mode 120000 index 0000000000..f580ce1095 --- /dev/null +++ b/libs/ui/include_vndk/ui/UiConfig.h @@ -0,0 +1 @@ +../../include/ui/UiConfig.h
\ No newline at end of file diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 08067fcf5d..aef6428cc8 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -27,3 +27,10 @@ cc_test { srcs: ["colorspace_test.cpp"], cflags: ["-Wall", "-Werror"], } + +cc_test { + name: "GraphicBuffer_test", + shared_libs: ["libpdx_default_transport", "libui", "libutils"], + srcs: ["GraphicBuffer_test.cpp"], + cflags: ["-Wall", "-Werror"], +} diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp new file mode 100644 index 0000000000..eb679ac236 --- /dev/null +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2018 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 "GraphicBufferTest" + +#include <ui/DetachedBufferHandle.h> +#include <ui/GraphicBuffer.h> + +#include <gtest/gtest.h> + +namespace android { + +namespace { + +constexpr uint32_t kTestWidth = 1024; +constexpr uint32_t kTestHeight = 1; +constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB; +constexpr uint32_t kTestLayerCount = 1; +constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; + +} // namespace + +class GraphicBufferTest : public testing::Test {}; + +TEST_F(GraphicBufferTest, DetachedBuffer) { + sp<GraphicBuffer> buffer( + new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage)); + + // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with + // BufferHub. But this may change in the future. + EXPECT_FALSE(buffer->isDetachedBuffer()); + + pdx::LocalChannelHandle channel{nullptr, 1234}; + EXPECT_TRUE(channel.valid()); + + std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel)); + EXPECT_FALSE(channel.valid()); + EXPECT_TRUE(handle->isValid()); + EXPECT_TRUE(handle->handle().valid()); + + buffer->setDetachedBufferHandle(std::move(handle)); + EXPECT_TRUE(handle == nullptr); + EXPECT_TRUE(buffer->isDetachedBuffer()); + + handle = buffer->takeDetachedBufferHandle(); + EXPECT_TRUE(handle != nullptr); + EXPECT_TRUE(handle->isValid()); + EXPECT_FALSE(buffer->isDetachedBuffer()); +} + +} // namespace android diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp index 3ce5c9f8d6..660a2003ea 100644 --- a/libs/vr/libbufferhub/buffer_hub-test.cpp +++ b/libs/vr/libbufferhub/buffer_hub-test.cpp @@ -769,9 +769,14 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { auto s3 = p->CreateConsumer(); EXPECT_FALSE(s3); + // Note that here the expected error code is EOPNOTSUPP as the socket towards + // ProducerChannel has been teared down. EXPECT_EQ(s3.error(), EOPNOTSUPP); s3 = c->CreateConsumer(); EXPECT_FALSE(s3); - EXPECT_EQ(s3.error(), EOPNOTSUPP); + // Note that here the expected error code is EPIPE returned from + // ConsumerChannel::HandleMessage as the socket is still open but the producer + // is gone. + EXPECT_EQ(s3.error(), EPIPE); } diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index b453d19d83..f3a9ad8b88 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -94,6 +94,7 @@ char const * const gBuiltinExtensionString = char const * const gExtensionString = "EGL_KHR_image " // mandatory "EGL_KHR_image_base " // mandatory + "EGL_KHR_image_gl_colorspace " "EGL_KHR_image_pixmap " "EGL_KHR_lock_surface " "EGL_KHR_gl_colorspace " diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index c3f4f58f58..9a449fa6d1 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -105,6 +105,36 @@ static inline const char* toString(bool value) { return value ? "true" : "false"; } +static std::string motionActionToString(int32_t action) { + // Convert MotionEvent action to string + switch(action & AMOTION_EVENT_ACTION_MASK) { + case AMOTION_EVENT_ACTION_DOWN: + return "DOWN"; + case AMOTION_EVENT_ACTION_MOVE: + return "MOVE"; + case AMOTION_EVENT_ACTION_UP: + return "UP"; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + return "POINTER_DOWN"; + case AMOTION_EVENT_ACTION_POINTER_UP: + return "POINTER_UP"; + } + return StringPrintf("%" PRId32, action); +} + +static std::string keyActionToString(int32_t action) { + // Convert KeyEvent action to string + switch(action) { + case AKEY_EVENT_ACTION_DOWN: + return "DOWN"; + case AKEY_EVENT_ACTION_UP: + return "UP"; + case AKEY_EVENT_ACTION_MULTIPLE: + return "MULTIPLE"; + } + return StringPrintf("%" PRId32, action); +} + static inline int32_t getMotionEventActionPointerIndex(int32_t action) { return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; @@ -3976,11 +4006,11 @@ InputDispatcher::KeyEntry::~KeyEntry() { } void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const { - msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%d, " + msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%s, " "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " "repeatCount=%d), policyFlags=0x%08x", - deviceId, source, action, flags, keyCode, scanCode, metaState, - repeatCount, policyFlags); + deviceId, source, keyActionToString(action).c_str(), flags, keyCode, + scanCode, metaState, repeatCount, policyFlags); } void InputDispatcher::KeyEntry::recycle() { @@ -4021,11 +4051,11 @@ InputDispatcher::MotionEntry::~MotionEntry() { } void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const { - msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, " + msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%s, actionButton=0x%08x, " "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, " "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[", - deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags, - xPrecision, yPrecision, displayId); + deviceId, source, motionActionToString(action).c_str(), actionButton, flags, metaState, + buttonState, edgeFlags, xPrecision, yPrecision, displayId); for (uint32_t i = 0; i < pointerCount; i++) { if (i) { msg += ", "; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 2bd0a19c44..8e9e7fdf7c 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -86,6 +86,7 @@ static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSOR SensorService::SensorService() : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED), mWakeLockAcquired(false) { + mUidPolicy = new UidPolicy(this); } bool SensorService::initializeHmacKey() { @@ -283,7 +284,6 @@ void SensorService::onFirstRef() { enableSchedFifoMode(); // Start watching UID changes to apply policy. - mUidPolicy = new UidPolicy(this); mUidPolicy->registerSelf(); } } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index ba28eb5298..ff994f515c 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -105,6 +105,7 @@ filegroup { "Layer.cpp", "LayerProtoHelper.cpp", "LayerRejecter.cpp", + "LayerStats.cpp", "LayerVector.cpp", "MessageQueue.cpp", "MonitoredProducer.cpp", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index d22c021139..82300e679f 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -690,9 +690,9 @@ void BufferLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope Mutex::Autolock lock(mQueueItemLock); - mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(), - item.mGraphicBuffer->getHeight(), - item.mFrameNumber); + mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(), + item.mGraphicBuffer->getHeight(), + item.mFrameNumber); // Reset the frame number tracker when we receive the first buffer after // a frame number reset if (item.mFrameNumber == 1) { @@ -829,7 +829,7 @@ void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityT getColor()); engine.setSourceDataSpace(mCurrentState.dataSpace); - if (mCurrentState.dataSpace == HAL_DATASPACE_BT2020_ITU_PQ && + if (mCurrentState.dataSpace == ui::Dataspace::BT2020_ITU_PQ && mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA && getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102) { engine.setSourceY410BT2020(true); diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 46ec0e322b..6b4f5dbfb0 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -65,7 +65,7 @@ BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentFence(Fence::NO_FENCE), mCurrentTimestamp(0), - mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), + mCurrentDataSpace(ui::Dataspace::UNKNOWN), mCurrentFrameNumber(0), mCurrentTransformToDisplayInverse(false), mCurrentSurfaceDamage(), @@ -341,7 +341,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, mCurrentTransform = item.mTransform; mCurrentScalingMode = item.mScalingMode; mCurrentTimestamp = item.mTimestamp; - mCurrentDataSpace = item.mDataSpace; + mCurrentDataSpace = static_cast<ui::Dataspace>(item.mDataSpace); mCurrentHdrMetadata = item.mHdrMetadata; mCurrentFence = item.mFence; mCurrentFenceTime = item.mFenceTime; @@ -445,7 +445,7 @@ nsecs_t BufferLayerConsumer::getTimestamp() { return mCurrentTimestamp; } -android_dataspace BufferLayerConsumer::getCurrentDataSpace() { +ui::Dataspace BufferLayerConsumer::getCurrentDataSpace() { BLC_LOGV("getCurrentDataSpace"); Mutex::Autolock lock(mMutex); return mCurrentDataSpace; diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index 11048d8df8..f81cdb1d91 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -23,6 +23,7 @@ #include <ui/FenceTime.h> #include <ui/GraphicBuffer.h> +#include <ui/GraphicTypes.h> #include <ui/Region.h> #include <utils/String8.h> @@ -122,7 +123,7 @@ public: // getDataSpace retrieves the DataSpace associated with the texture image // set by the most recent call to updateTexImage. - android_dataspace getCurrentDataSpace(); + ui::Dataspace getCurrentDataSpace(); // getCurrentHdrMetadata retrieves the HDR metadata associated with the // texture image set by the most recent call to updateTexImage. @@ -324,7 +325,7 @@ private: // mCurrentDataSpace is the dataspace for the current texture. It // gets set each time updateTexImage is called. - android_dataspace mCurrentDataSpace; + ui::Dataspace mCurrentDataSpace; // mCurrentHdrMetadata is the HDR metadata for the current texture. It // gets set each time updateTexImage is called. diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 92d5e21f34..58a774b7e2 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -49,16 +49,12 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <configstore/Utils.h> -// ---------------------------------------------------------------------------- -using namespace android; -// ---------------------------------------------------------------------------- +namespace android { // retrieve triple buffer setting from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; - -static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3; +using android::ui::ColorMode; /* * Initialize the display to the specified values. @@ -74,72 +70,44 @@ DisplayDevice::DisplayDevice( int32_t hwcId, bool isSecure, const wp<IBinder>& displayToken, + const sp<ANativeWindow>& nativeWindow, const sp<DisplaySurface>& displaySurface, - const sp<IGraphicBufferProducer>& producer, + std::unique_ptr<RE::Surface> renderSurface, + int displayWidth, + int displayHeight, bool supportWideColor, - bool supportHdr) + bool supportHdr, + int initialPowerMode) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), mType(type), mHwcDisplayId(hwcId), mDisplayToken(displayToken), + mNativeWindow(nativeWindow), mDisplaySurface(displaySurface), - mSurface{flinger->getRenderEngine().createSurface()}, - mDisplayWidth(), - mDisplayHeight(), - mPageFlipCount(), + mSurface{std::move(renderSurface)}, + mDisplayWidth(displayWidth), + mDisplayHeight(displayHeight), + mPageFlipCount(0), mIsSecure(isSecure), mLayerStack(NO_LAYER_STACK), mOrientation(), - mPowerMode(HWC_POWER_MODE_OFF), - mActiveConfig(0) + mViewport(Rect::INVALID_RECT), + mFrame(Rect::INVALID_RECT), + mPowerMode(initialPowerMode), + mActiveConfig(0), + mActiveColorMode(ColorMode::NATIVE), + mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY), + mDisplayHasWideColor(supportWideColor), + mDisplayHasHdr(supportHdr) { // clang-format on - Surface* surface; - mNativeWindow = surface = new Surface(producer, false); - ANativeWindow* const window = mNativeWindow.get(); - - mActiveColorMode = ColorMode::NATIVE; - mDisplayHasWideColor = supportWideColor; - mDisplayHasHdr = supportHdr; - - /* - * Create our display's surface - */ - mSurface->setCritical(mType == DisplayDevice::DISPLAY_PRIMARY); - mSurface->setAsync(mType >= DisplayDevice::DISPLAY_VIRTUAL); - mSurface->setNativeWindow(window); - mDisplayWidth = mSurface->queryWidth(); - mDisplayHeight = mSurface->queryHeight(); - - // Make sure that composition can never be stalled by a virtual display - // consumer that isn't processing buffers fast enough. We have to do this - // in two places: - // * Here, in case the display is composed entirely by HWC. - // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the - // window's swap interval in eglMakeCurrent, so they'll override the - // interval we set here. - if (mType >= DisplayDevice::DISPLAY_VIRTUAL) - window->setSwapInterval(window, 0); - - mPageFlipCount = 0; - mViewport.makeInvalid(); - mFrame.makeInvalid(); - - // virtual displays are always considered enabled - mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ? - HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF; // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); - - if (useTripleFramebuffer) { - surface->allocateBuffers(); - } } -DisplayDevice::~DisplayDevice() { -} +DisplayDevice::~DisplayDevice() = default; void DisplayDevice::disconnect(HWComposer& hwc) { if (mHwcDisplayId >= 0) { @@ -300,9 +268,19 @@ ColorMode DisplayDevice::getActiveColorMode() const { return mActiveColorMode; } -void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) { +void DisplayDevice::setColorTransform(const mat4& transform) { + const bool isIdentity = (transform == mat4()); + mColorTransform = + isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX; +} + +android_color_transform_t DisplayDevice::getColorTransform() const { + return mColorTransform; +} + +void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) { ANativeWindow* const window = mNativeWindow.get(); - native_window_set_buffers_data_space(window, dataspace); + native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace)); } // ---------------------------------------------------------------------------- @@ -485,8 +463,11 @@ void DisplayDevice::dump(String8& result) const { mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); auto const surface = static_cast<Surface*>(window); - android_dataspace dataspace = surface->getBuffersDataSpace(); - result.appendFormat(" dataspace: %s (%d)\n", dataspaceDetails(dataspace).c_str(), dataspace); + ui::Dataspace dataspace = surface->getBuffersDataSpace(); + result.appendFormat(" wideColor=%d, hdr=%d, colorMode=%s, dataspace: %s (%d)\n", + mDisplayHasWideColor, mDisplayHasHdr, + decodeColorMode(mActiveColorMode).c_str(), + dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace); String8 surfaceDump; mDisplaySurface->dumpAsString(surfaceDump); @@ -506,3 +487,5 @@ DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type, bool isS viewport.makeInvalid(); frame.makeInvalid(); } + +} // namespace android diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 737971f83d..e844d115c2 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -21,6 +21,8 @@ #include <stdlib.h> +#include <math/mat4.h> + #include <ui/Region.h> #include <binder/IBinder.h> @@ -31,7 +33,7 @@ #include <gui/ISurfaceComposer.h> #include <hardware/hwcomposer_defs.h> -#include <ui/GraphicsTypes.h> +#include <ui/GraphicTypes.h> #include "RenderArea.h" #include "RenderEngine/Surface.h" @@ -77,9 +79,14 @@ public: int32_t hwcId, bool isSecure, const wp<IBinder>& displayToken, + const sp<ANativeWindow>& nativeWindow, const sp<DisplaySurface>& displaySurface, - const sp<IGraphicBufferProducer>& producer, - bool supportWideColor, bool supportHdr); + std::unique_ptr<RE::Surface> renderSurface, + int displayWidth, + int displayHeight, + bool supportWideColor, + bool supportHdr, + int initialPowerMode); // clang-format on ~DisplayDevice(); @@ -156,9 +163,11 @@ public: void setPowerMode(int mode); bool isDisplayOn() const; - ColorMode getActiveColorMode() const; - void setActiveColorMode(ColorMode mode); - void setCompositionDataSpace(android_dataspace dataspace); + ui::ColorMode getActiveColorMode() const; + void setActiveColorMode(ui::ColorMode mode); + android_color_transform_t getColorTransform() const; + void setColorTransform(const mat4& transform); + void setCompositionDataSpace(ui::Dataspace dataspace); /* ------------------------------------------------------------------------ * Display active config management. @@ -231,7 +240,9 @@ private: // Current active config int mActiveConfig; // current active color mode - ColorMode mActiveColorMode; + ui::ColorMode mActiveColorMode; + // Current color transform + android_color_transform_t mColorTransform; // Need to know if display is wide-color capable or not. // Initialized by SurfaceFlinger when the DisplayDevice is created. @@ -280,7 +291,7 @@ public: bool needsFiltering() const override { return mDevice->needsFiltering(); } Rect getSourceCrop() const override { return mSourceCrop; } bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); } - ColorMode getActiveColorMode() const override { + ui::ColorMode getActiveColorMode() const override { return mDevice->getActiveColorMode(); } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 0425a8a216..bbffd0ae7f 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -32,6 +32,7 @@ namespace android { using hardware::Return; using hardware::hidl_vec; using hardware::hidl_handle; +using namespace hardware::graphics::common; using namespace hardware::graphics::composer; using PerFrameMetadata = hardware::graphics::composer::V2_2::IComposerClient::PerFrameMetadata; using PerFrameMetadataKey = @@ -256,17 +257,32 @@ Error Composer::createVirtualDisplay(uint32_t width, uint32_t height, { const uint32_t bufferSlotCount = 1; Error error = kDefaultError; - mClient->createVirtualDisplay(width, height, *format, bufferSlotCount, - [&](const auto& tmpError, const auto& tmpDisplay, - const auto& tmpFormat) { - error = tmpError; - if (error != Error::NONE) { - return; - } - - *outDisplay = tmpDisplay; - *format = tmpFormat; + if (mClient_2_2) { + mClient_2_2->createVirtualDisplay_2_2(width, height, *format, bufferSlotCount, + [&](const auto& tmpError, const auto& tmpDisplay, + const auto& tmpFormat) { + error = tmpError; + if (error != Error::NONE) { + return; + } + + *outDisplay = tmpDisplay; + *format = tmpFormat; + }); + } else { + mClient->createVirtualDisplay(width, height, + static_cast<V1_0::PixelFormat>(*format), bufferSlotCount, + [&](const auto& tmpError, const auto& tmpDisplay, + const auto& tmpFormat) { + error = tmpError; + if (error != Error::NONE) { + return; + } + + *outDisplay = tmpDisplay; + *format = static_cast<PixelFormat>(tmpFormat); }); + } return error; } @@ -522,7 +538,7 @@ Error Composer::setClientTarget(Display display, uint32_t slot, .height = target->getHeight(), .stride = target->getStride(), .layerCount = target->getLayerCount(), - .format = static_cast<PixelFormat>(target->getPixelFormat()), + .format = static_cast<V1_0::PixelFormat>(target->getPixelFormat()), .usage = target->getUsage(), }; mWriter.setClientTargetMetadata(metadata); @@ -645,7 +661,7 @@ Error Composer::setLayerBuffer(Display display, Layer layer, .height = buffer->getHeight(), .stride = buffer->getStride(), .layerCount = buffer->getLayerCount(), - .format = static_cast<PixelFormat>(buffer->getPixelFormat()), + .format = static_cast<V1_0::PixelFormat>(buffer->getPixelFormat()), .usage = buffer->getUsage(), }; mWriter.setLayerBufferMetadata(metadata); @@ -742,7 +758,7 @@ Error Composer::setLayerHdrMetadata(Display display, Layer layer, const HdrMetad metadata.cta8613.maxFrameAverageLightLevel}}); } - mWriter.setPerFrameMetadata(composerMetadata); + mWriter.setLayerPerFrameMetadata(composerMetadata); return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index c0373aa6c1..98f2f9d387 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -24,6 +24,7 @@ #include <vector> #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h> +#include <android/hardware/graphics/common/1.1/types.h> #include <android/hardware/graphics/composer/2.2/IComposer.h> #include <android/hardware/graphics/composer/2.2/IComposerClient.h> #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> @@ -39,10 +40,10 @@ using android::frameworks::vr::composer::V1_0::IVrComposerClient; using android::hardware::graphics::common::V1_0::ColorMode; using android::hardware::graphics::common::V1_0::ColorTransform; -using android::hardware::graphics::common::V1_0::Dataspace; using android::hardware::graphics::common::V1_0::Hdr; -using android::hardware::graphics::common::V1_0::PixelFormat; using android::hardware::graphics::common::V1_0::Transform; +using android::hardware::graphics::common::V1_1::Dataspace; +using android::hardware::graphics::common::V1_1::PixelFormat; using android::hardware::graphics::composer::V2_1::Config; using android::hardware::graphics::composer::V2_1::Display; diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 4faba3b77a..e6d783434a 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -44,6 +44,8 @@ namespace android { // ---------------------------------------------------------------------------- +using ui::Dataspace; + /* * This implements the (main) framebuffer management. This class is used * mostly by SurfaceFlinger, but also by command line GL application. @@ -92,7 +94,7 @@ status_t FramebufferSurface::advanceFrame() { uint32_t slot = 0; sp<GraphicBuffer> buf; sp<Fence> acquireFence(Fence::NO_FENCE); - android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; + Dataspace dataspace = Dataspace::UNKNOWN; status_t result = nextBuffer(slot, buf, acquireFence, dataspace); mDataSpace = dataspace; if (result != NO_ERROR) { @@ -104,7 +106,7 @@ status_t FramebufferSurface::advanceFrame() { status_t FramebufferSurface::nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence, - android_dataspace_t& outDataspace) { + Dataspace& outDataspace) { Mutex::Autolock lock(mMutex); BufferItem item; @@ -139,7 +141,7 @@ status_t FramebufferSurface::nextBuffer(uint32_t& outSlot, outFence = item.mFence; mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer); - outDataspace = item.mDataSpace; + outDataspace = static_cast<Dataspace>(item.mDataSpace); status_t result = mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace); if (result != NO_ERROR) { @@ -177,9 +179,10 @@ void FramebufferSurface::onFrameCommitted() { void FramebufferSurface::dumpAsString(String8& result) const { Mutex::Autolock lock(mMutex); - result.appendFormat("FramebufferSurface: dataspace: %s(%d)\n", - dataspaceDetails(mDataSpace).c_str(), mDataSpace); - ConsumerBase::dumpLocked(result, ""); + result.appendFormat(" FramebufferSurface: dataspace: %s(%d)\n", + dataspaceDetails(static_cast<android_dataspace>(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 ed756c49a1..0fd8e9eaa4 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -61,7 +61,7 @@ private: // BufferQueue and releases the previously latched buffer to the // BufferQueue. The new buffer is returned in the 'buffer' argument. status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer, - sp<Fence>& outFence, android_dataspace_t& outDataspace); + sp<Fence>& outFence, ui::Dataspace& outDataspace); // mDisplayType must match one of the HWC display types int mDisplayType; @@ -76,7 +76,7 @@ private: // 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; + ui::Dataspace mDataSpace; // mCurrentBuffer is the current buffer or nullptr to indicate that there is // no current buffer. diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 47f4e46361..2686788ade 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -47,6 +47,9 @@ using android::hardware::Void; namespace HWC2 { namespace Hwc2 = android::Hwc2; +using android::ui::ColorMode; +using android::ui::Dataspace; +using android::ui::PixelFormat; namespace { @@ -114,14 +117,13 @@ uint32_t Device::getMaxVirtualDisplayCount() const } Error Device::createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, Display** outDisplay) + PixelFormat* format, Display** outDisplay) { ALOGI("Creating virtual display"); hwc2_display_t displayId = 0; - auto intFormat = static_cast<Hwc2::PixelFormat>(*format); auto intError = mComposer->createVirtualDisplay(width, height, - &intFormat, &displayId); + format, &displayId); auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -129,8 +131,8 @@ Error Device::createVirtualDisplay(uint32_t width, uint32_t height, auto display = std::make_unique<Display>( *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual); + display->setConnected(true); *outDisplay = display.get(); - *format = static_cast<android_pixel_format_t>(intFormat); mDisplays.emplace(displayId, std::move(display)); ALOGI("Created virtual display"); return Error::None; @@ -168,6 +170,7 @@ void Device::onHotplug(hwc2_display_t displayId, Connection connection) { auto newDisplay = std::make_unique<Display>( *mComposer.get(), mCapabilities, displayId, displayType); + newDisplay->setConnected(true); mDisplays.emplace(displayId, std::move(newDisplay)); } else if (connection == Connection::Disconnected) { // The display will later be destroyed by a call to @@ -209,16 +212,14 @@ Error Device::flushCommands() // Display methods 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(type) -{ + const std::unordered_set<Capability>& capabilities, hwc2_display_t id, + DisplayType type) + : mComposer(composer), + mCapabilities(capabilities), + mId(id), + mIsConnected(false), + mType(type) { ALOGV("Created display %" PRIu64, id); - setConnected(true); } Display::~Display() { @@ -362,21 +363,10 @@ Error Display::getChangedCompositionTypes( return Error::None; } -Error Display::getColorModes(std::vector<android::ColorMode>* outModes) const +Error Display::getColorModes(std::vector<ColorMode>* outModes) const { - std::vector<android::ColorMode> modes; - auto intError = mComposer.getColorModes(mId, &modes); - uint32_t numModes = modes.size(); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - return error; - } - - outModes->resize(numModes); - for (size_t i = 0; i < numModes; i++) { - (*outModes)[i] = modes[i]; - } - return Error::None; + auto intError = mComposer.getColorModes(mId, outModes); + return static_cast<Error>(intError); } std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const @@ -527,17 +517,16 @@ Error Display::setActiveConfig(const std::shared_ptr<const Config>& config) } Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target, - const sp<Fence>& acquireFence, android_dataspace_t dataspace) + const sp<Fence>& acquireFence, Dataspace dataspace) { // TODO: Properly encode client target surface damage int32_t fenceFd = acquireFence->dup(); auto intError = mComposer.setClientTarget(mId, slot, target, - fenceFd, static_cast<Hwc2::Dataspace>(dataspace), - std::vector<Hwc2::IComposerClient::Rect>()); + fenceFd, dataspace, std::vector<Hwc2::IComposerClient::Rect>()); return static_cast<Error>(intError); } -Error Display::setColorMode(android::ColorMode mode) +Error Display::setColorMode(ColorMode mode) { auto intError = mComposer.setColorMode(mId, mode); return static_cast<Error>(intError); @@ -776,14 +765,13 @@ Error Layer::setCompositionType(Composition type) return static_cast<Error>(intError); } -Error Layer::setDataspace(android_dataspace_t dataspace) +Error Layer::setDataspace(Dataspace dataspace) { if (dataspace == mDataSpace) { return Error::None; } mDataSpace = dataspace; - auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace); - auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace); + auto intError = mComposer.setLayerDataspace(mDisplayId, mId, mDataSpace); return static_cast<Error>(intError); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 0fc37ece56..9b870e3ed9 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -25,7 +25,7 @@ #include <gui/HdrMetadata.h> #include <math/mat4.h> -#include <ui/GraphicsTypes.h> +#include <ui/GraphicTypes.h> #include <ui/HdrCapabilities.h> #include <utils/Log.h> @@ -48,6 +48,8 @@ namespace android { namespace Hwc2 { class Composer; } + + class TestableSurfaceFlinger; } namespace HWC2 { @@ -94,7 +96,7 @@ public: uint32_t getMaxVirtualDisplayCount() const; Error createVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, Display** outDisplay); + android::ui::PixelFormat* format, Display** outDisplay); void destroyDisplay(hwc2_display_t displayId); void onHotplug(hwc2_display_t displayId, Connection connection); @@ -126,8 +128,7 @@ private: class Display { public: - Display(android::Hwc2::Composer& composer, - const std::unordered_set<Capability>& capabilities, + Display(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities, hwc2_display_t id, DisplayType type); ~Display(); @@ -210,7 +211,7 @@ public: [[clang::warn_unused_result]] Error getChangedCompositionTypes( std::unordered_map<Layer*, Composition>* outTypes); [[clang::warn_unused_result]] Error getColorModes( - std::vector<android::ColorMode>* outModes) const; + std::vector<android::ui::ColorMode>* outModes) const; // Doesn't call into the HWC2 device, so no errors are possible std::vector<std::shared_ptr<const Config>> getConfigs() const; @@ -233,8 +234,9 @@ public: [[clang::warn_unused_result]] Error setClientTarget( uint32_t slot, const android::sp<android::GraphicBuffer>& target, const android::sp<android::Fence>& acquireFence, - android_dataspace_t dataspace); - [[clang::warn_unused_result]] Error setColorMode(android::ColorMode mode); + android::ui::Dataspace dataspace); + [[clang::warn_unused_result]] Error setColorMode( + android::ui::ColorMode mode); [[clang::warn_unused_result]] Error setColorTransform( const android::mat4& matrix, android_color_transform_t hint); [[clang::warn_unused_result]] Error setOutputBuffer( @@ -245,8 +247,8 @@ public: [[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes, uint32_t* outNumRequests); [[clang::warn_unused_result]] Error presentOrValidate(uint32_t* outNumTypes, - uint32_t* outNumRequests, - android::sp<android::Fence>* outPresentFence, uint32_t* state); + uint32_t* outNumRequests, + android::sp<android::Fence>* outPresentFence, uint32_t* state); // Other Display methods @@ -263,6 +265,8 @@ private: // on this display Layer* getLayerById(hwc2_layer_t id) const; + friend android::TestableSurfaceFlinger; + // Member variables // These are references to data owned by HWC2::Device, which will outlive @@ -307,7 +311,7 @@ public: [[clang::warn_unused_result]] Error setColor(hwc_color_t color); [[clang::warn_unused_result]] Error setCompositionType(Composition type); [[clang::warn_unused_result]] Error setDataspace( - android_dataspace_t dataspace); + android::ui::Dataspace dataspace); [[clang::warn_unused_result]] Error setHdrMetadata(const android::HdrMetadata& metadata); [[clang::warn_unused_result]] Error setDisplayFrame( const android::Rect& frame); @@ -331,7 +335,7 @@ private: hwc2_display_t mDisplayId; hwc2_layer_t mId; - android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + android::ui::Dataspace mDataSpace = android::ui::Dataspace::UNKNOWN; android::HdrMetadata mHdrMetadata; std::function<void(Layer*)> mLayerDestroyedListener; }; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 6d5917db2f..29e2727b3e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -179,7 +179,7 @@ bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp, } status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, int32_t *outId) { + ui::PixelFormat* format, int32_t *outId) { if (mRemainingHwcVirtualDisplays == 0) { ALOGE("allocateVirtualDisplay: No remaining virtual displays"); return NO_MEMORY; @@ -311,8 +311,8 @@ std::shared_ptr<const HWC2::Display::Config> return config; } -std::vector<ColorMode> HWComposer::getColorModes(int32_t displayId) const { - std::vector<ColorMode> modes; +std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const { + std::vector<ui::ColorMode> modes; if (!isValidDisplay(displayId)) { ALOGE("getColorModes: Attempted to access invalid display %d", @@ -324,13 +324,13 @@ std::vector<ColorMode> HWComposer::getColorModes(int32_t displayId) const { if (error != HWC2::Error::None) { ALOGE("getColorModes failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast<int32_t>(error)); - return std::vector<ColorMode>(); + return std::vector<ui::ColorMode>(); } return modes; } -status_t HWComposer::setActiveColorMode(int32_t displayId, ColorMode mode) { +status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode) { if (!isValidDisplay(displayId)) { ALOGE("setActiveColorMode: Display %d is not valid", displayId); return BAD_INDEX; @@ -387,7 +387,7 @@ void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) { status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target, - android_dataspace_t dataspace) { + ui::Dataspace dataspace) { if (!isValidDisplay(displayId)) { return BAD_INDEX; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index c442b2f191..6e2e156abd 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -23,7 +23,7 @@ #include <sys/types.h> #include <ui/Fence.h> -#include <ui/GraphicsTypes.h> +#include <ui/GraphicTypes.h> #include <utils/BitSet.h> #include <utils/Condition.h> @@ -80,7 +80,7 @@ public: // Attempts to allocate a virtual display. If the virtual display is created // on the HWC device, outId will contain its HWC ID. status_t allocateVirtualDisplay(uint32_t width, uint32_t height, - android_pixel_format_t* format, int32_t* outId); + ui::PixelFormat* format, int32_t* outId); // Attempts to create a new layer on this display HWC2::Layer* createLayer(int32_t displayId); @@ -92,7 +92,7 @@ public: status_t setClientTarget(int32_t displayId, uint32_t slot, const sp<Fence>& acquireFence, - const sp<GraphicBuffer>& target, android_dataspace_t dataspace); + const sp<GraphicBuffer>& target, ui::Dataspace dataspace); // Present layers to the display and read releaseFences. status_t presentAndGetReleaseFences(int32_t displayId); @@ -159,9 +159,9 @@ public: std::shared_ptr<const HWC2::Display::Config> getActiveConfig(int32_t displayId) const; - std::vector<ColorMode> getColorModes(int32_t displayId) const; + std::vector<ui::ColorMode> getColorModes(int32_t displayId) const; - status_t setActiveColorMode(int32_t displayId, ColorMode mode); + status_t setActiveColorMode(int32_t displayId, ui::ColorMode mode); bool isUsingVrComposer() const; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 3480b24390..9a2817dba1 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -222,7 +222,7 @@ status_t VirtualDisplaySurface::advanceFrame() { // TODO: Correctly propagate the dataspace from GL composition result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence, - hwcBuffer, HAL_DATASPACE_UNKNOWN); + hwcBuffer, ui::Dataspace::UNKNOWN); } return result; diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp index ac54059360..fb6cff5705 100644 --- a/services/surfaceflinger/EventControlThread.cpp +++ b/services/surfaceflinger/EventControlThread.cpp @@ -26,6 +26,10 @@ namespace android { +EventControlThread::~EventControlThread() = default; + +namespace impl { + EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function) : mSetVSyncEnabled(function) { pthread_setname_np(mThread.native_handle(), "EventControlThread"); @@ -67,4 +71,5 @@ void EventControlThread::threadMain() NO_THREAD_SAFETY_ANALYSIS { } } +} // namespace impl } // namespace android diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h index 321fb79831..9be4e7cd8e 100644 --- a/services/surfaceflinger/EventControlThread.h +++ b/services/surfaceflinger/EventControlThread.h @@ -16,8 +16,8 @@ #pragma once -#include <cstddef> #include <condition_variable> +#include <cstddef> #include <functional> #include <mutex> #include <thread> @@ -30,12 +30,22 @@ class SurfaceFlinger; class EventControlThread { public: + virtual ~EventControlThread(); + + virtual void setVsyncEnabled(bool enabled) = 0; +}; + +namespace impl { + +class EventControlThread final : public android::EventControlThread { +public: using SetVSyncEnabledFunction = std::function<void(bool)>; explicit EventControlThread(SetVSyncEnabledFunction function); ~EventControlThread(); - void setVsyncEnabled(bool enabled); + // EventControlThread implementation + void setVsyncEnabled(bool enabled) override; private: void threadMain(); @@ -51,4 +61,5 @@ private: std::thread mThread{&EventControlThread::threadMain, this}; }; +} // namespace impl } // namespace android diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 1f4f5a53f4..bb9c0703ed 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -217,7 +217,7 @@ Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked( if (timestamp) { // we have a vsync event to dispatch if (mInterceptVSyncs) { - mFlinger.mInterceptor.saveVSyncEvent(timestamp); + mFlinger.mInterceptor->saveVSyncEvent(timestamp); } *event = mVSyncEvent[i]; mVSyncEvent[i].header.timestamp = 0; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2499a985b4..9d356d86c7 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -42,6 +42,7 @@ #include <gui/LayerDebugInfo.h> #include <gui/Surface.h> +#include "BufferLayer.h" #include "Colorizer.h" #include "DisplayDevice.h" #include "Layer.h" @@ -121,7 +122,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& n mCurrentState.layerStack = 0; mCurrentState.sequence = 0; mCurrentState.requested = mCurrentState.active; - mCurrentState.dataSpace = HAL_DATASPACE_UNKNOWN; + mCurrentState.dataSpace = ui::Dataspace::UNKNOWN; mCurrentState.appId = 0; mCurrentState.type = 0; @@ -628,19 +629,14 @@ void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z transform = Transform(invTransform) * tr * bufferOrientation; } - // STOPSHIP (b/72106793): If we have less than 25% scaling, HWC usually needs to use the rotator - // to handle it. However, there is one guaranteed frame of jank when we switch to using the - // rotator. In the meantime, we force GL composition instead until we have a better fix for the - // HWC issue. - bool extremeScaling = abs(t[0][0]) <= 0.25 || abs(t[1][1]) <= 0.25; - // this gives us only the "orientation" component of the transform const uint32_t orientation = transform.getOrientation(); - if (orientation & Transform::ROT_INVALID || extremeScaling) { + if (orientation & Transform::ROT_INVALID) { // we can only handle simple transformation hwcInfo.forceClientComposition = true; } else { auto transform = static_cast<HWC2::Transform>(orientation); + hwcInfo.transform = transform; auto error = hwcLayer->setTransform(transform); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set transform %s: " @@ -1331,7 +1327,7 @@ bool Layer::setLayerStack(uint32_t layerStack) { return true; } -bool Layer::setDataSpace(android_dataspace dataSpace) { +bool Layer::setDataSpace(ui::Dataspace dataSpace) { if (mCurrentState.dataSpace == dataSpace) return false; mCurrentState.sequence++; mCurrentState.dataSpace = dataSpace; @@ -1340,7 +1336,7 @@ bool Layer::setDataSpace(android_dataspace dataSpace) { return true; } -android_dataspace Layer::getDataSpace() const { +ui::Dataspace Layer::getDataSpace() const { return mCurrentState.dataSpace; } @@ -1436,7 +1432,7 @@ LayerDebugInfo Layer::getLayerDebugInfo() const { info.mColor = ds.color; info.mFlags = ds.flags; info.mPixelFormat = getPixelFormat(); - info.mDataSpace = getDataSpace(); + info.mDataSpace = static_cast<android_dataspace>(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]; @@ -1494,7 +1490,11 @@ void Layer::miniDump(String8& result, int32_t hwcId) const { const Layer::State& layerState(getDrawingState()); const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(hwcId); - result.appendFormat(" %10d | ", layerState.z); + if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) { + result.appendFormat(" rel %6d | ", layerState.z); + } else { + result.appendFormat(" %10d | ", layerState.z); + } result.appendFormat("%10s | ", to_string(getCompositionType(hwcId)).c_str()); const Rect& frame = hwcInfo.displayFrame; result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom); @@ -1895,7 +1895,7 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) layerInfo->set_is_opaque(isOpaque(state)); layerInfo->set_invalidate(contentDirty); - layerInfo->set_dataspace(dataspaceDetails(getDataSpace())); + layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace()))); layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); LayerProtoHelper::writeToProto(getColor(), layerInfo->mutable_color()); LayerProtoHelper::writeToProto(state.color, layerInfo->mutable_requested_color()); @@ -1925,6 +1925,31 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) layerInfo->set_app_id(state.appId); } +void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) { + writeToProto(layerInfo, LayerVector::StateSet::Drawing); + + const auto& hwcInfo = getBE().mHwcLayers.at(hwcId); + + const Rect& frame = hwcInfo.displayFrame; + LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame()); + + const FloatRect& crop = hwcInfo.sourceCrop; + LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop()); + + const int32_t transform = static_cast<int32_t>(hwcInfo.transform); + layerInfo->set_hwc_transform(transform); + + const int32_t compositionType = static_cast<int32_t>(hwcInfo.compositionType); + layerInfo->set_hwc_composition_type(compositionType); + + if (std::strcmp(getTypeId(), "BufferLayer") == 0 && + static_cast<BufferLayer*>(this)->isProtected()) { + layerInfo->set_is_protected(true); + } else { + layerInfo->set_is_protected(false); + } +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 206fff39c0..8d2a0488dc 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -66,6 +66,10 @@ class SurfaceFlinger; class LayerDebugInfo; class LayerBE; +namespace impl { +class SurfaceInterceptor; +} + // --------------------------------------------------------------------------- struct CompositionInfo { @@ -109,7 +113,8 @@ public: layer(nullptr), forceClientComposition(false), compositionType(HWC2::Composition::Invalid), - clearClientTarget(false) {} + clearClientTarget(false), + transform(HWC2::Transform::None) {} HWComposer* hwc; HWC2::Layer* layer; @@ -119,6 +124,7 @@ public: Rect displayFrame; FloatRect sourceCrop; HWComposerBufferCache bufferCache; + HWC2::Transform transform; }; // A layer can be attached to multiple displays when operating in mirror mode @@ -201,7 +207,7 @@ public: // dependent. Region activeTransparentRegion; Region requestedTransparentRegion; - android_dataspace dataSpace; + ui::Dataspace dataSpace; int32_t appId; int32_t type; @@ -279,8 +285,8 @@ public: bool setTransparentRegionHint(const Region& transparent); bool setFlags(uint8_t flags, uint8_t mask); bool setLayerStack(uint32_t layerStack); - bool setDataSpace(android_dataspace dataSpace); - android_dataspace getDataSpace() const; + bool setDataSpace(ui::Dataspace dataSpace); + ui::Dataspace getDataSpace() const; uint32_t getLayerStack() const; void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber); void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber); @@ -353,6 +359,8 @@ public: void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing); + void writeToProto(LayerProto* layerInfo, int32_t hwcId); + protected: /* * onDraw - draws the surface. @@ -593,7 +601,7 @@ protected: virtual void onFirstRef(); - friend class SurfaceInterceptor; + friend class impl::SurfaceInterceptor; void commitTransaction(const State& stateToCommit); diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 6a33148d27..cc3955087a 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -37,6 +37,13 @@ void LayerProtoHelper::writeToProto(const Rect& rect, RectProto* rectProto) { rectProto->set_right(rect.right); } +void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) { + rectProto->set_left(rect.left); + rectProto->set_top(rect.top); + rectProto->set_bottom(rect.bottom); + rectProto->set_right(rect.right); +} + void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) { colorProto->set_r(color.r); colorProto->set_g(color.g); diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index 45a0b5d173..860da63ed2 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -29,6 +29,7 @@ namespace surfaceflinger { class LayerProtoHelper { public: static void writeToProto(const Rect& rect, RectProto* rectProto); + static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto); static void writeToProto(const Region& region, RegionProto* regionProto); static void writeToProto(const half4 color, ColorProto* colorProto); static void writeToProto(const Transform& transform, TransformProto* transformProto); @@ -36,4 +37,4 @@ public: }; } // namespace surfaceflinger -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp new file mode 100644 index 0000000000..38ea6edfc5 --- /dev/null +++ b/services/surfaceflinger/LayerStats.cpp @@ -0,0 +1,232 @@ +/* + * Copyright 2018 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. + */ +#undef LOG_TAG +#define LOG_TAG "LayerStats" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "LayerStats.h" +#include "DisplayHardware/HWComposer.h" +#include "ui/DebugUtils.h" + +#include <android-base/stringprintf.h> +#include <log/log.h> +#include <utils/String8.h> +#include <utils/Trace.h> + +namespace android { + +void LayerStats::enable() { + ATRACE_CALL(); + std::lock_guard<std::mutex> lock(mMutex); + if (mEnabled) return; + mLayerShapeStatsMap.clear(); + mEnabled = true; + ALOGD("Logging enabled"); +} + +void LayerStats::disable() { + ATRACE_CALL(); + std::lock_guard<std::mutex> lock(mMutex); + if (!mEnabled) return; + mEnabled = false; + ALOGD("Logging disabled"); +} + +void LayerStats::clear() { + ATRACE_CALL(); + std::lock_guard<std::mutex> lock(mMutex); + mLayerShapeStatsMap.clear(); + ALOGD("Cleared current layer stats"); +} + +bool LayerStats::isEnabled() { + return mEnabled; +} + +void LayerStats::traverseLayerTreeStatsLocked( + std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree, + const LayerProtoParser::LayerGlobal* layerGlobal, std::vector<std::string>& layerShapeVec) { + for (std::unique_ptr<LayerProtoParser::Layer>& layer : layerTree) { + if (!layer) continue; + traverseLayerTreeStatsLocked(std::move(layer->children), layerGlobal, layerShapeVec); + std::string key = ""; + base::StringAppendF(&key, ",%s", layer->type.c_str()); + base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType)); + base::StringAppendF(&key, ",%d", layer->isProtected); + base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform)); + base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format)); + base::StringAppendF(&key, ",%s", layer->dataspace.c_str()); + base::StringAppendF(&key, ",%s", + destinationLocation(layer->hwcFrame.left, layerGlobal->resolution[0], + true)); + base::StringAppendF(&key, ",%s", + destinationLocation(layer->hwcFrame.top, layerGlobal->resolution[1], + false)); + base::StringAppendF(&key, ",%s", + destinationSize(layer->hwcFrame.right - layer->hwcFrame.left, + layerGlobal->resolution[0], true)); + base::StringAppendF(&key, ",%s", + destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top, + layerGlobal->resolution[1], false)); + base::StringAppendF(&key, ",%s", scaleRatioWH(layer.get()).c_str()); + base::StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a))); + + layerShapeVec.push_back(key); + ALOGV("%s", key.c_str()); + } +} + +void LayerStats::logLayerStats(const LayersProto& layersProto) { + ATRACE_CALL(); + ALOGV("Logging"); + auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto); + auto layerTree = LayerProtoParser::generateLayerTree(layersProto); + std::vector<std::string> layerShapeVec; + + std::lock_guard<std::mutex> lock(mMutex); + traverseLayerTreeStatsLocked(std::move(layerTree), &layerGlobal, layerShapeVec); + + std::string layerShapeKey = + base::StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()), + layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(), + layerTransform(layerGlobal.globalTransform)); + ALOGV("%s", layerShapeKey.c_str()); + + std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>()); + for (auto const& s : layerShapeVec) { + layerShapeKey += s; + } + + mLayerShapeStatsMap[layerShapeKey]++; +} + +void LayerStats::dump(String8& result) { + ATRACE_CALL(); + ALOGD("Dumping"); + std::lock_guard<std::mutex> lock(mMutex); + result.append("Frequency,LayerCount,ColorMode,ColorTransform,Orientation\n"); + result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,"); + result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n"); + for (auto& u : mLayerShapeStatsMap) { + result.appendFormat("%u,%s\n", u.second, u.first.c_str()); + } +} + +const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) { + static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"}; + int32_t ratio = location * 8 / range; + if (ratio < 0) return "N/A"; + if (isHorizontal) { + // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"} + if (ratio > 6) return "3/4"; + // use index 0, 2, 4, 6 + return locationArray[ratio & ~1]; + } + if (ratio > 7) return "7/8"; + return locationArray[ratio]; +} + +const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) { + static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"}; + int32_t ratio = size * 8 / range; + if (ratio < 0) return "N/A"; + if (isWidth) { + // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"} + if (ratio > 6) return "1"; + // use index 1, 3, 5, 7 + return sizeArray[ratio | 1]; + } + if (ratio > 7) return "1"; + return sizeArray[ratio]; +} + +const char* LayerStats::layerTransform(int32_t transform) { + return getTransformName(static_cast<hwc_transform_t>(transform)); +} + +const char* LayerStats::layerCompositionType(int32_t compositionType) { + return getCompositionName(static_cast<hwc2_composition_t>(compositionType)); +} + +const char* LayerStats::layerPixelFormat(int32_t pixelFormat) { + return decodePixelFormat(pixelFormat).c_str(); +} + +std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) { + if (!layer->type.compare("ColorLayer")) return "N/A,N/A"; + std::string ret = ""; + if (isRotated(layer->hwcTransform)) { + ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left, + static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top)); + ret += ","; + ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top, + static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left)); + } else { + ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left, + static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left)); + ret += ","; + ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top, + static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top)); + } + return ret; +} + +const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) { + // Make scale buckets from <1/64 to >= 16, to avoid floating point + // calculation, x64 on destinationScale first + int32_t scale = destinationScale * 64 / sourceScale; + if (!scale) return "<1/64"; + if (scale < 2) return "1/64"; + if (scale < 4) return "1/32"; + if (scale < 8) return "1/16"; + if (scale < 16) return "1/8"; + if (scale < 32) return "1/4"; + if (scale < 64) return "1/2"; + if (scale < 128) return "1"; + if (scale < 256) return "2"; + if (scale < 512) return "4"; + if (scale < 1024) return "8"; + return ">=16"; +} + +const char* LayerStats::alpha(float a) { + if (a == 1.0f) return "1.0"; + if (a > 0.9f) return "0.99"; + if (a > 0.8f) return "0.9"; + if (a > 0.7f) return "0.8"; + if (a > 0.6f) return "0.7"; + if (a > 0.5f) return "0.6"; + if (a > 0.4f) return "0.5"; + if (a > 0.3f) return "0.4"; + if (a > 0.2f) return "0.3"; + if (a > 0.1f) return "0.2"; + if (a > 0.0f) return "0.1"; + return "0.0"; +} + +bool LayerStats::isRotated(int32_t transform) { + return transform & HWC_TRANSFORM_ROT_90; +} + +bool LayerStats::isVFlipped(int32_t transform) { + return transform & HWC_TRANSFORM_FLIP_V; +} + +bool LayerStats::isHFlipped(int32_t transform) { + return transform & HWC_TRANSFORM_FLIP_H; +} + +} // namespace android diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h new file mode 100644 index 0000000000..7871fc6602 --- /dev/null +++ b/services/surfaceflinger/LayerStats.h @@ -0,0 +1,76 @@ +/* + * Copyright 2018 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 <layerproto/LayerProtoHeader.h> +#include <layerproto/LayerProtoParser.h> +#include <mutex> +#include <unordered_map> + +using namespace android::surfaceflinger; + +namespace android { +class String8; + +class LayerStats { +public: + void enable(); + void disable(); + void clear(); + bool isEnabled(); + void logLayerStats(const LayersProto& layersProto); + void dump(String8& result); + +private: + // Traverse layer tree to get all visible layers' stats + void traverseLayerTreeStatsLocked( + std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree, + const LayerProtoParser::LayerGlobal* layerGlobal, + std::vector<std::string>& layerShapeVec); + // Convert layer's top-left position into 8x8 percentage of the display + static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal); + // Convert layer's size into 8x8 percentage of the display + static const char* destinationSize(int32_t size, int32_t range, bool isWidth); + // Return the name of the transform + static const char* layerTransform(int32_t transform); + // Return the name of the composition type + static const char* layerCompositionType(int32_t compositionType); + // Return the name of the pixel format + static const char* layerPixelFormat(int32_t pixelFormat); + // Calculate scale ratios of layer's width/height with rotation information + static std::string scaleRatioWH(const LayerProtoParser::Layer* layer); + // Calculate scale ratio from source to destination and convert to string + static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale); + // Bucket the alpha into designed buckets + static const char* alpha(float a); + // Return whether the original buffer is rotated in final composition + static bool isRotated(int32_t transform); + // Return whether the original buffer is V-flipped in final composition + static bool isVFlipped(int32_t transform); + // Return whether the original buffer is H-flipped in final composition + static bool isHFlipped(int32_t transform); + + bool mEnabled = false; + // Protect mLayersStatsMap + std::mutex mMutex; + // Hashmap for tracking the frame(layer shape) stats + // KEY is a concatenation of all layers' properties within a frame + // VALUE is the number of times this particular set has been scanned out + std::unordered_map<std::string, uint32_t> mLayerShapeStatsMap; +}; + +} // namespace android diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp index 5a6ff4dd98..056d381eb9 100644 --- a/services/surfaceflinger/MessageQueue.cpp +++ b/services/surfaceflinger/MessageQueue.cpp @@ -24,6 +24,7 @@ #include <utils/Timers.h> #include <utils/threads.h> +#include <gui/DisplayEventReceiver.h> #include <gui/IDisplayEventConnection.h> #include "EventThread.h" @@ -45,6 +46,12 @@ void MessageBase::handleMessage(const Message&) { // --------------------------------------------------------------------------- +MessageQueue::~MessageQueue() = default; + +// --------------------------------------------------------------------------- + +namespace impl { + void MessageQueue::Handler::dispatchRefresh() { if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH)); @@ -72,17 +79,13 @@ void MessageQueue::Handler::handleMessage(const Message& message) { // --------------------------------------------------------------------------- -MessageQueue::MessageQueue() {} - -MessageQueue::~MessageQueue() {} - void MessageQueue::init(const sp<SurfaceFlinger>& flinger) { mFlinger = flinger; mLooper = new Looper(true); mHandler = new Handler(*this); } -void MessageQueue::setEventThread(EventThread* eventThread) { +void MessageQueue::setEventThread(android::EventThread* eventThread) { if (mEventThread == eventThread) { return; } @@ -159,4 +162,5 @@ int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) { // --------------------------------------------------------------------------- -}; // namespace android +} // namespace impl +} // namespace android diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h index dcfc716524..90d1c72450 100644 --- a/services/surfaceflinger/MessageQueue.h +++ b/services/surfaceflinger/MessageQueue.h @@ -25,7 +25,7 @@ #include <utils/Timers.h> #include <utils/threads.h> -#include <gui/DisplayEventReceiver.h> +#include <gui/IDisplayEventConnection.h> #include <private/gui/BitTube.h> #include "Barrier.h" @@ -34,7 +34,6 @@ namespace android { -class IDisplayEventConnection; class EventThread; class SurfaceFlinger; @@ -77,6 +76,27 @@ private: // --------------------------------------------------------------------------- class MessageQueue { +public: + enum { + INVALIDATE = 0, + REFRESH = 1, + }; + + virtual ~MessageQueue(); + + virtual void init(const sp<SurfaceFlinger>& flinger) = 0; + virtual void setEventThread(EventThread* events) = 0; + virtual void waitMessage() = 0; + virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0; + virtual void invalidate() = 0; + virtual void refresh() = 0; +}; + +// --------------------------------------------------------------------------- + +namespace impl { + +class MessageQueue final : public android::MessageQueue { class Handler : public MessageHandler { enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 }; MessageQueue& mQueue; @@ -93,7 +113,7 @@ class MessageQueue { sp<SurfaceFlinger> mFlinger; sp<Looper> mLooper; - EventThread* mEventThread; + android::EventThread* mEventThread; sp<IDisplayEventConnection> mEvents; gui::BitTube mEventTube; sp<Handler> mHandler; @@ -102,27 +122,22 @@ class MessageQueue { int eventReceiver(int fd, int events); public: - enum { - INVALIDATE = 0, - REFRESH = 1, - }; - - MessageQueue(); - ~MessageQueue(); - void init(const sp<SurfaceFlinger>& flinger); - void setEventThread(EventThread* events); + ~MessageQueue() override = default; + void init(const sp<SurfaceFlinger>& flinger) override; + void setEventThread(android::EventThread* events) override; - void waitMessage(); - status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0); + void waitMessage() override; + status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) override; // sends INVALIDATE message at next VSYNC - void invalidate(); + void invalidate() override; // sends REFRESH message at next VSYNC - void refresh(); + void refresh() override; }; // --------------------------------------------------------------------------- -}; // namespace android +} // namespace impl +} // namespace android #endif /* ANDROID_MESSAGE_QUEUE_H */ diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h index b9c4909d5a..bf0707f13b 100644 --- a/services/surfaceflinger/RenderArea.h +++ b/services/surfaceflinger/RenderArea.h @@ -1,6 +1,6 @@ #pragma once -#include <ui/GraphicsTypes.h> +#include <ui/GraphicTypes.h> #include "Transform.h" @@ -32,7 +32,7 @@ public: int getReqWidth() const { return mReqWidth; }; Transform::orientation_flags getRotationFlags() const { return mRotationFlags; }; virtual bool getWideColorSupport() const = 0; - virtual ColorMode getActiveColorMode() const = 0; + virtual ui::ColorMode getActiveColorMode() const = 0; status_t updateDimensions(); diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index ea7dc2f1fd..1eda900f47 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -109,6 +109,8 @@ namespace RE { namespace impl { // --------------------------------------------------------------------------- +using ui::Dataspace; + GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) : mVpWidth(0), mVpHeight(0), mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); @@ -214,11 +216,11 @@ void GLES20RenderEngine::setSourceY410BT2020(bool enable) { mState.setY410BT2020(enable); } -void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) { +void GLES20RenderEngine::setSourceDataSpace(Dataspace source) { mDataSpace = source; } -void GLES20RenderEngine::setOutputDataSpace(android_dataspace dataspace) { +void GLES20RenderEngine::setOutputDataSpace(Dataspace dataspace) { mOutputDataSpace = dataspace; } @@ -301,14 +303,14 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { mesh.getByteStride(), mesh.getPositions()); // DISPLAY_P3 is the only supported wide color output - if (mPlatformHasWideColor && mOutputDataSpace == HAL_DATASPACE_DISPLAY_P3) { + if (mPlatformHasWideColor && mOutputDataSpace == Dataspace::DISPLAY_P3) { Description wideColorState = mState; - switch (int(mDataSpace)) { - case HAL_DATASPACE_DISPLAY_P3: + switch (mDataSpace) { + case Dataspace::DISPLAY_P3: // input matches output break; - case HAL_DATASPACE_BT2020_PQ: - case HAL_DATASPACE_BT2020_ITU_PQ: + case Dataspace::BT2020_PQ: + case Dataspace::BT2020_ITU_PQ: wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3); wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084); wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB); @@ -317,7 +319,7 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { default: // treat all other dataspaces as sRGB wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3); - if ((mDataSpace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_LINEAR) { + if ((mDataSpace & Dataspace::TRANSFER_MASK) & Dataspace::TRANSFER_LINEAR) { wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR); } else { wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB); @@ -350,8 +352,8 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { void GLES20RenderEngine::dump(String8& result) { RenderEngine::dump(result); result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n", - dataspaceDetails(mDataSpace).c_str(), - dataspaceDetails(mOutputDataSpace).c_str()); + dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(), + dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str()); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index db3f79281e..99da19d6b1 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -73,14 +73,14 @@ protected: // Color management related functions and state void setSourceY410BT2020(bool enable) override; - void setSourceDataSpace(android_dataspace source) override; - void setOutputDataSpace(android_dataspace dataspace) override; + void setSourceDataSpace(ui::Dataspace source) override; + void setOutputDataSpace(ui::Dataspace dataspace) override; // Current dataspace of layer being rendered - android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; + ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN; // Current output dataspace of the render engine - android_dataspace mOutputDataSpace = HAL_DATASPACE_UNKNOWN; + ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN; // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces const bool mPlatformHasWideColor = false; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index d1405740e6..f78b230778 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -119,8 +119,8 @@ public: // wide color support virtual void setSourceY410BT2020(bool enable) = 0; - virtual void setSourceDataSpace(android_dataspace source) = 0; - virtual void setOutputDataSpace(android_dataspace dataspace) = 0; + virtual void setSourceDataSpace(ui::Dataspace source) = 0; + virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0; // drawing virtual void drawMesh(const Mesh& mesh) = 0; diff --git a/services/surfaceflinger/RenderEngine/Surface.cpp b/services/surfaceflinger/RenderEngine/Surface.cpp index 3c29e4b2ea..0d20f1fd87 100644 --- a/services/surfaceflinger/RenderEngine/Surface.cpp +++ b/services/surfaceflinger/RenderEngine/Surface.cpp @@ -66,7 +66,7 @@ void Surface::swapBuffers() const { EGLint Surface::queryConfig(EGLint attrib) const { EGLint value; - if (!eglGetConfigAttrib(mEGLConfig, mEGLConfig, attrib, &value)) { + if (!eglGetConfigAttrib(mEGLDisplay, mEGLConfig, attrib, &value)) { value = 0; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7201f19632..bf76ef5d3e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -104,6 +104,8 @@ namespace android { using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +using ui::ColorMode; +using ui::Dataspace; namespace { class ConditionalLock { @@ -154,6 +156,32 @@ bool useTrebleTestingOverride() { return std::string(value) == "true"; } +NativeWindowSurface::~NativeWindowSurface() = default; + +namespace impl { + +class NativeWindowSurface final : public android::NativeWindowSurface { +public: + static std::unique_ptr<android::NativeWindowSurface> create( + const sp<IGraphicBufferProducer>& producer) { + return std::make_unique<NativeWindowSurface>(producer); + } + + explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer) + : surface(new Surface(producer, false)) {} + + ~NativeWindowSurface() override = default; + +private: + sp<ANativeWindow> getNativeWindow() const override { return surface; } + + void preallocateBuffers() override { surface->allocateBuffers(); } + + sp<Surface> surface; +}; + +} // namespace impl + SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()), mRenderEngine(nullptr), @@ -163,7 +191,7 @@ SurfaceFlingerBE::SurfaceFlingerBE() mComposerSequenceId(0) { } -SurfaceFlinger::SurfaceFlinger() +SurfaceFlinger::SurfaceFlinger(SurfaceFlinger::SkipInitializationTag) : BnSurfaceComposer(), mTransactionFlags(0), mTransactionPending(false), @@ -186,7 +214,6 @@ SurfaceFlinger::SurfaceFlinger() mLastTransactionTime(0), mBootFinished(false), mForceFullDamage(false), - mInterceptor(this), mPrimaryDispSync("PrimaryDispSync"), mPrimaryHWVsyncEnabled(false), mHWVsyncAvailable(false), @@ -195,7 +222,10 @@ SurfaceFlinger::SurfaceFlinger() mNumLayers(0), mVrFlingerRequestsDisplay(false), mMainThreadId(std::this_thread::get_id()), - mCreateBufferQueue(&BufferQueue::createBufferQueue) { + mCreateBufferQueue(&BufferQueue::createBufferQueue), + mCreateNativeWindowSurface(&impl::NativeWindowSurface::create) {} + +SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) { ALOGI("SurfaceFlinger is starting"); vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs, @@ -282,7 +312,7 @@ SurfaceFlinger::SurfaceFlinger() void SurfaceFlinger::onFirstRef() { - mEventQueue.init(this); + mEventQueue->init(this); } SurfaceFlinger::~SurfaceFlinger() @@ -348,7 +378,7 @@ sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure); info.displayName = displayName; mCurrentState.displays.add(token, info); - mInterceptor.saveDisplayCreation(info); + mInterceptor->saveDisplayCreation(info); return token; } @@ -366,7 +396,7 @@ void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) { ALOGE("destroyDisplay called for non-virtual display"); return; } - mInterceptor.saveDisplayDeletion(info.displayId); + mInterceptor->saveDisplayDeletion(info.displayId); mCurrentState.displays.removeItemsAt(idx); setTransactionFlags(eDisplayTransactionNeeded); } @@ -588,9 +618,10 @@ void SurfaceFlinger::init() { mSfEventThreadSource = std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf"); + mSFEventThread = std::make_unique<impl::EventThread>(mSfEventThreadSource.get(), *this, true, "sfEventThread"); - mEventQueue.setEventThread(mSFEventThread.get()); + mEventQueue->setEventThread(mSFEventThread.get()); // Get a RenderEngine for the given display / config (can't fail) getBE().mRenderEngine = @@ -637,9 +668,8 @@ void SurfaceFlinger::init() { } } - mEventControlThread = std::make_unique<EventControlThread>([this](bool enabled) { - setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); - }); + mEventControlThread = std::make_unique<impl::EventControlThread>( + [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); }); // initialize our drawing state mDrawingState = mCurrentState; @@ -1079,10 +1109,10 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { std::make_unique<impl::EventThread>(mVSyncInjector.get(), *this, false, "injEventThread"); } - mEventQueue.setEventThread(mInjectorEventThread.get()); + mEventQueue->setEventThread(mInjectorEventThread.get()); } else { ALOGV("VSync Injections disabled"); - mEventQueue.setEventThread(mSFEventThread.get()); + mEventQueue->setEventThread(mSFEventThread.get()); } mInjectVSyncs = enable; @@ -1147,30 +1177,30 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( // ---------------------------------------------------------------------------- void SurfaceFlinger::waitForEvent() { - mEventQueue.waitMessage(); + mEventQueue->waitMessage(); } void SurfaceFlinger::signalTransaction() { - mEventQueue.invalidate(); + mEventQueue->invalidate(); } void SurfaceFlinger::signalLayerUpdate() { - mEventQueue.invalidate(); + mEventQueue->invalidate(); } void SurfaceFlinger::signalRefresh() { mRefreshPending = true; - mEventQueue.refresh(); + mEventQueue->refresh(); } status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime, uint32_t /* flags */) { - return mEventQueue.postMessage(msg, reltime); + return mEventQueue->postMessage(msg, reltime); } status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime, uint32_t /* flags */) { - status_t res = mEventQueue.postMessage(msg, reltime); + status_t res = mEventQueue->postMessage(msg, reltime); if (res == NO_ERROR) { msg->wait(); } @@ -1455,6 +1485,7 @@ void SurfaceFlinger::handleMessageRefresh() { setUpHWComposer(); doDebugFlashRegions(); doTracing("handleRefresh"); + logLayerStats(); doComposition(); postComposition(refreshStartTime); @@ -1524,6 +1555,25 @@ void SurfaceFlinger::doTracing(const char* where) { } } +void SurfaceFlinger::logLayerStats() { + ATRACE_CALL(); + if (CC_UNLIKELY(mLayerStats.isEnabled())) { + int32_t hwcId = -1; + for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) { + const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]); + if (displayDevice->isPrimary()) { + hwcId = displayDevice->getHwcDisplayId(); + break; + } + } + if (hwcId < 0) { + ALOGE("LayerStats: Hmmm, no primary display?"); + return; + } + mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId)); + } +} + void SurfaceFlinger::preComposition(nsecs_t refreshStartTime) { ATRACE_CALL(); @@ -1788,7 +1838,7 @@ mat4 SurfaceFlinger::computeSaturationMatrix() const { // pickColorMode translates a given dataspace into the best available color mode. // Currently only support sRGB and Display-P3. -ColorMode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const { +ColorMode SurfaceFlinger::pickColorMode(Dataspace dataSpace) const { if (mForceNativeColorMode) { return ColorMode::NATIVE; } @@ -1796,47 +1846,48 @@ ColorMode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const { switch (dataSpace) { // treat Unknown as regular SRGB buffer, since that's what the rest of the // system expects. - case HAL_DATASPACE_UNKNOWN: - case HAL_DATASPACE_SRGB: - case HAL_DATASPACE_V0_SRGB: + case Dataspace::UNKNOWN: + case Dataspace::SRGB: + case Dataspace::V0_SRGB: return ColorMode::SRGB; break; - case HAL_DATASPACE_DISPLAY_P3: + case Dataspace::DISPLAY_P3: return ColorMode::DISPLAY_P3; break; default: // TODO (courtneygo): Do we want to assert an error here? - ALOGE("No color mode mapping for %s (%#x)", dataspaceDetails(dataSpace).c_str(), + ALOGE("No color mode mapping for %s (%#x)", + dataspaceDetails(static_cast<android_dataspace>(dataSpace)).c_str(), dataSpace); return ColorMode::SRGB; break; } } -android_dataspace SurfaceFlinger::bestTargetDataSpace( - android_dataspace a, android_dataspace b, bool hasHdr) const { +Dataspace SurfaceFlinger::bestTargetDataSpace( + Dataspace a, Dataspace b, bool hasHdr) const { // Only support sRGB and Display-P3 right now. - if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) { - return HAL_DATASPACE_DISPLAY_P3; + if (a == Dataspace::DISPLAY_P3 || b == Dataspace::DISPLAY_P3) { + return Dataspace::DISPLAY_P3; } - if (a == HAL_DATASPACE_V0_SCRGB_LINEAR || b == HAL_DATASPACE_V0_SCRGB_LINEAR) { - return HAL_DATASPACE_DISPLAY_P3; + if (a == Dataspace::V0_SCRGB_LINEAR || b == Dataspace::V0_SCRGB_LINEAR) { + return Dataspace::DISPLAY_P3; } - if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) { - return HAL_DATASPACE_DISPLAY_P3; + if (a == Dataspace::V0_SCRGB || b == Dataspace::V0_SCRGB) { + return Dataspace::DISPLAY_P3; } if (!hasHdr) { - if (a == HAL_DATASPACE_BT2020_PQ || b == HAL_DATASPACE_BT2020_PQ) { - return HAL_DATASPACE_DISPLAY_P3; + if (a == Dataspace::BT2020_PQ || b == Dataspace::BT2020_PQ) { + return Dataspace::DISPLAY_P3; } - if (a == HAL_DATASPACE_BT2020_ITU_PQ || b == HAL_DATASPACE_BT2020_ITU_PQ) { - return HAL_DATASPACE_DISPLAY_P3; + if (a == Dataspace::BT2020_ITU_PQ || b == Dataspace::BT2020_ITU_PQ) { + return Dataspace::DISPLAY_P3; } } - return HAL_DATASPACE_V0_SRGB; + return Dataspace::V0_SRGB; } void SurfaceFlinger::setUpHWComposer() { @@ -1911,13 +1962,14 @@ void SurfaceFlinger::setUpHWComposer() { continue; } if (colorMatrix != mPreviousColorMatrix) { + displayDevice->setColorTransform(colorMatrix); status_t result = getBE().mHwc->setColorTransform(hwcId, colorMatrix); ALOGE_IF(result != NO_ERROR, "Failed to set color transform on " "display %zd: %d", displayId, result); } for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - if ((layer->getDataSpace() == HAL_DATASPACE_BT2020_PQ || - layer->getDataSpace() == HAL_DATASPACE_BT2020_ITU_PQ) && + if ((layer->getDataSpace() == Dataspace::BT2020_PQ || + layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) && !displayDevice->getHdrSupport()) { layer->forceClientComposition(hwcId); } @@ -1933,14 +1985,14 @@ void SurfaceFlinger::setUpHWComposer() { if (hasWideColorDisplay) { ColorMode newColorMode; - android_dataspace newDataSpace = HAL_DATASPACE_V0_SRGB; + Dataspace newDataSpace = Dataspace::V0_SRGB; for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace, displayDevice->getHdrSupport()); ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)", - layer->getName().string(), dataspaceDetails(layer->getDataSpace()).c_str(), - layer->getDataSpace(), dataspaceDetails(newDataSpace).c_str(), newDataSpace); + layer->getName().string(), dataspaceDetails(static_cast<android_dataspace>(layer->getDataSpace())).c_str(), + layer->getDataSpace(), dataspaceDetails(static_cast<android_dataspace>(newDataSpace)).c_str(), newDataSpace); } newColorMode = pickColorMode(newDataSpace); @@ -2079,7 +2131,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) } DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t display, - HWC2::Connection connection) const { + HWC2::Connection connection) const { // Figure out whether the event is for the primary display or an // external display by matching the Hwc display id against one for a // connected display. If we did not find a match, we then check what @@ -2128,7 +2180,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ? "Built-in Screen" : "External Screen"; mCurrentState.displays.add(mBuiltinDisplays[displayType], info); - mInterceptor.saveDisplayCreation(info); + mInterceptor->saveDisplayCreation(info); } } else { ALOGV("Removing built in display %d", displayType); @@ -2136,7 +2188,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { ssize_t idx = mCurrentState.displays.indexOfKey(mBuiltinDisplays[displayType]); if (idx >= 0) { const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx)); - mInterceptor.saveDisplayDeletion(info.displayId); + mInterceptor->saveDisplayDeletion(info.displayId); mCurrentState.displays.removeItemsAt(idx); } mBuiltinDisplays[displayType].clear(); @@ -2148,6 +2200,84 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { mPendingHotplugEvents.clear(); } +sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( + const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state, + const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) { + bool hasWideColorSupport = false; + if (hasWideColorDisplay) { + std::vector<ColorMode> modes = getHwComposer().getColorModes(state.type); + for (ColorMode colorMode : modes) { + switch (colorMode) { + case ColorMode::DISPLAY_P3: + case ColorMode::ADOBE_RGB: + case ColorMode::DCI_P3: + hasWideColorSupport = true; + break; + default: + break; + } + } + } + + bool hasHdrSupport = false; + std::unique_ptr<HdrCapabilities> hdrCapabilities = + getHwComposer().getHdrCapabilities(state.type); + if (hdrCapabilities) { + const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes(); + auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10); + hasHdrSupport = iter != types.cend(); + } + + auto nativeWindowSurface = mCreateNativeWindowSurface(producer); + auto nativeWindow = nativeWindowSurface->getNativeWindow(); + + /* + * Create our display's surface + */ + std::unique_ptr<RE::Surface> renderSurface = getRenderEngine().createSurface(); + renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY); + renderSurface->setAsync(state.type >= DisplayDevice::DISPLAY_VIRTUAL); + renderSurface->setNativeWindow(nativeWindow.get()); + const int displayWidth = renderSurface->queryWidth(); + const int displayHeight = renderSurface->queryHeight(); + + // Make sure that composition can never be stalled by a virtual display + // consumer that isn't processing buffers fast enough. We have to do this + // in two places: + // * Here, in case the display is composed entirely by HWC. + // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the + // window's swap interval in eglMakeCurrent, so they'll override the + // interval we set here. + if (state.type >= DisplayDevice::DISPLAY_VIRTUAL) { + nativeWindow->setSwapInterval(nativeWindow.get(), 0); + } + + // virtual displays are always considered enabled + auto initialPowerMode = (state.type >= DisplayDevice::DISPLAY_VIRTUAL) ? HWC_POWER_MODE_NORMAL + : HWC_POWER_MODE_OFF; + + sp<DisplayDevice> hw = + new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow, + dispSurface, std::move(renderSurface), displayWidth, displayHeight, + hasWideColorSupport, hasHdrSupport, initialPowerMode); + + if (maxFrameBufferAcquiredBuffers >= 3) { + nativeWindowSurface->preallocateBuffers(); + } + + ColorMode defaultColorMode = ColorMode::NATIVE; + if (hasWideColorSupport) { + defaultColorMode = ColorMode::SRGB; + } + setActiveColorModeInternal(hw, defaultColorMode); + hw->setCompositionDataSpace(Dataspace::UNKNOWN); + hw->setLayerStack(state.layerStack); + hw->setProjection(state.orientation, state.viewport, state.frame); + hw->setDisplayName(state.displayName); + + return hw; +} + void SurfaceFlinger::processDisplayChangesLocked() { // here we take advantage of Vector's copy-on-write semantics to // improve performance by skipping the transaction entirely when @@ -2243,7 +2373,7 @@ void SurfaceFlinger::processDisplayChangesLocked() { int intFormat = 0; status = state.surface->query(NATIVE_WINDOW_FORMAT, &intFormat); ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); - auto format = static_cast<android_pixel_format_t>(intFormat); + auto format = static_cast<ui::PixelFormat>(intFormat); getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId); } @@ -2270,50 +2400,10 @@ void SurfaceFlinger::processDisplayChangesLocked() { } const wp<IBinder>& display(curr.keyAt(i)); - if (dispSurface != nullptr) { - bool hasWideColorSupport = false; - if (hasWideColorDisplay) { - std::vector<ColorMode> modes = - getHwComposer().getColorModes(state.type); - for (ColorMode colorMode : modes) { - switch (colorMode) { - case ColorMode::DISPLAY_P3: - case ColorMode::ADOBE_RGB: - case ColorMode::DCI_P3: - hasWideColorSupport = true; - break; - default: - break; - } - } - } - - bool hasHdrSupport = false; - std::unique_ptr<HdrCapabilities> hdrCapabilities = - getHwComposer().getHdrCapabilities(state.type); - if (hdrCapabilities) { - const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes(); - auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10); - hasHdrSupport = iter != types.cend(); - } - - sp<DisplayDevice> hw = - new DisplayDevice(this, state.type, hwcId, state.isSecure, display, - dispSurface, producer, hasWideColorSupport, - hasHdrSupport); - - ColorMode defaultColorMode = ColorMode::NATIVE; - if (hasWideColorSupport) { - defaultColorMode = ColorMode::SRGB; - } - setActiveColorModeInternal(hw, defaultColorMode); - hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN); - hw->setLayerStack(state.layerStack); - hw->setProjection(state.orientation, state.viewport, state.frame); - hw->setDisplayName(state.displayName); - - mDisplays.add(display, hw); + mDisplays.add(display, + setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface, + producer)); if (!state.isVirtualDisplay()) { mEventThread->onHotplugReceived(state.type, true); } @@ -2744,10 +2834,10 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev if (hasClientComposition) { ALOGV("hasClientComposition"); - android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN; + Dataspace outputDataspace = Dataspace::UNKNOWN; if (displayDevice->getWideColorSupport() && displayDevice->getActiveColorMode() == ColorMode::DISPLAY_P3) { - outputDataspace = HAL_DATASPACE_DISPLAY_P3; + outputDataspace = Dataspace::DISPLAY_P3; } getBE().mRenderEngine->setOutputDataSpace(outputDataspace); @@ -3063,8 +3153,8 @@ void SurfaceFlinger::setTransactionState( } if (transactionFlags) { - if (mInterceptor.isEnabled()) { - mInterceptor.saveTransaction(states, mCurrentState.displays, displays, flags); + if (mInterceptor->isEnabled()) { + mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags); } // this triggers the transaction @@ -3367,7 +3457,7 @@ status_t SurfaceFlinger::createLayer( if (result != NO_ERROR) { return result; } - mInterceptor.saveSurfaceCreation(layer); + mInterceptor->saveSurfaceCreation(layer); setTransactionFlags(eTransactionNeeded); return result; @@ -3439,7 +3529,7 @@ status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBind status_t err = NO_ERROR; sp<Layer> l(client->getLayerUser(handle)); if (l != nullptr) { - mInterceptor.saveSurfaceDeletion(l); + mInterceptor->saveSurfaceDeletion(l); err = removeLayer(l); ALOGE_IF(err<0 && err != NAME_NOT_FOUND, "error removing layer=%p (%s)", l.get(), strerror(-err)); @@ -3521,14 +3611,14 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, return; } - if (mInterceptor.isEnabled()) { + if (mInterceptor->isEnabled()) { ConditionalLock lock(mStateLock, !stateLockHeld); ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken()); if (idx < 0) { ALOGW("Surface Interceptor SavePowerMode: invalid display token"); return; } - mInterceptor.savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode); + mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode); } if (currentMode == HWC_POWER_MODE_OFF) { @@ -3590,6 +3680,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, ALOGE("Attempting to set unknown power mode: %d\n", mode); getHwComposer().setPowerMode(type, mode); } + ALOGD("Finished set power mode=%d, type=%d", mode, hw->getDisplayType()); } void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) { @@ -3704,6 +3795,34 @@ status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asPro dumpWideColorInfo(result); dumpAll = false; } + + if ((index < numArgs) && + (args[index] == String16("--enable-layer-stats"))) { + index++; + mLayerStats.enable(); + dumpAll = false; + } + + if ((index < numArgs) && + (args[index] == String16("--disable-layer-stats"))) { + index++; + mLayerStats.disable(); + dumpAll = false; + } + + if ((index < numArgs) && + (args[index] == String16("--clear-layer-stats"))) { + index++; + mLayerStats.clear(); + dumpAll = false; + } + + if ((index < numArgs) && + (args[index] == String16("--dump-layer-stats"))) { + index++; + mLayerStats.dump(result); + dumpAll = false; + } } if (dumpAll) { @@ -3911,6 +4030,29 @@ LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const return layersProto; } +LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const { + LayersProto layersProto; + const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]); + + SizeProto* resolution = layersProto.mutable_resolution(); + resolution->set_w(displayDevice->getWidth()); + resolution->set_h(displayDevice->getHeight()); + + layersProto.set_color_mode(decodeColorMode(displayDevice->getActiveColorMode())); + layersProto.set_color_transform(decodeColorTransform(displayDevice->getColorTransform())); + layersProto.set_global_transform( + static_cast<int32_t>(displayDevice->getOrientationTransform())); + + mDrawingState.traverseInZOrder([&](Layer* layer) { + if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) { + LayerProto* layerProto = layersProto.add_layers(); + layer->writeToProto(layerProto, hwcId); + } + }); + + return layersProto; +} + void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const { @@ -3981,6 +4123,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current); auto layerTree = LayerProtoParser::generateLayerTree(layersProto); result.append(LayerProtoParser::layersToString(std::move(layerTree)).c_str()); + result.append("\n"); /* * Dump Display state @@ -3993,6 +4136,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, const sp<const DisplayDevice>& hw(mDisplays[dpy]); hw->dump(result); } + result.append("\n"); /* * Dump SurfaceFlinger global state @@ -4332,11 +4476,11 @@ status_t SurfaceFlinger::onTransact( n = data.readInt32(); if (n) { ALOGV("Interceptor enabled"); - mInterceptor.enable(mDrawingState.layersSortedByZ, mDrawingState.displays); + mInterceptor->enable(mDrawingState.layersSortedByZ, mDrawingState.displays); } else{ ALOGV("Interceptor disabled"); - mInterceptor.disable(); + mInterceptor->disable(); } return NO_ERROR; } @@ -4660,10 +4804,10 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight); } - android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN; + Dataspace outputDataspace = Dataspace::UNKNOWN; if (renderArea.getWideColorSupport() && renderArea.getActiveColorMode() == ColorMode::DISPLAY_P3) { - outputDataspace = HAL_DATASPACE_DISPLAY_P3; + outputDataspace = Dataspace::DISPLAY_P3; } getBE().mRenderEngine->setOutputDataSpace(outputDataspace); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 432205096f..89c9cfda19 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -55,6 +55,7 @@ #include "DisplayDevice.h" #include "DispSync.h" #include "FrameTracker.h" +#include "LayerStats.h" #include "LayerVector.h" #include "MessageQueue.h" #include "SurfaceInterceptor.h" @@ -119,6 +120,19 @@ enum { eTransactionMask = 0x0f, }; +// A thin interface to abstract creating instances of Surface (gui/Surface.h) to +// use as a NativeWindow. +class NativeWindowSurface { +public: + virtual ~NativeWindowSurface(); + + // Gets the NativeWindow to use for the surface. + virtual sp<ANativeWindow> getNativeWindow() const = 0; + + // Indicates that the surface should allocate its buffers now. + virtual void preallocateBuffers() = 0; +}; + class SurfaceFlingerBE { public: @@ -266,6 +280,9 @@ public: return "SurfaceFlinger"; } + struct SkipInitializationTag {}; + static constexpr SkipInitializationTag SkipInitialization; + explicit SurfaceFlinger(SkipInitializationTag) ANDROID_API; SurfaceFlinger() ANDROID_API; // must be called before clients can connect @@ -395,9 +412,9 @@ private: Vector<DisplayInfo>* configs); virtual int getActiveConfig(const sp<IBinder>& display); virtual status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<ColorMode>* configs); - virtual ColorMode getActiveColorMode(const sp<IBinder>& display); - virtual status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode); + Vector<ui::ColorMode>* configs); + virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display); + virtual status_t setActiveColorMode(const sp<IBinder>& display, ui::ColorMode colorMode); virtual void setPowerMode(const sp<IBinder>& display, int mode); virtual status_t setActiveConfig(const sp<IBinder>& display, int id); virtual status_t clearAnimationFrameStats(); @@ -447,7 +464,7 @@ private: bool stateLockHeld); // Called on the main thread in response to setActiveColorMode() - void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ColorMode colorMode); + void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ui::ColorMode colorMode); // Returns whether the transaction actually modified any state bool handleMessageTransaction(); @@ -620,8 +637,8 @@ private: // Given a dataSpace, returns the appropriate color_mode to use // to display that dataSpace. - ColorMode pickColorMode(android_dataspace dataSpace) const; - android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b, + ui::ColorMode pickColorMode(ui::Dataspace dataSpace) const; + ui::Dataspace bestTargetDataSpace(ui::Dataspace a, ui::Dataspace b, bool hasHdr) const; mat4 computeSaturationMatrix() const; @@ -630,6 +647,7 @@ private: void doComposition(); void doDebugFlashRegions(); void doTracing(const char* where); + void logLayerStats(); void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion); // compose surfaces for display hw. this fails if using GL and the surface @@ -644,6 +662,10 @@ private: */ DisplayDevice::DisplayType determineDisplayType(hwc2_display_t display, HWC2::Connection connection) const; + sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& display, int hwcId, + const DisplayDeviceState& state, + const sp<DisplaySurface>& dispSurface, + const sp<IGraphicBufferProducer>& producer); void processDisplayChangesLocked(); void processDisplayHotplugEventsLocked(); @@ -692,6 +714,7 @@ private: void dumpBufferingStats(String8& result) const; void dumpWideColorInfo(String8& result) const; LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const; + LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const; bool isLayerTripleBufferingDisabled() const { return this->mLayerTripleBufferingDisabled; @@ -775,15 +798,17 @@ private: bool mBootFinished; bool mForceFullDamage; bool mPropagateBackpressure = true; - SurfaceInterceptor mInterceptor; + std::unique_ptr<SurfaceInterceptor> mInterceptor = + std::make_unique<impl::SurfaceInterceptor>(this); SurfaceTracing mTracing; + LayerStats mLayerStats; bool mUseHwcVirtualDisplays = false; // Restrict layers to use two buffers in their bufferqueues. bool mLayerTripleBufferingDisabled = false; // these are thread safe - mutable MessageQueue mEventQueue; + mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()}; FrameTracker mAnimFrameTracker; DispSync mPrimaryDispSync; @@ -834,6 +859,10 @@ private: bool /* consumerIsSurfaceFlinger */)>; CreateBufferQueueFunction mCreateBufferQueue; + using CreateNativeWindowSurfaceFunction = + std::function<std::unique_ptr<NativeWindowSurface>(const sp<IGraphicBufferProducer>&)>; + CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface; + SurfaceFlingerBE mBE; }; }; // namespace android diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index eeb492978c..4596a21f12 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -31,6 +31,10 @@ namespace android { // ---------------------------------------------------------------------------- +SurfaceInterceptor::~SurfaceInterceptor() = default; + +namespace impl { + SurfaceInterceptor::SurfaceInterceptor(SurfaceFlinger* flinger) : mFlinger(flinger) { @@ -593,5 +597,5 @@ void SurfaceInterceptor::savePowerModeUpdate(int32_t displayId, int32_t mode) { addPowerModeUpdateLocked(createTraceIncrementLocked(), displayId, mode); } - +} // namespace impl } // namespace android diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index 30ebcc6a1c..96defcc265 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -21,48 +21,89 @@ #include <mutex> +#include <gui/LayerState.h> + +#include <utils/KeyedVector.h> #include <utils/SortedVector.h> +#include <utils/StrongPointer.h> #include <utils/Vector.h> +#include "DisplayDevice.h" + namespace android { class BufferItem; class Layer; class SurfaceFlinger; +struct ComposerState; +struct DisplayDeviceState; struct DisplayState; struct layer_state_t; constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat"; +class SurfaceInterceptor { +public: + virtual ~SurfaceInterceptor(); + + // Both vectors are used to capture the current state of SF as the initial snapshot in the trace + virtual void enable(const SortedVector<sp<Layer>>& layers, + const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays) = 0; + virtual void disable() = 0; + virtual bool isEnabled() = 0; + + // Intercept display and surface transactions + virtual void saveTransaction( + const Vector<ComposerState>& stateUpdates, + const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays, + const Vector<DisplayState>& changedDisplays, uint32_t flags) = 0; + + // Intercept surface data + virtual void saveSurfaceCreation(const sp<const Layer>& layer) = 0; + virtual void saveSurfaceDeletion(const sp<const Layer>& layer) = 0; + virtual void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height, + uint64_t frameNumber) = 0; + + // Intercept display data + virtual void saveDisplayCreation(const DisplayDeviceState& info) = 0; + virtual void saveDisplayDeletion(int32_t displayId) = 0; + virtual void savePowerModeUpdate(int32_t displayId, int32_t mode) = 0; + virtual void saveVSyncEvent(nsecs_t timestamp) = 0; +}; + +namespace impl { + /* * SurfaceInterceptor intercepts and stores incoming streams of window * properties on SurfaceFlinger. */ -class SurfaceInterceptor { +class SurfaceInterceptor final : public android::SurfaceInterceptor { public: - SurfaceInterceptor(SurfaceFlinger* const flinger); + explicit SurfaceInterceptor(SurfaceFlinger* const flinger); + ~SurfaceInterceptor() override = default; + // Both vectors are used to capture the current state of SF as the initial snapshot in the trace void enable(const SortedVector<sp<Layer>>& layers, - const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays); - void disable(); - bool isEnabled(); + const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays) override; + void disable() override; + bool isEnabled() override; // Intercept display and surface transactions void saveTransaction(const Vector<ComposerState>& stateUpdates, - const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays, - const Vector<DisplayState>& changedDisplays, uint32_t flags); + const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays, + const Vector<DisplayState>& changedDisplays, uint32_t flags) override; // Intercept surface data - void saveSurfaceCreation(const sp<const Layer>& layer); - void saveSurfaceDeletion(const sp<const Layer>& layer); + void saveSurfaceCreation(const sp<const Layer>& layer) override; + void saveSurfaceDeletion(const sp<const Layer>& layer) override; void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height, - uint64_t frameNumber); + uint64_t frameNumber) override; // Intercept display data - void saveDisplayCreation(const DisplayDeviceState& info); - void saveDisplayDeletion(int32_t displayId); - void savePowerModeUpdate(int32_t displayId, int32_t mode); - void saveVSyncEvent(nsecs_t timestamp); + void saveDisplayCreation(const DisplayDeviceState& info) override; + void saveDisplayDeletion(int32_t displayId) override; + void savePowerModeUpdate(int32_t displayId, int32_t mode) override; + void saveVSyncEvent(nsecs_t timestamp) override; private: // The creation increments of Surfaces and Displays do not contain enough information to capture @@ -134,6 +175,7 @@ private: SurfaceFlinger* const mFlinger; }; -} +} // namespace impl +} // namespace android #endif // ANDROID_SURFACEINTERCEPTOR_H diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp index 47e5d1ff0b..fcf42f00a9 100644 --- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp +++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp @@ -42,6 +42,16 @@ bool sortLayerUniquePtrs(const std::unique_ptr<LayerProtoParser::Layer>& lhs, return sortLayers(lhs.get(), rhs.get()); } +const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo( + const LayersProto& layersProto) { + LayerGlobal layerGlobal; + layerGlobal.resolution = {layersProto.resolution().w(), layersProto.resolution().h()}; + layerGlobal.colorMode = layersProto.color_mode(); + layerGlobal.colorTransform = layersProto.color_transform(); + layerGlobal.globalTransform = layersProto.global_transform(); + return layerGlobal; +} + std::vector<std::unique_ptr<LayerProtoParser::Layer>> LayerProtoParser::generateLayerTree( const LayersProto& layersProto) { std::unordered_map<int32_t, LayerProtoParser::Layer*> layerMap = generateMap(layersProto); @@ -106,8 +116,13 @@ LayerProtoParser::Layer* LayerProtoParser::generateLayer(const LayerProto& layer layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer()); layer->queuedFrames = layerProto.queued_frames(); layer->refreshPending = layerProto.refresh_pending(); + layer->hwcFrame = generateRect(layerProto.hwc_frame()); + layer->hwcCrop = generateFloatRect(layerProto.hwc_crop()); + layer->hwcTransform = layerProto.hwc_transform(); layer->windowType = layerProto.window_type(); layer->appId = layerProto.app_id(); + layer->hwcCompositionType = layerProto.hwc_composition_type(); + layer->isProtected = layerProto.is_protected(); return layer; } @@ -133,6 +148,16 @@ LayerProtoParser::Rect LayerProtoParser::generateRect(const RectProto& rectProto return rect; } +LayerProtoParser::FloatRect LayerProtoParser::generateFloatRect(const FloatRectProto& rectProto) { + LayerProtoParser::FloatRect rect; + rect.left = rectProto.left(); + rect.top = rectProto.top(); + rect.right = rectProto.right(); + rect.bottom = rectProto.bottom(); + + return rect; +} + LayerProtoParser::Transform LayerProtoParser::generateTransform( const TransformProto& transformProto) { LayerProtoParser::Transform transform; @@ -246,6 +271,10 @@ std::string LayerProtoParser::Rect::to_string() const { return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom); } +std::string LayerProtoParser::FloatRect::to_string() const { + return StringPrintf("[%.2f, %.2f, %.2f, %.2f]", left, top, right, bottom); +} + std::string LayerProtoParser::Region::to_string(const char* what) const { std::string result = StringPrintf(" Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id), @@ -273,7 +302,7 @@ std::string LayerProtoParser::Layer::to_string() const { finalCrop.to_string().c_str()); StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate); StringAppendF(&result, "dataspace=%s, ", dataspace.c_str()); - StringAppendF(&result, "pixelformat=%s, ", pixelFormat.c_str()); + StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str()); StringAppendF(&result, "color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ", static_cast<double>(color.r), static_cast<double>(color.g), static_cast<double>(color.b), static_cast<double>(color.a), flags); diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h index b56a6fbb97..74a6f28f2b 100644 --- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h +++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once #include <layerproto/LayerProtoHeader.h> @@ -57,6 +58,16 @@ public: std::string to_string() const; }; + class FloatRect { + public: + float left; + float top; + float right; + float bottom; + + std::string to_string() const; + }; + class Region { public: uint64_t id; @@ -96,12 +107,26 @@ public: LayerProtoParser::ActiveBuffer activeBuffer; int32_t queuedFrames; bool refreshPending; + LayerProtoParser::Rect hwcFrame; + LayerProtoParser::FloatRect hwcCrop; + int32_t hwcTransform; int32_t windowType; int32_t appId; + int32_t hwcCompositionType; + bool isProtected; std::string to_string() const; }; + class LayerGlobal { + public: + int2 resolution; + std::string colorMode; + std::string colorTransform; + int32_t globalTransform; + }; + + static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto); static std::vector<std::unique_ptr<Layer>> generateLayerTree(const LayersProto& layersProto); static std::string layersToString(std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers); @@ -110,6 +135,7 @@ private: static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto); static LayerProtoParser::Region generateRegion(const RegionProto& regionProto); static LayerProtoParser::Rect generateRect(const RectProto& rectProto); + static LayerProtoParser::FloatRect generateFloatRect(const FloatRectProto& rectProto); static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto); static LayerProtoParser::ActiveBuffer generateActiveBuffer( const ActiveBufferProto& activeBufferProto); diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index f18386b1ac..77c6675b7f 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -7,6 +7,10 @@ package android.surfaceflinger; // Contains a list of all layers. message LayersProto { repeated LayerProto layers = 1; + optional SizeProto resolution = 2; + optional string color_mode = 3; + optional string color_transform = 4; + optional int32 global_transform = 5; } // Information about each layer. @@ -64,8 +68,18 @@ message LayerProto { // The number of frames available. optional int32 queued_frames = 28; optional bool refresh_pending = 29; - optional int32 window_type = 30; - optional int32 app_id = 31; + // The layer's composer backend destination frame + optional RectProto hwc_frame = 30; + // The layer's composer backend source crop + optional FloatRectProto hwc_crop = 31; + // The layer's composer backend transform + optional int32 hwc_transform = 32; + optional int32 window_type = 33; + optional int32 app_id = 34; + // The layer's composition type + optional int32 hwc_composition_type = 35; + // If it's a buffer layer, indicate if the content is protected + optional bool is_protected = 36; } message PositionProto { @@ -97,6 +111,13 @@ message RectProto { optional int32 bottom = 4; } +message FloatRectProto { + optional float left = 1; + optional float top = 2; + optional float right = 3; + optional float bottom = 4; +} + message ActiveBufferProto { optional uint32 width = 1; optional uint32 height = 2; @@ -109,4 +130,4 @@ message ColorProto { optional float g = 2; optional float b = 3; optional float a = 4; -}
\ No newline at end of file +} diff --git a/services/surfaceflinger/tests/hwc2/Android.bp b/services/surfaceflinger/tests/hwc2/Android.bp index e980522702..6c0e4abcfe 100644 --- a/services/surfaceflinger/tests/hwc2/Android.bp +++ b/services/surfaceflinger/tests/hwc2/Android.bp @@ -42,6 +42,7 @@ cc_test { ], shared_libs: [ "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", "libcutils", "libEGL", "libGLESv2", diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp index 86e2e1ec30..13774b4ed3 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp @@ -22,7 +22,7 @@ #include <android-base/unique_fd.h> #include <hardware/hardware.h> #include <sync/sync.h> -#include <ui/GraphicsTypes.h> +#include <ui/GraphicTypes.h> #define HWC2_INCLUDE_STRINGIFICATION #define HWC2_USE_CPP11 @@ -35,7 +35,8 @@ #include "Hwc2TestClientTarget.h" #include "Hwc2TestVirtualDisplay.h" -using android::ColorMode; +using android::ui::ColorMode; +using android::ui::Dataspace; void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData, hwc2_display_t display, int32_t connected); @@ -442,14 +443,14 @@ public: } void setLayerDataspace(hwc2_display_t display, hwc2_layer_t layer, - android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr) + Dataspace dataspace, hwc2_error_t* outErr = nullptr) { auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DATASPACE>( getFunction(HWC2_FUNCTION_SET_LAYER_DATASPACE)); ASSERT_TRUE(pfn) << "failed to get function"; auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, - layer, dataspace)); + layer, static_cast<int>(dataspace))); if (outErr) { *outErr = err; } else { @@ -790,14 +791,14 @@ public: void getClientTargetSupport(hwc2_display_t display, int32_t width, int32_t height, android_pixel_format_t format, - android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr) + Dataspace dataspace, hwc2_error_t* outErr = nullptr) { auto pfn = reinterpret_cast<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>( getFunction(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT)); ASSERT_TRUE(pfn) << "failed to get function"; auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, width, - height, format, dataspace)); + height, format, static_cast<int>(dataspace))); if (outErr) { *outErr = err; } else { @@ -807,7 +808,7 @@ public: } void setClientTarget(hwc2_display_t display, buffer_handle_t handle, - int32_t acquireFence, android_dataspace_t dataspace, + int32_t acquireFence, Dataspace dataspace, hwc_region_t damage, hwc2_error_t* outErr = nullptr) { auto pfn = reinterpret_cast<HWC2_PFN_SET_CLIENT_TARGET>( @@ -815,7 +816,7 @@ public: ASSERT_TRUE(pfn) << "failed to get function"; auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, handle, - acquireFence, dataspace, damage)); + acquireFence, static_cast<int>(dataspace), damage)); if (outErr) { *outErr = err; } else { @@ -1691,7 +1692,7 @@ protected: const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget, const Area& displayArea) { - android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; + Dataspace dataspace = Dataspace::UNKNOWN; hwc_region_t damage = { }; buffer_handle_t handle; int32_t acquireFence; @@ -3716,7 +3717,7 @@ TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_unsupported) * layer. */ TEST_F(Hwc2Test, SET_CLIENT_TARGET_basic) { - const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; + const Dataspace dataspace = Dataspace::UNKNOWN; const hwc_region_t damage = { }; const size_t layerCnt = 1; @@ -3795,7 +3796,7 @@ TEST_F(Hwc2Test, SET_CLIENT_TARGET_bad_display) std::set<hwc2_layer_t> clientLayers; std::set<hwc2_layer_t> flipClientTargetLayers; bool flipClientTarget = true; - const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; + const Dataspace dataspace = Dataspace::UNKNOWN; const hwc_region_t damage = { }; buffer_handle_t handle; int32_t acquireFence; diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp index 69254921d4..14c60a7d26 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp @@ -91,7 +91,7 @@ Area Hwc2TestClientTargetSupport::getBufferArea() const return mBufferArea.get(); } -android_dataspace_t Hwc2TestClientTargetSupport::getDataspace() const +android::ui::Dataspace Hwc2TestClientTargetSupport::getDataspace() const { return mDataspace.get(); } diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h index 3b47978bef..6f4090f321 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h @@ -53,7 +53,7 @@ public: bool advance(); Area getBufferArea() const; - android_dataspace_t getDataspace() const; + android::ui::Dataspace getDataspace() const; const hwc_region_t getSurfaceDamage() const; private: diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp index 937fce28fb..c1c9cc8f5b 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp @@ -146,7 +146,7 @@ hwc_rect_t Hwc2TestLayer::getCursorPosition() const return mDisplayFrame.get(); } -android_dataspace_t Hwc2TestLayer::getDataspace() const +android::ui::Dataspace Hwc2TestLayer::getDataspace() const { return mDataspace.get(); } diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h index 0e7dd228fb..29ae521804 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h @@ -54,7 +54,7 @@ public: hwc_color_t getColor() const; hwc2_composition_t getComposition() const; hwc_rect_t getCursorPosition() const; - android_dataspace_t getDataspace() const; + android::ui::Dataspace getDataspace() const; hwc_rect_t getDisplayFrame() const; float getPlaneAlpha() const; hwc_frect_t getSourceCrop() const; diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp index 495ef79609..90127a1302 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp @@ -169,7 +169,7 @@ hwc_rect_t Hwc2TestLayers::getCursorPosition(hwc2_layer_t layer) const return mTestLayers.at(layer).getCursorPosition(); } -android_dataspace_t Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const +android::ui::Dataspace Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const { if (mTestLayers.count(layer) == 0) { []() { GTEST_FAIL(); }(); diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h index d95a91f485..909dd486e8 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h @@ -63,7 +63,7 @@ public: hwc_color_t getColor(hwc2_layer_t layer) const; hwc2_composition_t getComposition(hwc2_layer_t layer) const; hwc_rect_t getCursorPosition(hwc2_layer_t layer) const; - android_dataspace_t getDataspace(hwc2_layer_t layer) const; + android::ui::Dataspace getDataspace(hwc2_layer_t layer) const; hwc_rect_t getDisplayFrame(hwc2_layer_t layer) const; android_pixel_format_t getFormat(hwc2_layer_t layer) const; float getPlaneAlpha(hwc2_layer_t layer) const; diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp index 5b3bbeb708..c5b92d0664 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp @@ -262,62 +262,62 @@ Hwc2TestDataspace::Hwc2TestDataspace(Hwc2TestCoverage coverage) std::string Hwc2TestDataspace::dump() const { std::stringstream dmp; - dmp << "\tdataspace: " << get() << "\n"; + dmp << "\tdataspace: " << static_cast<int32_t>(get()) << "\n"; return dmp.str(); } -const std::vector<android_dataspace_t> Hwc2TestDataspace::defaultDataspaces = { - HAL_DATASPACE_UNKNOWN, -}; - -const std::vector<android_dataspace_t> Hwc2TestDataspace::basicDataspaces = { - HAL_DATASPACE_UNKNOWN, - HAL_DATASPACE_V0_SRGB, -}; - -const std::vector<android_dataspace_t> Hwc2TestDataspace::completeDataspaces = { - HAL_DATASPACE_UNKNOWN, - HAL_DATASPACE_ARBITRARY, - HAL_DATASPACE_STANDARD_SHIFT, - HAL_DATASPACE_STANDARD_MASK, - HAL_DATASPACE_STANDARD_UNSPECIFIED, - HAL_DATASPACE_STANDARD_BT709, - HAL_DATASPACE_STANDARD_BT601_625, - HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED, - HAL_DATASPACE_STANDARD_BT601_525, - HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED, - HAL_DATASPACE_STANDARD_BT2020, - HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE, - HAL_DATASPACE_STANDARD_BT470M, - HAL_DATASPACE_STANDARD_FILM, - HAL_DATASPACE_TRANSFER_SHIFT, - HAL_DATASPACE_TRANSFER_MASK, - HAL_DATASPACE_TRANSFER_UNSPECIFIED, - HAL_DATASPACE_TRANSFER_LINEAR, - HAL_DATASPACE_TRANSFER_SRGB, - HAL_DATASPACE_TRANSFER_SMPTE_170M, - HAL_DATASPACE_TRANSFER_GAMMA2_2, - HAL_DATASPACE_TRANSFER_GAMMA2_8, - HAL_DATASPACE_TRANSFER_ST2084, - HAL_DATASPACE_TRANSFER_HLG, - HAL_DATASPACE_RANGE_SHIFT, - HAL_DATASPACE_RANGE_MASK, - HAL_DATASPACE_RANGE_UNSPECIFIED, - HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_RANGE_LIMITED, - HAL_DATASPACE_SRGB_LINEAR, - HAL_DATASPACE_V0_SRGB_LINEAR, - HAL_DATASPACE_SRGB, - HAL_DATASPACE_V0_SRGB, - HAL_DATASPACE_JFIF, - HAL_DATASPACE_V0_JFIF, - HAL_DATASPACE_BT601_625, - HAL_DATASPACE_V0_BT601_625, - HAL_DATASPACE_BT601_525, - HAL_DATASPACE_V0_BT601_525, - HAL_DATASPACE_BT709, - HAL_DATASPACE_V0_BT709, - HAL_DATASPACE_DEPTH, +const std::vector<android::ui::Dataspace> Hwc2TestDataspace::defaultDataspaces = { + android::ui::Dataspace::UNKNOWN, +}; + +const std::vector<android::ui::Dataspace> Hwc2TestDataspace::basicDataspaces = { + android::ui::Dataspace::UNKNOWN, + android::ui::Dataspace::V0_SRGB, +}; + +const std::vector<android::ui::Dataspace> Hwc2TestDataspace::completeDataspaces = { + android::ui::Dataspace::UNKNOWN, + android::ui::Dataspace::ARBITRARY, + android::ui::Dataspace::STANDARD_SHIFT, + android::ui::Dataspace::STANDARD_MASK, + android::ui::Dataspace::STANDARD_UNSPECIFIED, + android::ui::Dataspace::STANDARD_BT709, + android::ui::Dataspace::STANDARD_BT601_625, + android::ui::Dataspace::STANDARD_BT601_625_UNADJUSTED, + android::ui::Dataspace::STANDARD_BT601_525, + android::ui::Dataspace::STANDARD_BT601_525_UNADJUSTED, + android::ui::Dataspace::STANDARD_BT2020, + android::ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE, + android::ui::Dataspace::STANDARD_BT470M, + android::ui::Dataspace::STANDARD_FILM, + android::ui::Dataspace::TRANSFER_SHIFT, + android::ui::Dataspace::TRANSFER_MASK, + android::ui::Dataspace::TRANSFER_UNSPECIFIED, + android::ui::Dataspace::TRANSFER_LINEAR, + android::ui::Dataspace::TRANSFER_SRGB, + android::ui::Dataspace::TRANSFER_SMPTE_170M, + android::ui::Dataspace::TRANSFER_GAMMA2_2, + android::ui::Dataspace::TRANSFER_GAMMA2_8, + android::ui::Dataspace::TRANSFER_ST2084, + android::ui::Dataspace::TRANSFER_HLG, + android::ui::Dataspace::RANGE_SHIFT, + android::ui::Dataspace::RANGE_MASK, + android::ui::Dataspace::RANGE_UNSPECIFIED, + android::ui::Dataspace::RANGE_FULL, + android::ui::Dataspace::RANGE_LIMITED, + android::ui::Dataspace::SRGB_LINEAR, + android::ui::Dataspace::V0_SRGB_LINEAR, + android::ui::Dataspace::SRGB, + android::ui::Dataspace::V0_SRGB, + android::ui::Dataspace::JFIF, + android::ui::Dataspace::V0_JFIF, + android::ui::Dataspace::BT601_625, + android::ui::Dataspace::V0_BT601_625, + android::ui::Dataspace::BT601_525, + android::ui::Dataspace::V0_BT601_525, + android::ui::Dataspace::BT709, + android::ui::Dataspace::V0_BT709, + android::ui::Dataspace::DEPTH, }; diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h index cb811e06e2..d7082f3cb5 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h @@ -20,6 +20,7 @@ #include <array> #include <vector> +#include <ui/GraphicTypes.h> #include <ui/Region.h> #define HWC2_INCLUDE_STRINGIFICATION @@ -229,16 +230,16 @@ protected: }; -class Hwc2TestDataspace : public Hwc2TestProperty<android_dataspace_t> { +class Hwc2TestDataspace : public Hwc2TestProperty<android::ui::Dataspace> { public: Hwc2TestDataspace(Hwc2TestCoverage coverage); std::string dump() const override; protected: - static const std::vector<android_dataspace_t> defaultDataspaces; - static const std::vector<android_dataspace_t> basicDataspaces; - static const std::vector<android_dataspace_t> completeDataspaces; + static const std::vector<android::ui::Dataspace> defaultDataspaces; + static const std::vector<android::ui::Dataspace> basicDataspaces; + static const std::vector<android::ui::Dataspace> completeDataspaces; static const std::array<bool, 6> mCompositionSupport; }; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 353b24546d..8ffc5ad00e 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -21,10 +21,16 @@ cc_test { ":libsurfaceflinger_sources", "DisplayTransactionTest.cpp", "MockComposer.cpp", + "MockDisplaySurface.cpp", + "MockEventControlThread.cpp", "MockEventThread.cpp", "MockGraphicBufferConsumer.cpp", "MockGraphicBufferProducer.cpp", + "MockMessageQueue.cpp", + "MockNativeWindow.cpp", + "MockNativeWindowSurface.cpp", "MockRenderEngine.cpp", + "MockSurfaceInterceptor.cpp", ], static_libs: [ "libgmock", diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 21590dfffc..c048c583f2 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -21,12 +21,19 @@ #include <gtest/gtest.h> #include <log/log.h> +#include "system/window.h" #include "MockComposer.h" +#include "MockDisplaySurface.h" +#include "MockEventControlThread.h" #include "MockEventThread.h" #include "MockGraphicBufferConsumer.h" #include "MockGraphicBufferProducer.h" +#include "MockMessageQueue.h" +#include "MockNativeWindow.h" +#include "MockNativeWindowSurface.h" #include "MockRenderEngine.h" +#include "MockSurfaceInterceptor.h" #include "TestableSurfaceFlinger.h" namespace android { @@ -39,36 +46,119 @@ using testing::Mock; using testing::Return; using testing::SetArgPointee; +using android::hardware::graphics::common::V1_0::ColorMode; using android::hardware::graphics::common::V1_0::Hdr; using android::Hwc2::Error; using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; +using HWC2Display = TestableSurfaceFlinger::HWC2Display; +using HotplugEvent = TestableSurfaceFlinger::HotplugEvent; + constexpr int32_t DEFAULT_REFRESH_RATE = 1666666666; constexpr int32_t DEFAULT_DPI = 320; +constexpr int DEFAULT_CONFIG_ID = 0; + class DisplayTransactionTest : public testing::Test { protected: DisplayTransactionTest(); ~DisplayTransactionTest() override; - void setupComposer(int virtualDisplayCount); - void setupPrimaryDisplay(int width, int height); + // -------------------------------------------------------------------- + // Precondition helpers - void expectFramebufferQueuePairCreation(int width, int height); + void setupComposer(int virtualDisplayCount); + void setupFakeHwcDisplay(hwc2_display_t displayId, DisplayDevice::DisplayType type, int width, + int height); + + struct FakeDisplayDeviceFactory { + public: + FakeDisplayDeviceFactory(TestableSurfaceFlinger& flinger, sp<BBinder>& displayToken, + DisplayDevice::DisplayType type, int hwcId) + : mFlinger(flinger), mDisplayToken(displayToken), mType(type), mHwcId(hwcId) {} + + sp<DisplayDevice> build() { + return new DisplayDevice(mFlinger.mFlinger.get(), mType, mHwcId, false, mDisplayToken, + mNativeWindow, mDisplaySurface, std::move(mRenderSurface), 0, + 0, false, false, HWC_POWER_MODE_NORMAL); + } + + FakeDisplayDeviceFactory& setNativeWindow(const sp<ANativeWindow>& nativeWindow) { + mNativeWindow = nativeWindow; + return *this; + } + + FakeDisplayDeviceFactory& setDisplaySurface(const sp<DisplaySurface>& displaySurface) { + mDisplaySurface = displaySurface; + return *this; + } + + FakeDisplayDeviceFactory& setRenderSurface(std::unique_ptr<RE::Surface> renderSurface) { + mRenderSurface = std::move(renderSurface); + return *this; + } + + TestableSurfaceFlinger& mFlinger; + sp<BBinder>& mDisplayToken; + DisplayDevice::DisplayType mType; + int mHwcId; + sp<ANativeWindow> mNativeWindow; + sp<DisplaySurface> mDisplaySurface; + std::unique_ptr<RE::Surface> mRenderSurface; + }; + + sp<BBinder> setupFakeExistingPhysicalDisplay(hwc2_display_t displayId, + DisplayDevice::DisplayType type); + + void setupFakeBufferQueueFactory(); + void setupFakeNativeWindowSurfaceFactory(int displayWidth, int displayHeight, bool critical, + bool async); + void expectFramebufferUsageSet(int width, int height, int grallocUsage); + void expectHwcHotplugCalls(hwc2_display_t displayId, int displayWidth, int displayHeight); + + // -------------------------------------------------------------------- + // Call expectation helpers + + void expectRESurfaceCreationCalls(); + void expectPhysicalDisplayDeviceCreationCalls(hwc2_display_t displayId, int displayWidth, + int displayHeight, bool critical, bool async); + + // -------------------------------------------------------------------- + // Postcondition helpers + + bool hasTransactionFlagSet(int flag); + bool hasDisplayDevice(sp<IBinder> displayToken); + sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken); + bool hasCurrentDisplayState(sp<IBinder> displayToken); + const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken); + bool hasDrawingDisplayState(sp<IBinder> displayToken); + const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken); + + // -------------------------------------------------------------------- + // Test instances + + std::unordered_set<HWC2::Capability> mCapabilities; TestableSurfaceFlinger mFlinger; mock::EventThread* mEventThread = new mock::EventThread(); + mock::EventControlThread* mEventControlThread = new mock::EventControlThread(); // These mocks are created by the test, but are destroyed by SurfaceFlinger // by virtue of being stored into a std::unique_ptr. However we still need // to keep a reference to them for use in setting up call expectations. RE::mock::RenderEngine* mRenderEngine = new RE::mock::RenderEngine(); Hwc2::mock::Composer* mComposer = new Hwc2::mock::Composer(); + mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); + mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor(); // These mocks are created only when expected to be created via a factory. sp<mock::GraphicBufferConsumer> mConsumer; sp<mock::GraphicBufferProducer> mProducer; + mock::NativeWindowSurface* mNativeWindowSurface = nullptr; + sp<mock::NativeWindow> mNativeWindow; + RE::mock::Surface* mRenderSurface = nullptr; + std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays; }; DisplayTransactionTest::DisplayTransactionTest() { @@ -80,8 +170,16 @@ DisplayTransactionTest::DisplayTransactionTest() { ADD_FAILURE() << "Unexpected request to create a buffer queue."; }); + mFlinger.setCreateNativeWindowSurface([](auto) { + ADD_FAILURE() << "Unexpected request to create a native window surface."; + return nullptr; + }); + + mFlinger.mutableEventControlThread().reset(mEventControlThread); mFlinger.mutableEventThread().reset(mEventThread); + mFlinger.mutableEventQueue().reset(mMessageQueue); mFlinger.setupRenderEngine(std::unique_ptr<RE::RenderEngine>(mRenderEngine)); + mFlinger.mutableInterceptor().reset(mSurfaceInterceptor); setupComposer(0); } @@ -101,40 +199,49 @@ void DisplayTransactionTest::setupComposer(int virtualDisplayCount) { Mock::VerifyAndClear(mComposer); } -void DisplayTransactionTest::setupPrimaryDisplay(int width, int height) { - EXPECT_CALL(*mComposer, getDisplayType(DisplayDevice::DISPLAY_PRIMARY, _)) - .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), - Return(Error::NONE))); - EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE)); - EXPECT_CALL(*mComposer, getDisplayConfigs(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{0}), Return(Error::NONE))); - EXPECT_CALL(*mComposer, - getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0, - IComposerClient::Attribute::WIDTH, _)) - .WillOnce(DoAll(SetArgPointee<3>(width), Return(Error::NONE))); - EXPECT_CALL(*mComposer, - getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0, - IComposerClient::Attribute::HEIGHT, _)) - .WillOnce(DoAll(SetArgPointee<3>(height), Return(Error::NONE))); - EXPECT_CALL(*mComposer, - getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0, - IComposerClient::Attribute::VSYNC_PERIOD, _)) - .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE))); - EXPECT_CALL(*mComposer, - getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0, - IComposerClient::Attribute::DPI_X, _)) - .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE))); - EXPECT_CALL(*mComposer, - getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0, - IComposerClient::Attribute::DPI_Y, _)) - .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE))); +void DisplayTransactionTest::setupFakeHwcDisplay(hwc2_display_t displayId, + DisplayDevice::DisplayType type, int width, + int height) { + auto display = std::make_unique<HWC2Display>(*mComposer, mCapabilities, displayId, + HWC2::DisplayType::Physical); + display->mutableIsConnected() = true; + display->mutableConfigs().emplace(DEFAULT_CONFIG_ID, + HWC2::Display::Config::Builder(*display, DEFAULT_CONFIG_ID) + .setWidth(width) + .setHeight(height) + .setVsyncPeriod(DEFAULT_REFRESH_RATE) + .setDpiX(DEFAULT_DPI) + .setDpiY(DEFAULT_DPI) + .build()); + + mFlinger.mutableHwcDisplayData()[type].reset(); + mFlinger.mutableHwcDisplayData()[type].hwcDisplay = display.get(); + mFlinger.mutableHwcDisplaySlots().emplace(displayId, type); + + mFakeHwcDisplays.push_back(std::move(display)); +} - mFlinger.setupPrimaryDisplay(); +sp<BBinder> DisplayTransactionTest::setupFakeExistingPhysicalDisplay( + hwc2_display_t displayId, DisplayDevice::DisplayType type) { + setupFakeHwcDisplay(displayId, type, 0, 0); - Mock::VerifyAndClear(mComposer); + sp<BBinder> displayToken = new BBinder(); + mFlinger.mutableBuiltinDisplays()[type] = displayToken; + mFlinger.mutableDisplays() + .add(displayToken, + FakeDisplayDeviceFactory(mFlinger, displayToken, type, type).build()); + + DisplayDeviceState state(type, true); + mFlinger.mutableCurrentState().displays.add(displayToken, state); + mFlinger.mutableDrawingState().displays.add(displayToken, state); + + return displayToken; } -void DisplayTransactionTest::expectFramebufferQueuePairCreation(int width, int height) { +void DisplayTransactionTest::setupFakeBufferQueueFactory() { + // This setup is only expected once per test. + ASSERT_TRUE(mConsumer == nullptr && mProducer == nullptr); + mConsumer = new mock::GraphicBufferConsumer(); mProducer = new mock::GraphicBufferProducer(); @@ -142,64 +249,187 @@ void DisplayTransactionTest::expectFramebufferQueuePairCreation(int width, int h *outProducer = mProducer; *outConsumer = mConsumer; }); +} + +void DisplayTransactionTest::setupFakeNativeWindowSurfaceFactory(int displayWidth, + int displayHeight, bool critical, + bool async) { + // This setup is only expected once per test. + ASSERT_TRUE(mNativeWindowSurface == nullptr); + + mNativeWindowSurface = new mock::NativeWindowSurface(); + mNativeWindow = new mock::NativeWindow(); + + mFlinger.setCreateNativeWindowSurface( + [this](auto) { return std::unique_ptr<NativeWindowSurface>(mNativeWindowSurface); }); + + EXPECT_CALL(*mNativeWindowSurface, getNativeWindow()).WillOnce(Return(mNativeWindow)); + EXPECT_CALL(*mNativeWindow, perform(19)).Times(1); + + EXPECT_CALL(*mRenderSurface, setAsync(async)).Times(1); + EXPECT_CALL(*mRenderSurface, setCritical(critical)).Times(1); + EXPECT_CALL(*mRenderSurface, setNativeWindow(mNativeWindow.get())).Times(1); + EXPECT_CALL(*mRenderSurface, queryWidth()).WillOnce(Return(displayWidth)); + EXPECT_CALL(*mRenderSurface, queryHeight()).WillOnce(Return(displayHeight)); +} + +void DisplayTransactionTest::expectFramebufferUsageSet(int width, int height, int grallocUsage) { EXPECT_CALL(*mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR)); - EXPECT_CALL(*mConsumer, - setConsumerUsageBits(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | - GRALLOC_USAGE_HW_FB)) - .WillRepeatedly(Return(NO_ERROR)); + EXPECT_CALL(*mConsumer, setConsumerUsageBits(grallocUsage)).WillRepeatedly(Return(NO_ERROR)); EXPECT_CALL(*mConsumer, setDefaultBufferSize(width, height)).WillRepeatedly(Return(NO_ERROR)); EXPECT_CALL(*mConsumer, setMaxAcquiredBufferCount(_)).WillRepeatedly(Return(NO_ERROR)); EXPECT_CALL(*mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return()); } -TEST_F(DisplayTransactionTest, processDisplayChangesLockedProcessesPrimaryDisplayConnected) { - using android::hardware::graphics::common::V1_0::ColorMode; +void DisplayTransactionTest::expectHwcHotplugCalls(hwc2_display_t displayId, int displayWidth, + int displayHeight) { + EXPECT_CALL(*mComposer, getDisplayType(displayId, _)) + .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), + Return(Error::NONE))); + EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE)); + EXPECT_CALL(*mComposer, getDisplayConfigs(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{0}), Return(Error::NONE))); + EXPECT_CALL(*mComposer, getDisplayAttribute(displayId, 0, IComposerClient::Attribute::WIDTH, _)) + .WillOnce(DoAll(SetArgPointee<3>(displayWidth), Return(Error::NONE))); + EXPECT_CALL(*mComposer, + getDisplayAttribute(displayId, 0, IComposerClient::Attribute::HEIGHT, _)) + .WillOnce(DoAll(SetArgPointee<3>(displayHeight), Return(Error::NONE))); + EXPECT_CALL(*mComposer, + getDisplayAttribute(displayId, 0, IComposerClient::Attribute::VSYNC_PERIOD, _)) + .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE))); + EXPECT_CALL(*mComposer, getDisplayAttribute(displayId, 0, IComposerClient::Attribute::DPI_X, _)) + .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE))); + EXPECT_CALL(*mComposer, getDisplayAttribute(displayId, 0, IComposerClient::Attribute::DPI_Y, _)) + .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE))); +} - setupPrimaryDisplay(1920, 1080); +void DisplayTransactionTest::expectRESurfaceCreationCalls() { + // This setup is only expected once per test. + ASSERT_TRUE(mRenderSurface == nullptr); - sp<BBinder> token = new BBinder(); - mFlinger.mutableCurrentState().displays.add(token, {DisplayDevice::DISPLAY_PRIMARY, true}); + mRenderSurface = new RE::mock::Surface(); + EXPECT_CALL(*mRenderEngine, createSurface()) + .WillOnce(Return(ByMove(std::unique_ptr<RE::Surface>(mRenderSurface)))); +} - EXPECT_CALL(*mComposer, getActiveConfig(DisplayDevice::DISPLAY_PRIMARY, _)) - .WillOnce(DoAll(SetArgPointee<1>(0), Return(Error::NONE))); - EXPECT_CALL(*mComposer, getColorModes(DisplayDevice::DISPLAY_PRIMARY, _)).Times(0); - EXPECT_CALL(*mComposer, getHdrCapabilities(DisplayDevice::DISPLAY_PRIMARY, _, _, _, _)) +void DisplayTransactionTest::expectPhysicalDisplayDeviceCreationCalls(hwc2_display_t displayId, + int displayWidth, + int displayHeight, + bool critical, bool async) { + EXPECT_CALL(*mComposer, getActiveConfig(displayId, _)) + .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE))); + EXPECT_CALL(*mComposer, getColorModes(displayId, _)).Times(0); + EXPECT_CALL(*mComposer, getHdrCapabilities(displayId, _, _, _, _)) .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE))); - expectFramebufferQueuePairCreation(1920, 1080); + setupFakeBufferQueueFactory(); + expectFramebufferUsageSet(displayWidth, displayHeight, + GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | + GRALLOC_USAGE_HW_FB); - auto reSurface = new RE::mock::Surface(); - EXPECT_CALL(*mRenderEngine, createSurface()) - .WillOnce(Return(ByMove(std::unique_ptr<RE::Surface>(reSurface)))); - EXPECT_CALL(*reSurface, setAsync(false)).Times(1); - EXPECT_CALL(*reSurface, setCritical(true)).Times(1); - EXPECT_CALL(*reSurface, setNativeWindow(_)).Times(1); - EXPECT_CALL(*reSurface, queryWidth()).WillOnce(Return(1920)); - EXPECT_CALL(*reSurface, queryHeight()).WillOnce(Return(1080)); + setupFakeNativeWindowSurfaceFactory(displayWidth, displayHeight, critical, async); +} + +bool DisplayTransactionTest::hasTransactionFlagSet(int flag) { + return mFlinger.mutableTransactionFlags() & flag; +} + +bool DisplayTransactionTest::hasDisplayDevice(sp<IBinder> displayToken) { + return mFlinger.mutableDisplays().indexOfKey(displayToken) >= 0; +} + +sp<DisplayDevice> DisplayTransactionTest::getDisplayDevice(sp<IBinder> displayToken) { + return mFlinger.mutableDisplays().valueFor(displayToken); +} + +bool DisplayTransactionTest::hasCurrentDisplayState(sp<IBinder> displayToken) { + return mFlinger.mutableCurrentState().displays.indexOfKey(displayToken) >= 0; +} + +const DisplayDeviceState& DisplayTransactionTest::getCurrentDisplayState(sp<IBinder> displayToken) { + return mFlinger.mutableCurrentState().displays.valueFor(displayToken); +} + +bool DisplayTransactionTest::hasDrawingDisplayState(sp<IBinder> displayToken) { + return mFlinger.mutableDrawingState().displays.indexOfKey(displayToken) >= 0; +} + +const DisplayDeviceState& DisplayTransactionTest::getDrawingDisplayState(sp<IBinder> displayToken) { + return mFlinger.mutableDrawingState().displays.valueFor(displayToken); +} + +/* ------------------------------------------------------------------------ + * SurfaceFlinger::handleTransactionLocked(eDisplayTransactionNeeded) + */ + +TEST_F(DisplayTransactionTest, handleTransactionLockedProcessesHotplugConnectPrimary) { + constexpr hwc2_display_t externalDisplayId = 102; + constexpr hwc2_display_t displayId = 123; + constexpr int displayWidth = 1920; + constexpr int displayHeight = 1080; + + // -------------------------------------------------------------------- + // Preconditions + + // An external display may already be set up + setupFakeHwcDisplay(externalDisplayId, DisplayDevice::DISPLAY_EXTERNAL, 3840, 2160); + + // A hotplug connect comes in for a new display + mFlinger.mutablePendingHotplugEvents().emplace_back( + HotplugEvent{displayId, HWC2::Connection::Connected}); + + // -------------------------------------------------------------------- + // Call Expectations + + EXPECT_CALL(*mComposer, isUsingVrComposer()).WillOnce(Return(false)); + expectHwcHotplugCalls(displayId, displayWidth, displayHeight); + expectRESurfaceCreationCalls(); + expectPhysicalDisplayDeviceCreationCalls(displayId, displayWidth, displayHeight, true, false); + + EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1); EXPECT_CALL(*mEventThread, onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, true)).Times(1); - mFlinger.processDisplayChangesLocked(); + // -------------------------------------------------------------------- + // Invocation + + mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions - ASSERT_TRUE(mFlinger.mutableDisplays().indexOfKey(token) >= 0); + // HWComposer should have an entry for the display + EXPECT_TRUE(mFlinger.mutableHwcDisplaySlots().count(displayId) == 1); - const auto& device = mFlinger.mutableDisplays().valueFor(token); - ASSERT_TRUE(device.get()); + // The display should have set up as a primary built-in display. + auto displayToken = mFlinger.mutableBuiltinDisplays()[DisplayDevice::DISPLAY_PRIMARY]; + ASSERT_TRUE(displayToken != nullptr); + + // The display device should have been set up in the list of displays. + ASSERT_TRUE(hasDisplayDevice(displayToken)); + const auto& device = getDisplayDevice(displayToken); EXPECT_TRUE(device->isSecure()); EXPECT_TRUE(device->isPrimary()); - ssize_t i = mFlinger.mutableDrawingState().displays.indexOfKey(token); - ASSERT_GE(0, i); - const auto& draw = mFlinger.mutableDrawingState().displays[i]; + // The display should have been set up in the current display state + ASSERT_TRUE(hasCurrentDisplayState(displayToken)); + const auto& current = getCurrentDisplayState(displayToken); + EXPECT_EQ(DisplayDevice::DISPLAY_PRIMARY, current.type); + + // The display should have been set up in the drawing display state + ASSERT_TRUE(hasDrawingDisplayState(displayToken)); + const auto& draw = getDrawingDisplayState(displayToken); EXPECT_EQ(DisplayDevice::DISPLAY_PRIMARY, draw.type); - EXPECT_CALL(*mComposer, setVsyncEnabled(0, IComposerClient::Vsync::DISABLE)) - .WillOnce(Return(Error::NONE)); + // -------------------------------------------------------------------- + // Cleanup conditions - EXPECT_CALL(*mConsumer, consumerDisconnect()).Times(1); + EXPECT_CALL(*mComposer, setVsyncEnabled(displayId, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/MockComposer.h b/services/surfaceflinger/tests/unittests/MockComposer.h index acd9b3099a..00e565b75c 100644 --- a/services/surfaceflinger/tests/unittests/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/MockComposer.h @@ -29,10 +29,10 @@ namespace mock { using android::hardware::graphics::common::V1_0::ColorMode; using android::hardware::graphics::common::V1_0::ColorTransform; -using android::hardware::graphics::common::V1_0::Dataspace; using android::hardware::graphics::common::V1_0::Hdr; -using android::hardware::graphics::common::V1_0::PixelFormat; using android::hardware::graphics::common::V1_0::Transform; +using android::hardware::graphics::common::V1_1::Dataspace; +using android::hardware::graphics::common::V1_1::PixelFormat; using android::hardware::graphics::composer::V2_1::Config; using android::hardware::graphics::composer::V2_1::Display; diff --git a/services/surfaceflinger/tests/unittests/MockDisplaySurface.cpp b/services/surfaceflinger/tests/unittests/MockDisplaySurface.cpp new file mode 100644 index 0000000000..507626bf8f --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockDisplaySurface.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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 "MockDisplaySurface.h" + +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +DisplaySurface::DisplaySurface() = default; +DisplaySurface::~DisplaySurface() = default; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockDisplaySurface.h b/services/surfaceflinger/tests/unittests/MockDisplaySurface.h new file mode 100644 index 0000000000..d6c9aa46b4 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockDisplaySurface.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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 <gmock/gmock.h> + +#include <utils/String8.h> + +#include "DisplayHardware/DisplaySurface.h" + +namespace android { +namespace mock { + +class DisplaySurface : public android::DisplaySurface { +public: + DisplaySurface(); + ~DisplaySurface() override; + + MOCK_METHOD1(beginFrame, status_t(bool mustRecompose)); + MOCK_METHOD1(prepareFrame, status_t(CompositionType compositionType)); + MOCK_METHOD0(advanceFrame, status_t()); + MOCK_METHOD0(onFrameCommitted, void()); + MOCK_CONST_METHOD1(dumpAsString, void(String8& result)); + MOCK_METHOD2(resizeBuffers, void(uint32_t, uint32_t)); + MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&()); +}; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockEventControlThread.cpp b/services/surfaceflinger/tests/unittests/MockEventControlThread.cpp new file mode 100644 index 0000000000..398fd42542 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockEventControlThread.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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 "MockEventControlThread.h" + +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +EventControlThread::EventControlThread() = default; +EventControlThread::~EventControlThread() = default; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockEventControlThread.h b/services/surfaceflinger/tests/unittests/MockEventControlThread.h new file mode 100644 index 0000000000..8ac09a962d --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockEventControlThread.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 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 <gmock/gmock.h> + +#include "EventControlThread.h" + +namespace android { +namespace mock { + +class EventControlThread : public android::EventControlThread { +public: + EventControlThread(); + ~EventControlThread() override; + + MOCK_METHOD1(setVsyncEnabled, void(bool)); +}; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockMessageQueue.cpp b/services/surfaceflinger/tests/unittests/MockMessageQueue.cpp new file mode 100644 index 0000000000..62f45edd31 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockMessageQueue.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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 "MockMessageQueue.h" + +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +MessageQueue::MessageQueue() = default; +MessageQueue::~MessageQueue() = default; + +} // namespace mock +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/MockMessageQueue.h new file mode 100644 index 0000000000..cf07cf7ba9 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockMessageQueue.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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 <gmock/gmock.h> + +#include "MessageQueue.h" + +namespace android { +namespace mock { + +class MessageQueue : public android::MessageQueue { +public: + MessageQueue(); + ~MessageQueue() override; + + MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&)); + MOCK_METHOD1(setEventThread, void(android::EventThread*)); + MOCK_METHOD0(waitMessage, void()); + MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t)); + MOCK_METHOD0(invalidate, void()); + MOCK_METHOD0(refresh, void()); +}; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockNativeWindow.cpp b/services/surfaceflinger/tests/unittests/MockNativeWindow.cpp new file mode 100644 index 0000000000..61038f4879 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockNativeWindow.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018 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 "MockNativeWindow.h" + +namespace android { +namespace mock { +namespace { + +int dispatch_setSwapInterval(struct ANativeWindow* window, int interval) { + return static_cast<NativeWindow*>(window)->setSwapInterval(interval); +} + +int dispatch_dequeueBuffer_DEPRECATED(struct ANativeWindow* window, + struct ANativeWindowBuffer** buffer) { + return static_cast<NativeWindow*>(window)->dequeueBuffer_DEPRECATED(buffer); +} + +int dispatch_lockBuffer_DEPRECATED(struct ANativeWindow* window, + struct ANativeWindowBuffer* buffer) { + return static_cast<NativeWindow*>(window)->lockBuffer_DEPRECATED(buffer); +} + +int dispatch_queueBuffer_DEPRECATED(struct ANativeWindow* window, + struct ANativeWindowBuffer* buffer) { + return static_cast<NativeWindow*>(window)->queueBuffer_DEPRECATED(buffer); +} + +int dispatch_query(const struct ANativeWindow* window, int what, int* value) { + return static_cast<const NativeWindow*>(window)->query(what, value); +} + +int dispatch_perform(struct ANativeWindow* window, int operation, ...) { + // TODO: Handle the various operations and their varargs better. + return static_cast<NativeWindow*>(window)->perform(operation); +} + +int dispatch_cancelBuffer_DEPRECATED(struct ANativeWindow* window, + struct ANativeWindowBuffer* buffer) { + return static_cast<NativeWindow*>(window)->cancelBuffer_DEPRECATED(buffer); +} + +int dispatch_dequeueBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer** buffer, + int* fenceFd) { + return static_cast<NativeWindow*>(window)->dequeueBuffer(buffer, fenceFd); +} + +int dispatch_queueBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, + int fenceFd) { + return static_cast<NativeWindow*>(window)->queueBuffer(buffer, fenceFd); +} + +int dispatch_cancelBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, + int fenceFd) { + return static_cast<NativeWindow*>(window)->cancelBuffer(buffer, fenceFd); +} + +} // namespace + +NativeWindow::NativeWindow() { + // ANativeWindow is a structure with function pointers and not a C++ class. + // Set all the pointers to dispatch functions, which will invoke the mock + // interface functions. + ANativeWindow::setSwapInterval = &dispatch_setSwapInterval; + ANativeWindow::dequeueBuffer_DEPRECATED = &dispatch_dequeueBuffer_DEPRECATED; + ANativeWindow::lockBuffer_DEPRECATED = &dispatch_lockBuffer_DEPRECATED; + ANativeWindow::queueBuffer_DEPRECATED = &dispatch_queueBuffer_DEPRECATED; + ANativeWindow::query = &dispatch_query; + ANativeWindow::perform = &dispatch_perform; + ANativeWindow::cancelBuffer_DEPRECATED = &dispatch_cancelBuffer_DEPRECATED; + ANativeWindow::dequeueBuffer = &dispatch_dequeueBuffer; + ANativeWindow::queueBuffer = &dispatch_queueBuffer; + ANativeWindow::cancelBuffer = &dispatch_cancelBuffer; +} + +// Explicit default instantiation is recommended. +NativeWindow::~NativeWindow() = default; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockNativeWindow.h b/services/surfaceflinger/tests/unittests/MockNativeWindow.h new file mode 100644 index 0000000000..561fd5869e --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockNativeWindow.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 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 <gmock/gmock.h> + +#include <system/window.h> + +#include <ui/ANativeObjectBase.h> + +namespace android { +namespace mock { + +class NativeWindow : public ANativeObjectBase<ANativeWindow, NativeWindow, RefBase> { +public: + NativeWindow(); + ~NativeWindow(); + + MOCK_METHOD1(setSwapInterval, int(int interval)); + MOCK_METHOD1(dequeueBuffer_DEPRECATED, int(struct ANativeWindowBuffer**)); + MOCK_METHOD1(lockBuffer_DEPRECATED, int(struct ANativeWindowBuffer*)); + MOCK_METHOD1(queueBuffer_DEPRECATED, int(struct ANativeWindowBuffer*)); + MOCK_CONST_METHOD2(query, int(int, int*)); + MOCK_METHOD1(perform, int(int)); + MOCK_METHOD1(cancelBuffer_DEPRECATED, int(struct ANativeWindowBuffer*)); + MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*)); + MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int)); + MOCK_METHOD2(cancelBuffer, int(struct ANativeWindowBuffer*, int)); +}; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.cpp b/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.cpp new file mode 100644 index 0000000000..0314568519 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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 "MockNativeWindowSurface.h" + +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +NativeWindowSurface::NativeWindowSurface() = default; +NativeWindowSurface::~NativeWindowSurface() = default; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.h b/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.h new file mode 100644 index 0000000000..88d1a9fc51 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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 <gmock/gmock.h> + +#include <system/window.h> // for ANativeWindow + +#include "SurfaceFlinger.h" // for base NativeWindowSurface + +namespace android { +namespace mock { + +class NativeWindowSurface : public android::NativeWindowSurface { +public: + NativeWindowSurface(); + ~NativeWindowSurface(); + + MOCK_CONST_METHOD0(getNativeWindow, sp<ANativeWindow>()); + MOCK_METHOD0(preallocateBuffers, void()); +}; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/MockRenderEngine.h index 6d3e17ff73..9bb2a3c961 100644 --- a/services/surfaceflinger/tests/unittests/MockRenderEngine.h +++ b/services/surfaceflinger/tests/unittests/MockRenderEngine.h @@ -64,8 +64,8 @@ public: MOCK_METHOD0(disableTexturing, void()); MOCK_METHOD0(disableBlending, void()); MOCK_METHOD1(setSourceY410BT2020, void(bool)); - MOCK_METHOD1(setSourceDataSpace, void(android_dataspace)); - MOCK_METHOD1(setOutputDataSpace, void(android_dataspace)); + MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace)); + MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace)); MOCK_METHOD2(bindNativeBufferAsFrameBuffer, void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*)); MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*)); diff --git a/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.cpp b/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.cpp new file mode 100644 index 0000000000..b2ec721f44 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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 "MockSurfaceInterceptor.h" + +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +SurfaceInterceptor::SurfaceInterceptor() = default; +SurfaceInterceptor::~SurfaceInterceptor() = default; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.h new file mode 100644 index 0000000000..458b2f3da2 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018 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 <gmock/gmock.h> + +#include "SurfaceInterceptor.h" + +namespace android { +namespace mock { + +class SurfaceInterceptor : public android::SurfaceInterceptor { +public: + SurfaceInterceptor(); + ~SurfaceInterceptor() override; + + MOCK_METHOD2(enable, + void(const SortedVector<sp<Layer>>&, + const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&)); + MOCK_METHOD0(disable, void()); + MOCK_METHOD0(isEnabled, bool()); + MOCK_METHOD4(saveTransaction, + void(const Vector<ComposerState>&, + const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&, + const Vector<DisplayState>&, uint32_t)); + MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&)); + MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&)); + MOCK_METHOD4(saveBufferUpdate, void(const sp<const Layer>&, uint32_t, uint32_t, uint64_t)); + MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&)); + MOCK_METHOD1(saveDisplayDeletion, void(int32_t)); + MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t)); + MOCK_METHOD1(saveVSyncEvent, void(nsecs_t)); +}; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4895e16d31..2dd8e5f50f 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -44,33 +44,44 @@ public: mFlinger->getBE().mHwc.reset(new HWComposer(std::move(composer))); } - void setupPrimaryDisplay() { - mFlinger->getBE().mHwc->mHwcDevice->onHotplug(0, HWC2::Connection::Connected); - mFlinger->getBE().mHwc->onHotplug(0, DisplayDevice::DISPLAY_PRIMARY, - HWC2::Connection::Connected); - } - using CreateBufferQueueFunction = SurfaceFlinger::CreateBufferQueueFunction; - void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { mFlinger->mCreateBufferQueue = f; } + using CreateNativeWindowSurfaceFunction = SurfaceFlinger::CreateNativeWindowSurfaceFunction; + void setCreateNativeWindowSurface(CreateNativeWindowSurfaceFunction f) { + mFlinger->mCreateNativeWindowSurface = f; + } + + using HotplugEvent = SurfaceFlinger::HotplugEvent; + /* ------------------------------------------------------------------------ * Forwarding for functions being tested */ - auto processDisplayChangesLocked() { return mFlinger->processDisplayChangesLocked(); } + + auto handleTransactionLocked(uint32_t transactionFlags) { + return mFlinger->handleTransactionLocked(transactionFlags); + } /* ------------------------------------------------------------------------ * Read-write access to private data to set up preconditions and assert * post-conditions. */ + auto& mutableBuiltinDisplays() { return mFlinger->mBuiltinDisplays; } - auto& mutableDisplays() { return mFlinger->mDisplays; } auto& mutableCurrentState() { return mFlinger->mCurrentState; } + auto& mutableDisplays() { return mFlinger->mDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } - auto& mutableEventThread() { return mFlinger->mEventThread; } + auto& mutableEventControlThread() { return mFlinger->mEventControlThread; } auto& mutableEventQueue() { return mFlinger->mEventQueue; } + auto& mutableEventThread() { return mFlinger->mEventThread; } + auto& mutableInterceptor() { return mFlinger->mInterceptor; } + auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } + auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } + + auto& mutableHwcDisplayData() { return mFlinger->getBE().mHwc->mDisplayData; } + auto& mutableHwcDisplaySlots() { return mFlinger->getBE().mHwc->mHwcDisplaySlots; } ~TestableSurfaceFlinger() { // All these pointer and container clears help ensure that GMock does @@ -78,12 +89,33 @@ public: // still be referenced by something despite our best efforts to destroy // it after each test is done. mutableDisplays().clear(); + mutableEventControlThread().reset(); + mutableEventQueue().reset(); mutableEventThread().reset(); + mutableInterceptor().reset(); mFlinger->getBE().mHwc.reset(); mFlinger->getBE().mRenderEngine.reset(); } - sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(); + /* ------------------------------------------------------------------------ + * Wrapper classes for Read-write access to private data to set up + * preconditions and assert post-conditions. + */ + struct HWC2Display : public HWC2::Display { + HWC2Display(Hwc2::Composer& composer, + const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id, + HWC2::DisplayType type) + : HWC2::Display(composer, capabilities, id, type) {} + ~HWC2Display() { + // Prevents a call to disable vsyncs. + mType = HWC2::DisplayType::Invalid; + } + + auto& mutableIsConnected() { return this->mIsConnected; } + auto& mutableConfigs() { return this->mConfigs; } + }; + + sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization); }; } // namespace android diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index e141b91286..c38c12b7b1 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp @@ -134,7 +134,6 @@ ProducerChannel::~ProducerChannel() { channel_id(), buffer_id(), buffer_state_->load()); for (auto consumer : consumer_channels_) { consumer->OnProducerClosed(); - service()->SetChannel(consumer->channel_id(), nullptr); } Hangup(); } diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index dec39e0b0f..741fbb812b 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -500,13 +500,36 @@ void CreateInfoWrapper::FilterExtension(const char* name) { // both we and HAL can take part in hook_extensions_.set(ext_bit); break; - case ProcHook::EXTENSION_UNKNOWN: case ProcHook::KHR_get_physical_device_properties2: - // HAL's extensions + case ProcHook::EXTENSION_UNKNOWN: + // Extensions we don't need to do anything about at this level break; - default: - ALOGW("Ignored invalid instance extension %s", name); + + case ProcHook::KHR_incremental_present: + case ProcHook::KHR_shared_presentable_image: + case ProcHook::KHR_swapchain: + case ProcHook::EXT_hdr_metadata: + case ProcHook::ANDROID_external_memory_android_hardware_buffer: + case ProcHook::ANDROID_native_buffer: + case ProcHook::GOOGLE_display_timing: + case ProcHook::EXTENSION_CORE: + case ProcHook::EXTENSION_COUNT: + // Device and meta extensions. If we ever get here it's a bug in + // our code. But enumerating them lets us avoid having a default + // case, and default hides other bugs. + ALOGE( + "CreateInfoWrapper::FilterExtension: invalid instance " + "extension '%s'. FIX ME", + name); return; + + // Don't use a default case. Without it, -Wswitch will tell us + // at compile time if someone adds a new ProcHook extension but + // doesn't handle it above. That's a real bug that has + // not-immediately-obvious effects. + // + // default: + // break; } } else { switch (ext_bit) { @@ -524,12 +547,36 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::EXT_hdr_metadata: hook_extensions_.set(ext_bit); break; + case ProcHook::ANDROID_external_memory_android_hardware_buffer: case ProcHook::EXTENSION_UNKNOWN: - // HAL's extensions + // Extensions we don't need to do anything about at this level break; - default: - ALOGW("Ignored invalid device extension %s", name); + + case ProcHook::KHR_android_surface: + case ProcHook::KHR_get_physical_device_properties2: + case ProcHook::KHR_get_surface_capabilities2: + case ProcHook::KHR_surface: + case ProcHook::EXT_debug_report: + case ProcHook::EXT_swapchain_colorspace: + case ProcHook::ANDROID_native_buffer: + case ProcHook::EXTENSION_CORE: + case ProcHook::EXTENSION_COUNT: + // Instance and meta extensions. If we ever get here it's a bug + // in our code. But enumerating them lets us avoid having a + // default case, and default hides other bugs. + ALOGE( + "CreateInfoWrapper::FilterExtension: invalid device " + "extension '%s'. FIX ME", + name); return; + + // Don't use a default case. Without it, -Wswitch will tell us + // at compile time if someone adds a new ProcHook extension but + // doesn't handle it above. That's a real bug that has + // not-immediately-obvious effects. + // + // default: + // break; } } |