Merge changes from topic "blast-callback"
* changes:
blast: send TransactionStats with callback
blast: Send transaction callback
blast: Send transaction listener from SCC to SF
blast: Create ITransactionCompletedListener
blast: set layers to scale to window
blast: update hasDrawingBuffer to hasFrameUpdate
diff --git a/libs/gui/CleanSpec.mk b/CleanSpec.mk
similarity index 70%
rename from libs/gui/CleanSpec.mk
rename to CleanSpec.mk
index 5a5144c..1855d26 100644
--- a/libs/gui/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 The Android Open Source Project
+# 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.
@@ -34,19 +34,23 @@
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/thermalserviced)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/thermalservice.rc)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 50a2412..90cadb4 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -201,53 +201,23 @@
}
}
-// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
-// need to be performed between the fork and exec.
-class ExecVHelper {
- public:
- // Store a placeholder for the binary name.
- ExecVHelper() : args_(1u, std::string()) {}
-
- void PrepareArgs(const std::string& bin) {
- CHECK(!args_.empty());
- CHECK(args_[0].empty());
- args_[0] = bin;
- // Write char* into array.
- for (const std::string& arg : args_) {
- argv_.push_back(arg.c_str());
- }
- argv_.push_back(nullptr); // Add null terminator.
+// Automatically adds binary and null terminator arg.
+static inline void ExecVWithArgs(const char* bin, const std::vector<std::string>& args) {
+ std::vector<const char*> argv = {bin};
+ for (const std::string& arg : args) {
+ argv.push_back(arg.c_str());
}
+ // Add null terminator.
+ argv.push_back(nullptr);
+ execv(bin, (char * const *)&argv[0]);
+}
- [[ noreturn ]]
- void Exec(int exit_code) {
- execv(argv_[0], (char * const *)&argv_[0]);
- PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
- exit(exit_code);
+static inline void AddArgIfNonEmpty(const std::string& arg, std::vector<std::string>* args) {
+ DCHECK(args != nullptr);
+ if (!arg.empty()) {
+ args->push_back(arg);
}
-
- // Add an arg if it's not empty.
- void AddArg(const std::string& arg) {
- if (!arg.empty()) {
- args_.push_back(arg);
- }
- }
-
- // Add a runtime arg if it's not empty.
- void AddRuntimeArg(const std::string& arg) {
- if (!arg.empty()) {
- args_.push_back("--runtime-arg");
- args_.push_back(arg);
- }
- }
-
- protected:
- // Holder arrays for backing arg storage.
- std::vector<std::string> args_;
-
- // Argument poiners.
- std::vector<const char*> argv_;
-};
+}
static std::string MapPropertyToArg(const std::string& property,
const std::string& format,
@@ -259,220 +229,212 @@
return "";
}
-class RunDex2Oat : public ExecVHelper {
- public:
- RunDex2Oat(int zip_fd,
- int oat_fd,
- int input_vdex_fd,
- int output_vdex_fd,
- int image_fd,
- const char* input_file_name,
- const char* output_file_name,
- int swap_fd,
- const char* instruction_set,
- const char* compiler_filter,
- bool debuggable,
- bool post_bootcomplete,
- bool background_job_compile,
- int profile_fd,
- const char* class_loader_context,
- int target_sdk_version,
- bool enable_hidden_api_checks,
- bool generate_compact_dex,
- int dex_metadata_fd,
- const char* compilation_reason) {
- // Get the relative path to the input file.
- const char* relative_input_file_name = get_location_from_path(input_file_name);
+[[ noreturn ]]
+static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
+ const char* input_file_name, const char* output_file_name, int swap_fd,
+ const char* instruction_set, const char* compiler_filter,
+ bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
+ const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
+ bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
+ // Get the relative path to the input file.
+ const char* relative_input_file_name = get_location_from_path(input_file_name);
- std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
- std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
+ std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
+ std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
- const char* threads_property = post_bootcomplete
- ? "dalvik.vm.dex2oat-threads"
- : "dalvik.vm.boot-dex2oat-threads";
- std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
+ const char* threads_property = post_bootcomplete
+ ? "dalvik.vm.dex2oat-threads"
+ : "dalvik.vm.boot-dex2oat-threads";
+ std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
- const std::string dex2oat_isa_features_key =
- StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
- std::string instruction_set_features_arg =
- MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
+ const std::string dex2oat_isa_features_key =
+ StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+ std::string instruction_set_features_arg =
+ MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
- const std::string dex2oat_isa_variant_key =
- StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
- std::string instruction_set_variant_arg =
- MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
+ const std::string dex2oat_isa_variant_key =
+ StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+ std::string instruction_set_variant_arg =
+ MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
- const char* dex2oat_norelocation = "-Xnorelocate";
+ const char *dex2oat_norelocation = "-Xnorelocate";
- const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
- std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
- ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
+ const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
+ std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
+ ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
- // If we are booting without the real /data, don't spend time compiling.
- std::string vold_decrypt = GetProperty("vold.decrypt", "");
- bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
- vold_decrypt == "1";
+ // If we are booting without the real /data, don't spend time compiling.
+ std::string vold_decrypt = GetProperty("vold.decrypt", "");
+ bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+ vold_decrypt == "1";
- const std::string resolve_startup_string_arg =
- MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
- "--resolve-startup-const-strings=%s");
- const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
+ const std::string resolve_startup_string_arg =
+ MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+ "--resolve-startup-const-strings=%s");
+ const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
- std::string image_format_arg;
- if (image_fd >= 0) {
- image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
- }
-
- std::string dex2oat_large_app_threshold_arg =
- MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
-
- // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
- const char* dex2oat_bin = "/system/bin/dex2oat";
- constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
- // Do not use dex2oatd for release candidates (give dex2oat more soak time).
- bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
- if (is_debug_runtime() ||
- (background_job_compile && is_debuggable_build() && !is_release)) {
- if (access(kDex2oatDebugPath, X_OK) == 0) {
- dex2oat_bin = kDex2oatDebugPath;
- }
- }
-
- bool generate_minidebug_info = kEnableMinidebugInfo &&
- GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
-
- // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
- // use arraysize instead.
- std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
- std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
- std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
- std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
- std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
- std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
- std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
- std::string dex2oat_compiler_filter_arg;
- std::string dex2oat_swap_fd;
- std::string dex2oat_image_fd;
- std::string target_sdk_version_arg;
- if (target_sdk_version != 0) {
- StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
- }
- std::string class_loader_context_arg;
- if (class_loader_context != nullptr) {
- class_loader_context_arg = StringPrintf("--class-loader-context=%s",
- class_loader_context);
- }
-
- if (swap_fd >= 0) {
- dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
- }
- if (image_fd >= 0) {
- dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
- }
-
- // Compute compiler filter.
- bool have_dex2oat_relocation_skip_flag = false;
- if (skip_compilation) {
- dex2oat_compiler_filter_arg = "--compiler-filter=extract";
- have_dex2oat_relocation_skip_flag = true;
- } else if (compiler_filter != nullptr) {
- dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
- }
-
- if (dex2oat_compiler_filter_arg.empty()) {
- dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
- "--compiler-filter=%s");
- }
-
- // Check whether all apps should be compiled debuggable.
- if (!debuggable) {
- debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
- }
- std::string profile_arg;
- if (profile_fd != -1) {
- profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
- }
-
- // Get the directory of the apk to pass as a base classpath directory.
- std::string base_dir;
- std::string apk_dir(input_file_name);
- unsigned long dir_index = apk_dir.rfind('/');
- bool has_base_dir = dir_index != std::string::npos;
- if (has_base_dir) {
- apk_dir = apk_dir.substr(0, dir_index);
- base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
- }
-
- std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
- std::string compilation_reason_arg = compilation_reason == nullptr
- ? ""
- : std::string("--compilation-reason=") + compilation_reason;
-
- ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
-
- // Disable cdex if update input vdex is true since this combination of options is not
- // supported.
- const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
- AddArg(zip_fd_arg);
- AddArg(zip_location_arg);
- AddArg(input_vdex_fd_arg);
- AddArg(output_vdex_fd_arg);
- AddArg(oat_fd_arg);
- AddArg(oat_location_arg);
- AddArg(instruction_set_arg);
-
- AddArg(instruction_set_variant_arg);
- AddArg(instruction_set_features_arg);
-
- AddRuntimeArg(dex2oat_Xms_arg);
- AddRuntimeArg(dex2oat_Xmx_arg);
-
- AddArg(resolve_startup_string_arg);
- AddArg(dex2oat_compiler_filter_arg);
- AddArg(dex2oat_threads_arg);
- AddArg(dex2oat_swap_fd);
- AddArg(dex2oat_image_fd);
-
- if (generate_debug_info) {
- AddArg("--generate-debug-info");
- }
- if (debuggable) {
- AddArg("--debuggable");
- }
- AddArg(image_format_arg);
- AddArg(dex2oat_large_app_threshold_arg);
-
- if (have_dex2oat_relocation_skip_flag) {
- AddRuntimeArg(dex2oat_norelocation);
- }
- AddArg(profile_arg);
- AddArg(base_dir);
- AddArg(class_loader_context_arg);
- if (generate_minidebug_info) {
- AddArg(kMinidebugDex2oatFlag);
- }
- if (disable_cdex) {
- AddArg(kDisableCompactDexFlag);
- }
- AddArg(target_sdk_version_arg);
- if (enable_hidden_api_checks) {
- AddRuntimeArg("-Xhidden-api-checks");
- }
-
- if (dex_metadata_fd > -1) {
- AddArg(dex_metadata_fd_arg);
- }
-
- AddArg(compilation_reason_arg);
-
- // Do not add args after dex2oat_flags, they should override others for debugging.
- args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
-
- PrepareArgs(dex2oat_bin);
+ std::string image_format_arg;
+ if (image_fd >= 0) {
+ image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
}
-};
+
+ std::string dex2oat_large_app_threshold_arg =
+ MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
+
+ // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
+ const char* dex2oat_bin = "/system/bin/dex2oat";
+ constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+ // Do not use dex2oatd for release candidates (give dex2oat more soak time).
+ bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
+ if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) {
+ if (access(kDex2oatDebugPath, X_OK) == 0) {
+ dex2oat_bin = kDex2oatDebugPath;
+ }
+ }
+
+ bool generate_minidebug_info = kEnableMinidebugInfo &&
+ android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
+ kMinidebugInfoSystemPropertyDefault);
+
+ // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
+ // use arraysize instead.
+ std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
+ std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
+ std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
+ std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
+ std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
+ std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
+ std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
+ std::string dex2oat_compiler_filter_arg;
+ std::string dex2oat_swap_fd;
+ std::string dex2oat_image_fd;
+ std::string target_sdk_version_arg;
+ if (target_sdk_version != 0) {
+ StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+ }
+ std::string class_loader_context_arg;
+ if (class_loader_context != nullptr) {
+ class_loader_context_arg = StringPrintf("--class-loader-context=%s", class_loader_context);
+ }
+
+ if (swap_fd >= 0) {
+ dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
+ }
+ if (image_fd >= 0) {
+ dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
+ }
+
+ // Compute compiler filter.
+ bool have_dex2oat_relocation_skip_flag = false;
+ if (skip_compilation) {
+ dex2oat_compiler_filter_arg = "--compiler-filter=extract";
+ have_dex2oat_relocation_skip_flag = true;
+ } else if (compiler_filter != nullptr) {
+ dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
+ }
+
+ if (dex2oat_compiler_filter_arg.empty()) {
+ dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+ "--compiler-filter=%s");
+ }
+
+ // Check whether all apps should be compiled debuggable.
+ if (!debuggable) {
+ debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
+ }
+ std::string profile_arg;
+ if (profile_fd != -1) {
+ profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
+ }
+
+ // Get the directory of the apk to pass as a base classpath directory.
+ std::string base_dir;
+ std::string apk_dir(input_file_name);
+ unsigned long dir_index = apk_dir.rfind('/');
+ bool has_base_dir = dir_index != std::string::npos;
+ if (has_base_dir) {
+ apk_dir = apk_dir.substr(0, dir_index);
+ base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
+ }
+
+ std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
+
+ std::string compilation_reason_arg = compilation_reason == nullptr
+ ? ""
+ : std::string("--compilation-reason=") + compilation_reason;
+
+ ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
+
+ // Disable cdex if update input vdex is true since this combination of options is not
+ // supported.
+ const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
+
+ std::vector<std::string> args = {
+ zip_fd_arg,
+ zip_location_arg,
+ input_vdex_fd_arg,
+ output_vdex_fd_arg,
+ oat_fd_arg,
+ oat_location_arg,
+ instruction_set_arg,
+ };
+ auto add_runtime_arg = [&](const std::string& arg) {
+ args.push_back("--runtime-arg");
+ args.push_back(arg);
+ };
+
+ AddArgIfNonEmpty(instruction_set_variant_arg, &args);
+ AddArgIfNonEmpty(instruction_set_features_arg, &args);
+ if (!dex2oat_Xms_arg.empty()) {
+ add_runtime_arg(dex2oat_Xms_arg);
+ }
+ if (!dex2oat_Xmx_arg.empty()) {
+ add_runtime_arg(dex2oat_Xmx_arg);
+ }
+ AddArgIfNonEmpty(resolve_startup_string_arg, &args);
+ AddArgIfNonEmpty(dex2oat_compiler_filter_arg, &args);
+ AddArgIfNonEmpty(dex2oat_threads_arg, &args);
+ AddArgIfNonEmpty(dex2oat_swap_fd, &args);
+ AddArgIfNonEmpty(dex2oat_image_fd, &args);
+
+ if (generate_debug_info) {
+ args.push_back("--generate-debug-info");
+ }
+ if (debuggable) {
+ args.push_back("--debuggable");
+ }
+ AddArgIfNonEmpty(image_format_arg, &args);
+ AddArgIfNonEmpty(dex2oat_large_app_threshold_arg, &args);
+ args.insert(args.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
+ if (have_dex2oat_relocation_skip_flag) {
+ add_runtime_arg(dex2oat_norelocation);
+ }
+ AddArgIfNonEmpty(profile_arg, &args);
+ AddArgIfNonEmpty(base_dir, &args);
+ AddArgIfNonEmpty(class_loader_context_arg, &args);
+ if (generate_minidebug_info) {
+ args.push_back(kMinidebugDex2oatFlag);
+ }
+ if (disable_cdex) {
+ args.push_back(kDisableCompactDexFlag);
+ }
+ AddArgIfNonEmpty(target_sdk_version_arg, &args);
+ if (enable_hidden_api_checks) {
+ add_runtime_arg("-Xhidden-api-checks");
+ }
+
+ if (dex_metadata_fd > -1) {
+ args.push_back(dex_metadata_fd_arg);
+ }
+
+ AddArgIfNonEmpty(compilation_reason_arg, &args);
+
+ // Do not add after dex2oat_flags, they should override others for debugging.
+
+ ExecVWithArgs(dex2oat_bin, args);
+ PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
+ exit(DexoptReturnCodes::kDex2oatExec);
+}
/*
* Whether dexopt should use a swap file when compiling an APK.
@@ -648,85 +610,74 @@
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
-class RunProfman : public ExecVHelper {
- public:
- void SetupArgs(const std::vector<unique_fd>& profile_fds,
- const unique_fd& reference_profile_fd,
- const std::vector<unique_fd>& apk_fds,
- const std::vector<std::string>& dex_locations,
- bool copy_and_update) {
- const char* profman_bin =
- is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+[[ noreturn ]]
+static void run_profman(const std::vector<unique_fd>& profile_fds,
+ const unique_fd& reference_profile_fd,
+ const std::vector<unique_fd>* apk_fds,
+ const std::vector<std::string>* dex_locations,
+ bool copy_and_update) {
+ const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
- if (copy_and_update) {
- CHECK_EQ(1u, profile_fds.size());
- CHECK_EQ(1u, apk_fds.size());
- }
- if (reference_profile_fd != -1) {
- AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
- }
+ if (copy_and_update) {
+ CHECK_EQ(1u, profile_fds.size());
+ CHECK(apk_fds != nullptr);
+ CHECK_EQ(1u, apk_fds->size());
+ }
+ std::vector<std::string> args;
+ args.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
- for (const unique_fd& fd : profile_fds) {
- AddArg("--profile-file-fd=" + std::to_string(fd.get()));
- }
-
- for (const unique_fd& fd : apk_fds) {
- AddArg("--apk-fd=" + std::to_string(fd.get()));
- }
-
- for (const std::string& dex_location : dex_locations) {
- AddArg("--dex-location=" + dex_location);
- }
-
- if (copy_and_update) {
- AddArg("--copy-and-update-profile-key");
- }
-
- // Do not add after dex2oat_flags, they should override others for debugging.
- PrepareArgs(profman_bin);
+ for (const unique_fd& fd : profile_fds) {
+ args.push_back("--profile-file-fd=" + std::to_string(fd.get()));
}
- void SetupMerge(const std::vector<unique_fd>& profiles_fd,
- const unique_fd& reference_profile_fd,
- const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
- const std::vector<std::string>& dex_locations = std::vector<std::string>()) {
- SetupArgs(profiles_fd,
- reference_profile_fd,
- apk_fds,
- dex_locations,
- /*copy_and_update=*/false);
+ if (apk_fds != nullptr) {
+ for (const unique_fd& fd : *apk_fds) {
+ args.push_back("--apk-fd=" + std::to_string(fd.get()));
+ }
}
- void SetupCopyAndUpdate(unique_fd&& profile_fd,
- unique_fd&& reference_profile_fd,
- unique_fd&& apk_fd,
- const std::string& dex_location) {
- std::vector<unique_fd> profiles_fd;
- profiles_fd.push_back(std::move(profile_fd));
- std::vector<unique_fd> apk_fds;
- profiles_fd.push_back(std::move(apk_fd));
- std::vector<std::string> dex_locations = {dex_location};
- SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
- /*copy_and_update=*/true);
+ std::vector<std::string> dex_location_args;
+ if (dex_locations != nullptr) {
+ for (const std::string& dex_location : *dex_locations) {
+ args.push_back("--dex-location=" + dex_location);
+ }
}
- void SetupDump(const std::vector<unique_fd>& profiles_fd,
- const unique_fd& reference_profile_fd,
- const std::vector<std::string>& dex_locations,
- const std::vector<unique_fd>& apk_fds,
- const unique_fd& output_fd) {
- AddArg("--dump-only");
- AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
- SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
- /*copy_and_update=*/false);
+ if (copy_and_update) {
+ args.push_back("--copy-and-update-profile-key");
}
- void Exec() {
- ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
- }
-};
+ // Do not add after dex2oat_flags, they should override others for debugging.
+ ExecVWithArgs(profman_bin, args);
+ PLOG(ERROR) << "execv(" << profman_bin << ") failed";
+ exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */
+}
+[[ noreturn ]]
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+ const unique_fd& reference_profile_fd,
+ const std::vector<unique_fd>* apk_fds = nullptr,
+ const std::vector<std::string>* dex_locations = nullptr) {
+ run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
+ /*copy_and_update*/false);
+}
+
+[[ noreturn ]]
+static void run_profman_copy_and_update(unique_fd&& profile_fd,
+ unique_fd&& reference_profile_fd,
+ unique_fd&& apk_fd,
+ const std::string& dex_location) {
+ std::vector<unique_fd> profiles_fd;
+ profiles_fd.push_back(std::move(profile_fd));
+ std::vector<unique_fd> apk_fds;
+ apk_fds.push_back(std::move(apk_fd));
+ std::vector<std::string> dex_locations;
+ dex_locations.push_back(dex_location);
+
+ run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations,
+ /*copy_and_update*/true);
+}
// Decides if profile guided compilation is needed or not based on existing profiles.
// The location is the package name for primary apks or the dex path for secondary dex files.
@@ -746,13 +697,11 @@
return false;
}
- RunProfman profman_merge;
- profman_merge.SetupMerge(profiles_fd, reference_profile_fd);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
drop_capabilities(uid);
- profman_merge.Exec();
+ run_profman_merge(profiles_fd, reference_profile_fd);
}
/* parent */
int return_code = wait_child(pid);
@@ -825,6 +774,35 @@
return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
}
+[[ noreturn ]]
+static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
+ const unique_fd& reference_profile_fd,
+ const std::vector<std::string>& dex_locations,
+ const std::vector<unique_fd>& apk_fds,
+ const unique_fd& output_fd) {
+ std::vector<std::string> profman_args;
+ static const char* PROFMAN_BIN = "/system/bin/profman";
+ profman_args.push_back("--dump-only");
+ profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
+ if (reference_profile_fd != -1) {
+ profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
+ reference_profile_fd.get()));
+ }
+ for (size_t i = 0; i < profile_fds.size(); i++) {
+ profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get()));
+ }
+ for (const std::string& dex_location : dex_locations) {
+ profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
+ }
+ for (size_t i = 0; i < apk_fds.size(); i++) {
+ profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
+ }
+
+ ExecVWithArgs(PROFMAN_BIN, profman_args);
+ PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
+ exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */
+}
+
bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
const std::string& code_path) {
std::vector<unique_fd> profile_fds;
@@ -861,13 +839,12 @@
apk_fds.push_back(std::move(apk_fd));
- RunProfman profman_dump;
- profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
drop_capabilities(uid);
- profman_dump.Exec();
+ run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
+ apk_fds, output_fd);
}
/* parent */
int return_code = wait_child(pid);
@@ -1439,60 +1416,55 @@
// The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
// If this is for a profile guided compilation, profile_was_updated will tell whether or not
// the profile has changed.
-class RunDexoptAnalyzer : public ExecVHelper {
- public:
- RunDexoptAnalyzer(const std::string& dex_file,
- int vdex_fd,
- int oat_fd,
- int zip_fd,
- const std::string& instruction_set,
- const std::string& compiler_filter,
- bool profile_was_updated,
- bool downgrade,
- const char* class_loader_context) {
- CHECK_GE(zip_fd, 0);
- const char* dexoptanalyzer_bin =
- is_debug_runtime()
- ? "/system/bin/dexoptanalyzerd"
- : "/system/bin/dexoptanalyzer";
+static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oat_fd,
+ int zip_fd, const std::string& instruction_set, const std::string& compiler_filter,
+ bool profile_was_updated, bool downgrade,
+ const char* class_loader_context) {
+ CHECK_GE(zip_fd, 0);
+ const char* dexoptanalyzer_bin =
+ is_debug_runtime()
+ ? "/system/bin/dexoptanalyzerd"
+ : "/system/bin/dexoptanalyzer";
- std::string dex_file_arg = "--dex-file=" + dex_file;
- std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
- std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
- std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
- std::string isa_arg = "--isa=" + instruction_set;
- std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
- const char* assume_profile_changed = "--assume-profile-changed";
- const char* downgrade_flag = "--downgrade";
- std::string class_loader_context_arg = "--class-loader-context=";
- if (class_loader_context != nullptr) {
- class_loader_context_arg += class_loader_context;
- }
-
- // program name, dex file, isa, filter
- AddArg(dex_file_arg);
- AddArg(isa_arg);
- AddArg(compiler_filter_arg);
- if (oat_fd >= 0) {
- AddArg(oat_fd_arg);
- }
- if (vdex_fd >= 0) {
- AddArg(vdex_fd_arg);
- }
- AddArg(zip_fd_arg.c_str());
- if (profile_was_updated) {
- AddArg(assume_profile_changed);
- }
- if (downgrade) {
- AddArg(downgrade_flag);
- }
- if (class_loader_context != nullptr) {
- AddArg(class_loader_context_arg.c_str());
- }
-
- PrepareArgs(dexoptanalyzer_bin);
+ std::string dex_file_arg = "--dex-file=" + dex_file;
+ std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
+ std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
+ std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
+ std::string isa_arg = "--isa=" + instruction_set;
+ std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
+ const char* assume_profile_changed = "--assume-profile-changed";
+ const char* downgrade_flag = "--downgrade";
+ std::string class_loader_context_arg = "--class-loader-context=";
+ if (class_loader_context != nullptr) {
+ class_loader_context_arg += class_loader_context;
}
-};
+
+ // program name, dex file, isa, filter
+ std::vector<std::string> args = {
+ dex_file_arg,
+ isa_arg,
+ compiler_filter_arg,
+ };
+ if (oat_fd >= 0) {
+ args.push_back(oat_fd_arg);
+ }
+ if (vdex_fd >= 0) {
+ args.push_back(vdex_fd_arg);
+ }
+ args.push_back(zip_fd_arg.c_str());
+ if (profile_was_updated) {
+ args.push_back(assume_profile_changed);
+ }
+ if (downgrade) {
+ args.push_back(downgrade_flag);
+ }
+ if (class_loader_context != nullptr) {
+ args.push_back(class_loader_context_arg.c_str());
+ }
+
+ ExecVWithArgs(dexoptanalyzer_bin, args);
+ ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
+}
// Prepares the oat dir for the secondary dex files.
static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
@@ -1744,17 +1716,16 @@
/*is_secondary_dex*/true);
// Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
- // Note that we do not do it before the fork since opening the files is required to happen
- // after forking.
- RunDexoptAnalyzer run_dexopt_analyzer(dex_path,
- vdex_file_fd.get(),
- oat_file_fd.get(),
- zip_fd.get(),
- instruction_set,
- compiler_filter, profile_was_updated,
- downgrade,
- class_loader_context);
- run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+ exec_dexoptanalyzer(dex_path,
+ vdex_file_fd.get(),
+ oat_file_fd.get(),
+ zip_fd.get(),
+ instruction_set,
+ compiler_filter, profile_was_updated,
+ downgrade,
+ class_loader_context);
+ PLOG(ERROR) << "Failed to exec dexoptanalyzer";
+ _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
}
/* parent */
@@ -1923,27 +1894,6 @@
LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
- RunDex2Oat runner(input_fd.get(),
- out_oat_fd.get(),
- in_vdex_fd.get(),
- out_vdex_fd.get(),
- image_fd.get(),
- dex_path,
- out_oat_path,
- swap_fd.get(),
- instruction_set,
- compiler_filter,
- debuggable,
- boot_complete,
- background_job_compile,
- reference_profile_fd.get(),
- class_loader_context,
- target_sdk_version,
- enable_hidden_api_checks,
- generate_compact_dex,
- dex_metadata_fd.get(),
- compilation_reason);
-
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -1955,7 +1905,26 @@
_exit(DexoptReturnCodes::kFlock);
}
- runner.Exec(DexoptReturnCodes::kDex2oatExec);
+ run_dex2oat(input_fd.get(),
+ out_oat_fd.get(),
+ in_vdex_fd.get(),
+ out_vdex_fd.get(),
+ image_fd.get(),
+ dex_path,
+ out_oat_path,
+ swap_fd.get(),
+ instruction_set,
+ compiler_filter,
+ debuggable,
+ boot_complete,
+ background_job_compile,
+ reference_profile_fd.get(),
+ class_loader_context,
+ target_sdk_version,
+ enable_hidden_api_checks,
+ generate_compact_dex,
+ dex_metadata_fd.get(),
+ compilation_reason);
} else {
int res = wait_child(pid);
if (res == 0) {
@@ -2519,13 +2488,11 @@
return false;
}
- RunProfman args;
- args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
drop_capabilities(app_shared_gid);
- args.Exec();
+ run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
}
/* parent */
@@ -2605,8 +2572,6 @@
profiles_fd.push_back(std::move(fd));
}
}
- RunProfman args;
- args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -2614,7 +2579,7 @@
// The introduction of new access flags into boot jars causes them to
// fail dex file verification.
- args.Exec();
+ run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
}
/* parent */
@@ -2668,11 +2633,6 @@
return false;
}
- RunProfman args;
- args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
- std::move(ref_profile_fd),
- std::move(apk_fd),
- code_path);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -2680,7 +2640,10 @@
drop_capabilities(app_shared_gid);
// The copy and update takes ownership over the fds.
- args.Exec();
+ run_profman_copy_and_update(std::move(dex_metadata_fd),
+ std::move(ref_profile_fd),
+ std::move(apk_fd),
+ code_path);
}
/* parent */
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 68ddeb0..c169b76 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -160,7 +160,7 @@
message DisplayCreation {
required int32 id = 1;
required string name = 2;
- required int32 type = 3;
+ optional uint64 display_id = 3;
required bool is_secure = 4;
}
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
index a892e46..d63d97f 100644
--- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
+++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
@@ -172,7 +172,7 @@
def display_create(increment):
increment.display_creation.id = int(input("Enter id: "))
increment.display_creation.name = str(raw_input("Enter name: "))
- increment.display_creation.type = int(input("Enter type: "))
+ increment.display_creation.display_id = int(input("Enter display ID: "))
increment.display_creation.is_secure = bool(input("Enter if secure: "))
def display_delete(increment):
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 14edcbe..1674516 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -47,7 +47,7 @@
* (method calls, property get and set) is down through a low-level
* protocol implemented on top of the transact() API.
*/
-class IBinder : public virtual RefBase
+class [[clang::lto_visibility_public]] IBinder : public virtual RefBase
{
public:
enum {
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 5222bda..d711ad8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -287,6 +287,9 @@
* For debugging only!
*
* \param binder the binder object to retrieve the refcount of.
+ *
+ * \return the number of strong-refs on this binder in this process. If binder is null, this will be
+ * -1.
*/
int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29);
diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh
index 2257eb2..a0c49fb 100755
--- a/libs/binder/ndk/runtests.sh
+++ b/libs/binder/ndk/runtests.sh
@@ -22,12 +22,13 @@
set -ex
function run_libbinder_ndk_test() {
- adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
- local pid=$!
- trap "kill $pid" ERR
- adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client
- trap '' ERR
- kill $pid
+ adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
+
+ # avoid getService 1s delay for most runs, non-critical
+ sleep 0.1
+
+ adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \
+ adb shell killall libbinder_ndk_test_server
}
[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
@@ -40,4 +41,5 @@
# very simple unit tests, tests things outside of the NDK as well
run_libbinder_ndk_test
-atest android.binder.cts.NdkBinderTest
+# CTS tests (much more comprehensive, new tests should ideally go here)
+atest android.binder.cts
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8e40a01..b29b6e7 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -14,9 +14,6 @@
* limitations under the License.
*/
-// This test is a unit test of the low-level API that is presented here.
-// Actual users should use AIDL to generate these complicated stubs.
-
cc_defaults {
name: "test_libbinder_ndk_defaults",
shared_libs: [
@@ -55,6 +52,9 @@
],
}
+// This test is a unit test of the low-level API that is presented here,
+// specifically the parts which are outside of the NDK. Actual users should
+// also instead use AIDL to generate these stubs. See android.binder.cts.
cc_test {
name: "libbinder_ndk_test_client",
defaults: ["test_libbinder_ndk_test_defaults"],
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
index d46fde8..6ef964e 100644
--- a/libs/binder/ndk/test/iface.cpp
+++ b/libs/binder/ndk/test/iface.cpp
@@ -18,10 +18,13 @@
#include <android/binder_manager.h>
#include <iface/iface.h>
+#include <android/binder_auto_utils.h>
+
using ::android::sp;
using ::android::wp;
const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
+const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
const char* kIFooDescriptor = "my-special-IFoo-class";
struct IFoo_Class_Data {
@@ -49,12 +52,18 @@
switch (code) {
case IFoo::DOFOO: {
int32_t valueIn;
+ int32_t valueOut;
stat = AParcel_readInt32(in, &valueIn);
if (stat != STATUS_OK) break;
- int32_t valueOut = foo->doubleNumber(valueIn);
+ stat = foo->doubleNumber(valueIn, &valueOut);
+ if (stat != STATUS_OK) break;
stat = AParcel_writeInt32(out, valueOut);
break;
}
+ case IFoo::DIE: {
+ stat = foo->die();
+ break;
+ }
}
return stat;
@@ -68,22 +77,36 @@
BpFoo(AIBinder* binder) : mBinder(binder) {}
virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
- virtual int32_t doubleNumber(int32_t in) {
+ virtual binder_status_t doubleNumber(int32_t in, int32_t* out) {
+ binder_status_t stat = STATUS_OK;
+
AParcel* parcelIn;
- CHECK(STATUS_OK == AIBinder_prepareTransaction(mBinder, &parcelIn));
+ stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+ if (stat != STATUS_OK) return stat;
- CHECK(STATUS_OK == AParcel_writeInt32(parcelIn, in));
+ stat = AParcel_writeInt32(parcelIn, in);
+ if (stat != STATUS_OK) return stat;
- AParcel* parcelOut;
- CHECK(STATUS_OK ==
- AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/));
+ ::ndk::ScopedAParcel parcelOut;
+ stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+ if (stat != STATUS_OK) return stat;
- int32_t out;
- CHECK(STATUS_OK == AParcel_readInt32(parcelOut, &out));
+ stat = AParcel_readInt32(parcelOut.get(), out);
+ if (stat != STATUS_OK) return stat;
- AParcel_delete(parcelOut);
+ return stat;
+ }
- return out;
+ virtual binder_status_t die() {
+ binder_status_t stat = STATUS_OK;
+
+ AParcel* parcelIn;
+ stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+
+ ::ndk::ScopedAParcel parcelOut;
+ stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+
+ return stat;
}
private:
@@ -117,7 +140,7 @@
return status;
}
-sp<IFoo> IFoo::getService(const char* instance) {
+sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) {
AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
if (binder == nullptr) {
return nullptr;
@@ -128,6 +151,11 @@
return nullptr;
}
+ if (outBinder != nullptr) {
+ AIBinder_incStrong(binder);
+ *outBinder = binder;
+ }
+
if (AIBinder_isRemote(binder)) {
sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
return ret;
@@ -143,7 +171,6 @@
CHECK(held == binder);
AIBinder_decStrong(held);
- // IFoo only keeps a weak reference to AIBinder, so we can drop this
AIBinder_decStrong(binder);
return ret;
}
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h
index 25f5188..cdf5493 100644
--- a/libs/binder/ndk/test/include/iface/iface.h
+++ b/libs/binder/ndk/test/include/iface/iface.h
@@ -19,22 +19,33 @@
#include <android/binder_ibinder.h>
#include <utils/RefBase.h>
+// warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of
+// the other niceties make sure that, for instance, binder proxies are always the same. They also
+// don't use internal Android APIs like refbase which are used here only for convenience.
+
class IFoo : public virtual ::android::RefBase {
public:
static const char* kSomeInstanceName;
+ static const char* kInstanceNameToDieFor;
+
static AIBinder_Class* kClass;
// Takes ownership of IFoo
binder_status_t addService(const char* instance);
- static ::android::sp<IFoo> getService(const char* instance);
+ static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr);
enum Call {
DOFOO = FIRST_CALL_TRANSACTION + 0,
+ DIE = FIRST_CALL_TRANSACTION + 1,
};
virtual ~IFoo();
- virtual int32_t doubleNumber(int32_t in) = 0;
+
+ virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0;
+ virtual binder_status_t die() = 0;
private:
- AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder
+ // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not
+ // for BpFoo.
+ AIBinder_Weak* mWeakBinder = nullptr;
};
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 507daa2..c159d71 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -21,6 +21,10 @@
#include <gtest/gtest.h>
#include <iface/iface.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
using ::android::sp;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
@@ -34,7 +38,47 @@
TEST(NdkBinder, DoubleNumber) {
sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
ASSERT_NE(foo, nullptr);
- EXPECT_EQ(2, foo->doubleNumber(1));
+
+ int32_t out;
+ EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out));
+ EXPECT_EQ(2, out);
+}
+
+void LambdaOnDeath(void* cookie) {
+ auto onDeath = static_cast<std::function<void(void)>*>(cookie);
+ (*onDeath)();
+};
+TEST(NdkBinder, DeathRecipient) {
+ using namespace std::chrono_literals;
+
+ AIBinder* binder;
+ sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder);
+ ASSERT_NE(nullptr, foo.get());
+ ASSERT_NE(nullptr, binder);
+
+ std::mutex deathMutex;
+ std::condition_variable deathCv;
+ bool deathRecieved = false;
+
+ std::function<void(void)> onDeath = [&] {
+ std::cerr << "Binder died (as requested)." << std::endl;
+ deathRecieved = true;
+ deathCv.notify_one();
+ };
+
+ AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+
+ EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
+
+ // the binder driver should return this if the service dies during the transaction
+ EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+
+ std::unique_lock<std::mutex> lock(deathMutex);
+ EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
+ EXPECT_TRUE(deathRecieved);
+
+ AIBinder_DeathRecipient_delete(recipient);
+ AIBinder_decStrong(binder);
}
TEST(NdkBinder, RetrieveNonNdkService) {
@@ -52,9 +96,6 @@
}
TEST(NdkBinder, LinkToDeath) {
- ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications
- ABinderProcess_startThreadPool();
-
AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
ASSERT_NE(nullptr, binder);
@@ -72,9 +113,14 @@
}
class MyTestFoo : public IFoo {
- int32_t doubleNumber(int32_t in) override {
- LOG(INFO) << "doubleNumber " << in;
- return 2 * in;
+ binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+ *out = 2 * in;
+ LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+ return STATUS_OK;
+ }
+ binder_status_t die() override {
+ ADD_FAILURE() << "die called on local instance";
+ return STATUS_OK;
}
};
@@ -87,7 +133,9 @@
sp<IFoo> getFoo = IFoo::getService(kInstanceName);
EXPECT_EQ(foo.get(), getFoo.get());
- EXPECT_EQ(2, getFoo->doubleNumber(1));
+ int32_t out;
+ EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out));
+ EXPECT_EQ(2, out);
}
TEST(NdkBinder, EqualityOfRemoteBinderPointer) {
@@ -132,6 +180,15 @@
EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
}
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks
+ ABinderProcess_startThreadPool();
+
+ return RUN_ALL_TESTS();
+}
+
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
#include <android/binder_parcel_utils.h>
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
index 0718a69..a6e17e8 100644
--- a/libs/binder/ndk/test/main_server.cpp
+++ b/libs/binder/ndk/test/main_server.cpp
@@ -21,23 +21,37 @@
using ::android::sp;
class MyFoo : public IFoo {
- int32_t doubleNumber(int32_t in) override {
- LOG(INFO) << "doubling " << in;
- return 2 * in;
+ binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+ *out = 2 * in;
+ LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+ return STATUS_OK;
+ }
+
+ binder_status_t die() override {
+ LOG(FATAL) << "IFoo::die called!";
+ return STATUS_UNKNOWN_ERROR;
}
};
-int main() {
+int service(const char* instance) {
ABinderProcess_setThreadPoolMaxThreadCount(0);
// Strong reference to MyFoo kept by service manager.
- binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName);
+ binder_status_t status = (new MyFoo)->addService(instance);
if (status != STATUS_OK) {
- LOG(FATAL) << "Could not register: " << status;
+ LOG(FATAL) << "Could not register: " << status << " " << instance;
}
ABinderProcess_joinThreadPool();
- return 1;
+ return 1; // should not return
+}
+
+int main() {
+ if (fork() == 0) {
+ return service(IFoo::kInstanceNameToDieFor);
+ }
+
+ return service(IFoo::kSomeInstanceName);
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 97b4828..afa32b6 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -68,8 +68,7 @@
}
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
- const std::string appPref, bool developerOptIn,
- const int rulesFd, const long rulesOffset,
+ bool developerOptIn, const int rulesFd, const long rulesOffset,
const long rulesLength) {
if (!mAnglePath.empty()) {
ALOGV("ignoring attempt to change ANGLE path from '%s' to '%s'", mAnglePath.c_str(),
@@ -87,14 +86,6 @@
mAngleAppName = appName;
}
- if (!mAngleAppPref.empty()) {
- ALOGV("ignoring attempt to change ANGLE application opt-in from '%s' to '%s'",
- mAngleAppPref.c_str(), appPref.c_str());
- } else {
- ALOGV("setting ANGLE application opt-in to '%s'", appPref.c_str());
- mAngleAppPref = appPref;
- }
-
mAngleDeveloperOptIn = developerOptIn;
ALOGV("setting ANGLE rules file descriptor to '%i'", rulesFd);
@@ -128,11 +119,6 @@
return mAngleDeveloperOptIn;
}
-const char* GraphicsEnv::getAngleAppPref() {
- if (mAngleAppPref.empty()) return nullptr;
- return mAngleAppPref.c_str();
-}
-
int GraphicsEnv::getAngleRulesFd() {
return mAngleRulesFd;
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 528c260..20e4d66 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -44,9 +44,8 @@
// (libraries must be stored uncompressed and page aligned); such elements
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
- void setAngleInfo(const std::string path, const std::string appName, const std::string appPref,
- bool devOptIn, const int rulesFd, const long rulesOffset,
- const long rulesLength);
+ void setAngleInfo(const std::string path, const std::string appName, bool devOptIn,
+ const int rulesFd, const long rulesOffset, const long rulesLength);
android_namespace_t* getAngleNamespace();
const char* getAngleAppName();
const char* getAngleAppPref();
@@ -70,7 +69,6 @@
std::string mDriverPath;
std::string mAnglePath;
std::string mAngleAppName;
- std::string mAngleAppPref;
bool mAngleDeveloperOptIn;
int mAngleRulesFd;
long mAngleRulesOffset;
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index a247e60..606aee60 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "BufferHubBufferTest"
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
#include <gtest/gtest.h>
#include <hidl/ServiceManagement.h>
@@ -33,11 +34,11 @@
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
-} // namespace
-
using dvr::BufferHubDefs::IsBufferGained;
using dvr::BufferHubDefs::kFirstClientBitMask;
using dvr::BufferHubDefs::kMetadataHeaderSize;
+using frameworks::bufferhub::V1_0::BufferHubStatus;
+using frameworks::bufferhub::V1_0::IBufferClient;
using frameworks::bufferhub::V1_0::IBufferHub;
using hardware::hidl_handle;
using hidl::base::V1_0::IBase;
@@ -129,8 +130,14 @@
// TODO(b/116681016): Fill in real test once the interface gets implemented..
hidl_handle handle;
- sp<IBase> interface = bufferhub->importBuffer(handle);
- EXPECT_EQ(nullptr, interface.get());
+ EXPECT_TRUE(bufferhub
+ ->importBuffer(handle,
+ [](const auto& client, const auto& ret) {
+ EXPECT_EQ(client, nullptr);
+ EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+ })
+ .isOk());
}
+} // namespace
} // namespace android
diff --git a/libs/vr/CleanSpec.mk b/libs/vr/CleanSpec.mk
deleted file mode 100644
index a17c9b2..0000000
--- a/libs/vr/CleanSpec.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2012 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.
-#
-
-# If you don't need to do a full clean build but would like to touch
-# a file or delete some intermediate files, add a clean step to the end
-# of the list. These steps will only be run once, if they haven't been
-# run before.
-#
-# E.g.:
-# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
-#
-# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
-# files that are missing or have been moved.
-#
-# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
-# Use $(OUT_DIR) to refer to the "out" directory.
-#
-# If you need to re-do something that's already mentioned, just copy
-# the command and add it to the bottom of the list. E.g., if a change
-# that you made last week required touching a file and a change you
-# made today requires touching the same file, just copy the old
-# touch step and add it to the end of the list.
-#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-
-# For example:
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
-#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
-#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index e1c1aa9..f7942d0 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -69,7 +69,7 @@
.data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}};
ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
if (ret < 0) {
- ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
+ ALOGE("%s: Failed to add event fd to epoll set: %s", __FUNCTION__,
strerror(-ret));
}
}
@@ -77,7 +77,7 @@
Status<void> BufferHubQueue::ImportQueue() {
auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
if (!status) {
- ALOGE("BufferHubQueue::ImportQueue: Failed to import queue: %s",
+ ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return ErrorStatus(status.error());
} else {
@@ -136,9 +136,7 @@
consumer_queue->GetChannel()->TakeChannelParcelable());
if (!queue_parcelable.IsValid()) {
- ALOGE(
- "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create "
- "consumer queue parcelable.");
+ ALOGE("%s: Failed to create consumer queue parcelable.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
@@ -169,8 +167,7 @@
}
if (ret < 0 && ret != -EINTR) {
- ALOGE("BufferHubQueue::WaitForBuffers: Failed to wait for buffers: %s",
- strerror(-ret));
+ ALOGE("%s: Failed to wait for buffers: %s", __FUNCTION__, strerror(-ret));
return false;
}
@@ -264,14 +261,14 @@
// wait will be tried again to acquire the newly imported buffer.
auto buffer_status = OnBufferAllocated();
if (!buffer_status) {
- ALOGE("BufferHubQueue::HandleQueueEvent: Failed to import buffer: %s",
+ ALOGE("%s: Failed to import buffer: %s", __FUNCTION__,
buffer_status.GetErrorMessage().c_str());
}
} else if (events & EPOLLHUP) {
- ALOGD_IF(TRACE, "BufferHubQueue::HandleQueueEvent: hang up event!");
+ ALOGD_IF(TRACE, "%s: hang up event!", __FUNCTION__);
hung_up_ = true;
} else {
- ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%x", events);
+ ALOGW("%s: Unknown epoll events=%x", __FUNCTION__, events);
}
return {};
@@ -279,12 +276,11 @@
Status<void> BufferHubQueue::AddBuffer(
const std::shared_ptr<BufferHubBase>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu",
- buffer->id(), slot);
+ ALOGD_IF(TRACE, "%s: buffer_id=%d slot=%zu", __FUNCTION__, buffer->id(),
+ slot);
if (is_full()) {
- ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu",
- capacity_);
+ ALOGE("%s: queue is at maximum capacity: %zu", __FUNCTION__, capacity_);
return ErrorStatus(E2BIG);
}
@@ -303,7 +299,7 @@
const int ret =
epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
if (ret < 0) {
- ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
+ ALOGE("%s: Failed to add buffer to epoll set: %s", __FUNCTION__,
strerror(-ret));
return ErrorStatus(-ret);
}
@@ -315,17 +311,15 @@
}
Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
+ ALOGD_IF(TRACE, "%s: slot=%zu", __FUNCTION__, slot);
if (buffers_[slot]) {
for (const auto& event_source : buffers_[slot]->GetEventSources()) {
const int ret =
epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
if (ret < 0) {
- ALOGE(
- "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
- "set: %s",
- strerror(-ret));
+ ALOGE("%s: Failed to remove buffer from epoll set: %s", __FUNCTION__,
+ strerror(-ret));
return ErrorStatus(-ret);
}
}
@@ -343,6 +337,15 @@
Status<void> BufferHubQueue::Enqueue(Entry entry) {
if (!is_full()) {
+ // Find and remove the enqueued buffer from unavailable_buffers_slot if
+ // exist.
+ auto enqueued_buffer_iter = std::find_if(
+ unavailable_buffers_slot_.begin(), unavailable_buffers_slot_.end(),
+ [&entry](size_t slot) -> bool { return slot == entry.slot; });
+ if (enqueued_buffer_iter != unavailable_buffers_slot_.end()) {
+ unavailable_buffers_slot_.erase(enqueued_buffer_iter);
+ }
+
available_buffers_.push(std::move(entry));
// Trigger OnBufferAvailable callback if registered.
@@ -351,17 +354,16 @@
return {};
} else {
- ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
+ ALOGE("%s: Buffer queue is full!", __FUNCTION__);
return ErrorStatus(E2BIG);
}
}
Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout,
size_t* slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
- timeout);
+ ALOGD_IF(TRACE, "%s: count=%zu, timeout=%d", __FUNCTION__, count(), timeout);
- PDX_TRACE_FORMAT("BufferHubQueue::Dequeue|count=%zu|", count());
+ PDX_TRACE_FORMAT("%s|count=%zu|", __FUNCTION__, count());
if (count() == 0) {
if (!WaitForBuffers(timeout))
@@ -376,6 +378,7 @@
*slot = entry.slot;
available_buffers_.pop();
+ unavailable_buffers_slot_.push_back(*slot);
return {std::move(buffer)};
}
@@ -564,7 +567,7 @@
auto status =
InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
if (!status) {
- ALOGE("ProducerQueue::RemoveBuffer: Failed to remove producer buffer: %s",
+ ALOGE("%s: Failed to remove producer buffer: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return status.error_status();
}
@@ -580,31 +583,81 @@
pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* release_fence) {
+ pdx::LocalHandle* release_fence, bool gain_posted_buffer) {
ATRACE_NAME("ProducerQueue::Dequeue");
if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
- ALOGE("ProducerQueue::Dequeue: Invalid parameter.");
+ ALOGE("%s: Invalid parameter.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
- auto status = BufferHubQueue::Dequeue(timeout, slot);
- if (!status)
- return status.error_status();
-
- auto buffer = std::static_pointer_cast<BufferProducer>(status.take());
- const int ret = buffer->GainAsync(out_meta, release_fence);
+ std::shared_ptr<BufferProducer> buffer;
+ Status<std::shared_ptr<BufferHubBase>> dequeue_status =
+ BufferHubQueue::Dequeue(timeout, slot);
+ if (dequeue_status.ok()) {
+ buffer = std::static_pointer_cast<BufferProducer>(dequeue_status.take());
+ } else {
+ if (gain_posted_buffer) {
+ Status<std::shared_ptr<BufferProducer>> dequeue_unacquired_status =
+ ProducerQueue::DequeueUnacquiredBuffer(slot);
+ if (!dequeue_unacquired_status.ok()) {
+ ALOGE("%s: DequeueUnacquiredBuffer returned error: %d", __FUNCTION__,
+ dequeue_unacquired_status.error());
+ return dequeue_unacquired_status.error_status();
+ }
+ buffer = dequeue_unacquired_status.take();
+ } else {
+ return dequeue_status.error_status();
+ }
+ }
+ const int ret =
+ buffer->GainAsync(out_meta, release_fence, gain_posted_buffer);
if (ret < 0 && ret != -EALREADY)
return ErrorStatus(-ret);
return {std::move(buffer)};
}
+Status<std::shared_ptr<BufferProducer>> ProducerQueue::DequeueUnacquiredBuffer(
+ size_t* slot) {
+ if (unavailable_buffers_slot_.size() < 1) {
+ ALOGE(
+ "%s: Failed to dequeue un-acquired buffer. All buffer(s) are in "
+ "acquired state if exist.",
+ __FUNCTION__);
+ return ErrorStatus(ENOMEM);
+ }
+
+ // Find the first buffer that is not in acquired state from
+ // unavailable_buffers_slot_.
+ for (auto iter = unavailable_buffers_slot_.begin();
+ iter != unavailable_buffers_slot_.end(); iter++) {
+ std::shared_ptr<BufferProducer> buffer = ProducerQueue::GetBuffer(*iter);
+ if (buffer == nullptr) {
+ ALOGE("%s failed. Buffer slot %d is null.", __FUNCTION__,
+ static_cast<int>(*slot));
+ return ErrorStatus(EIO);
+ }
+ if (!BufferHubDefs::IsBufferAcquired(buffer->buffer_state())) {
+ *slot = *iter;
+ unavailable_buffers_slot_.erase(iter);
+ unavailable_buffers_slot_.push_back(*slot);
+ ALOGD("%s: Producer queue dequeue unacquired buffer in slot %d",
+ __FUNCTION__, static_cast<int>(*slot));
+ return {std::move(buffer)};
+ }
+ }
+ ALOGE(
+ "%s: Failed to dequeue un-acquired buffer. No un-acquired buffer exist.",
+ __FUNCTION__);
+ return ErrorStatus(EBUSY);
+}
+
pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
if (capacity() != 0) {
ALOGE(
- "ProducerQueue::TakeAsParcelable: producer queue can only be taken out"
- " as a parcelable when empty. Current queue capacity: %zu",
- capacity());
+ "%s: producer queue can only be taken out as a parcelable when empty. "
+ "Current queue capacity: %zu",
+ __FUNCTION__, capacity());
return ErrorStatus(EINVAL);
}
@@ -628,17 +681,16 @@
: BufferHubQueue(std::move(handle)) {
auto status = ImportQueue();
if (!status) {
- ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
+ ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
Close(-status.error());
}
auto import_status = ImportBuffers();
if (import_status) {
- ALOGI("ConsumerQueue::ConsumerQueue: Imported %zu buffers.",
- import_status.get());
+ ALOGI("%s: Imported %zu buffers.", __FUNCTION__, import_status.get());
} else {
- ALOGE("ConsumerQueue::ConsumerQueue: Failed to import buffers: %s",
+ ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
import_status.GetErrorMessage().c_str());
}
}
@@ -647,14 +699,11 @@
auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
if (!status) {
if (status.error() == EBADR) {
- ALOGI(
- "ConsumerQueue::ImportBuffers: Queue is silent, no buffers "
- "imported.");
+ ALOGI("%s: Queue is silent, no buffers imported.", __FUNCTION__);
return {0};
} else {
- ALOGE(
- "ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
- status.GetErrorMessage().c_str());
+ ALOGE("%s: Failed to import consumer buffer: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
return status.error_status();
}
}
@@ -665,13 +714,13 @@
auto buffer_handle_slots = status.take();
for (auto& buffer_handle_slot : buffer_handle_slots) {
- ALOGD_IF(TRACE, "ConsumerQueue::ImportBuffers: buffer_handle=%d",
+ ALOGD_IF(TRACE, ": buffer_handle=%d", __FUNCTION__,
buffer_handle_slot.first.value());
std::unique_ptr<BufferConsumer> buffer_consumer =
BufferConsumer::Import(std::move(buffer_handle_slot.first));
if (!buffer_consumer) {
- ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
+ ALOGE("%s: Failed to import buffer: slot=%zu", __FUNCTION__,
buffer_handle_slot.second);
last_error = ErrorStatus(EPIPE);
continue;
@@ -680,7 +729,7 @@
auto add_status =
AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
if (!add_status) {
- ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s",
+ ALOGE("%s: Failed to add buffer: %s", __FUNCTION__,
add_status.GetErrorMessage().c_str());
last_error = add_status;
} else {
@@ -696,8 +745,8 @@
Status<void> ConsumerQueue::AddBuffer(
const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
- id(), buffer->id(), slot);
+ ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu", __FUNCTION__, id(),
+ buffer->id(), slot);
return BufferHubQueue::AddBuffer(buffer, slot);
}
@@ -706,9 +755,9 @@
LocalHandle* acquire_fence) {
if (user_metadata_size != user_metadata_size_) {
ALOGE(
- "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
- "does not match metadata size (%zu) for the queue.",
- user_metadata_size, user_metadata_size_);
+ "%s: Metadata size (%zu) for the dequeuing buffer does not match "
+ "metadata size (%zu) for the queue.",
+ __FUNCTION__, user_metadata_size, user_metadata_size_);
return ErrorStatus(EINVAL);
}
@@ -723,7 +772,7 @@
if (metadata_src) {
memcpy(meta, metadata_src, user_metadata_size);
} else {
- ALOGW("ConsumerQueue::Dequeue: no user-defined metadata.");
+ ALOGW("%s: no user-defined metadata.", __FUNCTION__);
}
}
@@ -735,7 +784,7 @@
pdx::LocalHandle* acquire_fence) {
ATRACE_NAME("ConsumerQueue::Dequeue");
if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
- ALOGE("ConsumerQueue::Dequeue: Invalid parameter.");
+ ALOGE("%s: Invalid parameter.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
@@ -752,19 +801,18 @@
}
Status<void> ConsumerQueue::OnBufferAllocated() {
- ALOGD_IF(TRACE, "ConsumerQueue::OnBufferAllocated: queue_id=%d", id());
+ ALOGD_IF(TRACE, "%s: queue_id=%d", __FUNCTION__, id());
auto status = ImportBuffers();
if (!status) {
- ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
+ ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return ErrorStatus(status.error());
} else if (status.get() == 0) {
- ALOGW("ConsumerQueue::OnBufferAllocated: No new buffers allocated!");
+ ALOGW("%s: No new buffers allocated!", __FUNCTION__);
return ErrorStatus(ENOBUFS);
} else {
- ALOGD_IF(TRACE,
- "ConsumerQueue::OnBufferAllocated: Imported %zu consumer buffers.",
+ ALOGD_IF(TRACE, "%s: Imported %zu consumer buffers.", __FUNCTION__,
status.get());
return {};
}
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index c69002d..def7c6b 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -57,10 +57,10 @@
uint32_t default_width() const { return default_width_; }
// Returns the default buffer height of this buffer queue.
- uint32_t default_height() const { return static_cast<uint32_t>(default_height_); }
+ uint32_t default_height() const { return default_height_; }
// Returns the default buffer format of this buffer queue.
- uint32_t default_format() const { return static_cast<uint32_t>(default_format_); }
+ uint32_t default_format() const { return default_format_; }
// Creates a new consumer in handle form for immediate transport over RPC.
pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
@@ -208,6 +208,14 @@
// Size of the metadata that buffers in this queue cary.
size_t user_metadata_size_{0};
+ // Buffers and related data that are available for dequeue.
+ std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
+ available_buffers_;
+
+ // Slot of the buffers that are not available for normal dequeue. For example,
+ // the slot of posted or acquired buffers in the perspective of a producer.
+ std::vector<size_t> unavailable_buffers_slot_;
+
private:
void Initialize();
@@ -252,10 +260,6 @@
// queue regardless of its queue position or presence in the ring buffer.
std::array<std::shared_ptr<BufferHubBase>, kMaxQueueCapacity> buffers_;
- // Buffers and related data that are available for dequeue.
- std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
- available_buffers_;
-
// Keeps track with how many buffers have been added into the queue.
size_t capacity_{0};
@@ -349,11 +353,30 @@
// Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
// and caller should call Post() once it's done writing to release the buffer
// to the consumer side.
+ // @return a buffer in gained state, which was originally in released state.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
int timeout, size_t* slot, pdx::LocalHandle* release_fence);
+
+ // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
+ // and caller should call Post() once it's done writing to release the buffer
+ // to the consumer side.
+ //
+ // @param timeout to dequeue a buffer.
+ // @param slot is the slot of the output BufferProducer.
+ // @param release_fence for gaining a buffer.
+ // @param out_meta metadata of the output buffer.
+ // @param gain_posted_buffer whether to gain posted buffer if no released
+ // buffer is available to gain.
+ // @return a buffer in gained state, which was originally in released state if
+ // gain_posted_buffer is false, or in posted/released state if
+ // gain_posted_buffer is true.
+ // TODO(b/112007999): gain_posted_buffer true is only used to prevent
+ // libdvrtracking from starving when there are non-responding clients. This
+ // gain_posted_buffer param can be removed once libdvrtracking start to use
+ // the new AHardwareBuffer API.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* release_fence);
+ pdx::LocalHandle* release_fence, bool gain_posted_buffer = false);
// Enqueues a producer buffer in the queue.
pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer,
@@ -374,6 +397,16 @@
// arguments as the constructors.
explicit ProducerQueue(pdx::LocalChannelHandle handle);
ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
+
+ // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
+ // and caller should call Post() once it's done writing to release the buffer
+ // to the consumer side.
+ //
+ // @param slot the slot of the returned buffer.
+ // @return a buffer in gained state, which was originally in posted state or
+ // released state.
+ pdx::Status<std::shared_ptr<BufferProducer>> DequeueUnacquiredBuffer(
+ size_t* slot);
};
class ConsumerQueue : public BufferHubQueue {
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 046df54..c58f55f 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -1,5 +1,6 @@
#include <base/logging.h>
#include <binder/Parcel.h>
+#include <dvr/dvr_api.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
@@ -122,6 +123,147 @@
}
}
+TEST_F(BufferHubQueueTest,
+ TestDequeuePostedBufferIfNoAvailableReleasedBuffer_withBufferConsumer) {
+ ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+ // Allocate 3 buffers to use.
+ const size_t test_queue_capacity = 3;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ AllocateBuffer();
+ }
+ EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
+
+ size_t producer_slot, consumer_slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer posts 2 buffers and remember their posted sequence.
+ std::deque<size_t> posted_slots;
+ for (int64_t i = 0; i < 2; i++) {
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // Producer should not be gaining posted buffer when there are still
+ // available buffers to gain.
+ auto found_iter =
+ std::find(posted_slots.begin(), posted_slots.end(), producer_slot);
+ EXPECT_EQ(found_iter, posted_slots.end());
+ posted_slots.push_back(producer_slot);
+
+ // Producer posts the buffer.
+ mi.index = i;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+ }
+
+ // Consumer acquires one buffer.
+ auto c1_status =
+ consumer_queue_->Dequeue(kTimeoutMs, &consumer_slot, &mo, &fence);
+ EXPECT_TRUE(c1_status.ok());
+ auto c1 = c1_status.take();
+ ASSERT_NE(c1, nullptr);
+ // Consumer should get the oldest posted buffer. No checks here.
+ // posted_slots[0] should be in acquired state now.
+ EXPECT_EQ(mo.index, 0);
+ // Consumer releases the buffer.
+ EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
+ // posted_slots[0] should be in released state now.
+
+ // Producer gain and post 2 buffers.
+ for (int64_t i = 0; i < 2; i++) {
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the one in released state or the one haven't
+ // been use.
+ EXPECT_NE(posted_slots[1], producer_slot);
+
+ mi.index = i + 2;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+ }
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the oldest posted buffer.
+ EXPECT_EQ(posted_slots[1], producer_slot);
+
+ // Producer posts the buffer.
+ mi.index = 4;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+}
+
+TEST_F(BufferHubQueueTest,
+ TestDequeuePostedBufferIfNoAvailableReleasedBuffer_noBufferConsumer) {
+ ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+ // Allocate 4 buffers to use.
+ const size_t test_queue_capacity = 4;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ AllocateBuffer();
+ }
+ EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
+
+ // Post all allowed buffers and remember their posted sequence.
+ std::deque<size_t> posted_slots;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ size_t slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // Producer should not be gaining posted buffer when there are still
+ // available buffers to gain.
+ auto found_iter = std::find(posted_slots.begin(), posted_slots.end(), slot);
+ EXPECT_EQ(found_iter, posted_slots.end());
+ posted_slots.push_back(slot);
+
+ // Producer posts the buffer.
+ mi.index = i;
+ EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+ }
+
+ // Gain posted buffers in sequence.
+ const int64_t nb_dequeue_all_times = 2;
+ for (int j = 0; j < nb_dequeue_all_times; ++j) {
+ for (int i = 0; i < test_queue_capacity; ++i) {
+ size_t slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the oldest posted buffer.
+ EXPECT_EQ(posted_slots[i], slot);
+
+ // Producer posts the buffer.
+ mi.index = i + test_queue_capacity * (j + 1);
+ EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+ }
+ }
+}
+
TEST_F(BufferHubQueueTest, TestProducerConsumer) {
const size_t kBufferCount = 16;
size_t slot;
@@ -245,8 +387,8 @@
for (size_t i = 0; i < kBufferCount; i++) {
Entry* entry = &buffers[i];
- auto producer_status = producer_queue_->Dequeue(
- kTimeoutMs, &entry->slot, &mo, &entry->fence);
+ auto producer_status =
+ producer_queue_->Dequeue(kTimeoutMs, &entry->slot, &mo, &entry->fence);
ASSERT_TRUE(producer_status.ok());
entry->buffer = producer_status.take();
ASSERT_NE(nullptr, entry->buffer);
diff --git a/libs/vr/libpdx/status_tests.cpp b/libs/vr/libpdx/status_tests.cpp
index d4e697c..772c529 100644
--- a/libs/vr/libpdx/status_tests.cpp
+++ b/libs/vr/libpdx/status_tests.cpp
@@ -2,6 +2,8 @@
#include <gtest/gtest.h>
+#include <memory>
+
using android::pdx::ErrorStatus;
using android::pdx::Status;
@@ -84,8 +86,8 @@
Status<std::unique_ptr<int>> status1;
Status<std::unique_ptr<int>> status2;
- status1 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{11}}};
- status2 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{12}}};
+ status1 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{11})};
+ status2 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{12})};
EXPECT_FALSE(status1.empty());
EXPECT_FALSE(status2.empty());
EXPECT_TRUE(status1.ok());
@@ -114,7 +116,7 @@
}
TEST(Status, Take) {
- Status<std::unique_ptr<int>> status{std::unique_ptr<int>{new int{123}}};
+ Status<std::unique_ptr<int>> status{std::make_unique<int>(int{123})};
EXPECT_FALSE(status.empty());
EXPECT_NE(nullptr, status.get());
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index a150db1..e27f233 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -42,18 +42,6 @@
android_namespace_t* android_get_exported_namespace(const char*);
// TODO(ianelliott@): Get this from an ANGLE header:
- typedef enum ANGLEPreference {
- ANGLE_NO_PREFERENCE = 0,
- ANGLE_PREFER_NATIVE = 1,
- ANGLE_PREFER_ANGLE = 2,
- } ANGLEPreference;
-
- // TODO(ianelliott@): Get this from an ANGLE header:
- typedef bool (*fpANGLEUseForApplication)(const char* appName, const char* deviceMfr,
- const char* deviceModel, ANGLEPreference developerOption,
- ANGLEPreference appPreference);
-
- // TODO(ianelliott@): Get this from an ANGLE header:
typedef bool (*fpANGLEGetUtilityAPI)(unsigned int* versionToUse);
// TODO(ianelliott@): Get this from an ANGLE header:
@@ -522,16 +510,56 @@
return nullptr;
}
-static ANGLEPreference getAnglePref(const char* app_pref) {
- if (app_pref == nullptr)
- return ANGLE_NO_PREFERENCE;
- if (strcmp(app_pref, "angle") == 0) {
- return ANGLE_PREFER_ANGLE;
- } else if (strcmp(app_pref, "native") == 0) {
- return ANGLE_PREFER_NATIVE;
+static bool check_angle_rules(void* so, const char* app_name) {
+ bool use_angle = false;
+ const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
+ const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
+ const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
+
+ std::string app_name_str = app_name ? app_name : "";
+ char manufacturer[PROPERTY_VALUE_MAX];
+ char model[PROPERTY_VALUE_MAX];
+ property_get("ro.product.manufacturer", manufacturer, "UNSET");
+ property_get("ro.product.model", model, "UNSET");
+
+ fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
+ (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
+
+ if (ANGLEGetUtilityAPI) {
+
+ // Negotiate the interface version by requesting most recent known to the platform
+ unsigned int versionToUse = 1;
+ if ((ANGLEGetUtilityAPI)(&versionToUse)) {
+
+ // Add and remove versions below as needed
+ switch(versionToUse) {
+ case 1: {
+ ALOGV("Using version 1 of ANGLE opt-in/out logic interface");
+ fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
+ (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
+
+ if (AndroidUseANGLEForApplication) {
+ use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
+ rules_length, app_name_str.c_str(),
+ manufacturer, model);
+ } else {
+ ALOGW("Cannot find AndroidUseANGLEForApplication in ANGLE feature-support library");
+ }
+ }
+ break;
+ default:
+ ALOGW("Cannot find supported version of ANGLE feature-support library, found version %u", versionToUse);
+ }
+ } else {
+ ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, requested version %u", versionToUse);
+ }
+ } else {
+ ALOGW("Cannot find ANGLEGetUtilityAPI function");
}
- return ANGLE_NO_PREFERENCE;
+
+ ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
+ return use_angle;
}
static void* load_angle(const char* kind, android_namespace_t* ns, egl_connection_t* cnx) {
@@ -543,15 +571,10 @@
char prop[PROPERTY_VALUE_MAX];
const char* app_name = android::GraphicsEnv::getInstance().getAngleAppName();
- const char* app_pref = android::GraphicsEnv::getInstance().getAngleAppPref();
bool developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
- const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
- const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
- const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
// Determine whether or not to use ANGLE:
- ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
- bool use_angle = (developer_option == ANGLE_PREFER_ANGLE);
+ bool use_angle = developer_opt_in;
if (use_angle) {
ALOGV("User set \"Developer Options\" to force the use of ANGLE");
@@ -560,59 +583,17 @@
} else {
// The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily
// load ANGLE and call the updatable opt-in/out logic:
- std::string app_name_str = app_name ? app_name : "";
- char manufacturer[PROPERTY_VALUE_MAX];
- char model[PROPERTY_VALUE_MAX];
- property_get("ro.product.manufacturer", manufacturer, "UNSET");
- property_get("ro.product.model", model, "UNSET");
- cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+ // Check if ANGLE is enabled. Workaround for several bugs:
+ // b/119305693 b/119322355 b/119305887
+ // Something is not working correctly in the feature library
+ property_get("debug.angle.enable", prop, "0");
+ if (atoi(prop)) {
+ cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+ }
if (cnx->featureSo) {
ALOGV("loaded ANGLE's opt-in/out logic from namespace");
- bool use_version0_API = false;
- bool use_version1_API = false;
- fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
- (fpANGLEGetUtilityAPI)dlsym(cnx->featureSo, "ANGLEGetUtilityAPI");
- if (ANGLEGetUtilityAPI) {
- unsigned int versionToUse = 1;
- if ((ANGLEGetUtilityAPI)(&versionToUse)) {
- if (versionToUse == 1) {
- use_version1_API = true;
- } else {
- use_version0_API = true;
- }
- }
- } else {
- use_version0_API = true;
- ALOGV("Cannot find ANGLEGetUtilityAPI in library");
- }
- if (use_version1_API) {
- // Use the new version 1 API to determine if the
- // application should use the ANGLE or the native driver.
- fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
- (fpAndroidUseANGLEForApplication)dlsym(cnx->featureSo, "AndroidUseANGLEForApplication");
- if (AndroidUseANGLEForApplication) {
- use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
- rules_length, app_name_str.c_str(),
- manufacturer, model);
- } else {
- ALOGW("Cannot find AndroidUseANGLEForApplication in library");
- }
- } else if (use_version0_API) {
- // Use the old version 0 API to determine if the
- // application should use the ANGLE or the native driver.
- fpANGLEUseForApplication ANGLEUseForApplication =
- (fpANGLEUseForApplication)dlsym(cnx->featureSo, "ANGLEUseForApplication");
- if (ANGLEUseForApplication) {
- ANGLEPreference app_preference =
- getAnglePref(android::GraphicsEnv::getInstance().getAngleAppPref());
- use_angle = (ANGLEUseForApplication)(app_name_str.c_str(), manufacturer, model,
- developer_option, app_preference);
- ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
- } else {
- ALOGW("Cannot find ANGLEUseForApplication in library");
- }
- }
+ use_angle = check_angle_rules(cnx->featureSo, app_name);
} else {
// We weren't able to load and call the updateable opt-in/out logic.
// If we can't load the library, there is no ANGLE available.
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index d03d833..ca65e02 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -22,6 +22,7 @@
"-Wextra",
],
srcs: [
+ "BufferClient.cpp",
"BufferHubService.cpp",
"BufferNode.cpp",
],
diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp
new file mode 100644
index 0000000..b3662b2
--- /dev/null
+++ b/services/bufferhub/BufferClient.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 <bufferhub/BufferClient.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::hidl_handle;
+using hardware::Void;
+
+Return<void> BufferClient::duplicate(duplicate_cb _hidl_cb) {
+ // TODO(b/118614157): implement token generation and registration
+ _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
\ No newline at end of file
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 8be85a5..86598e0 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -22,16 +22,21 @@
namespace V1_0 {
namespace implementation {
-using ::android::status_t;
-using ::android::hardware::Void;
+using hardware::Void;
Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& /*description*/,
- allocateBuffer_cb /*hidl_cb*/) {
+ const uint32_t /*userMetadataSize*/,
+ allocateBuffer_cb _hidl_cb) {
+ // TODO(b/118614333): implement buffer allocation
+ _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::NO_ERROR);
return Void();
}
-Return<sp<IBase>> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/) {
- return nullptr;
+Return<void> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/,
+ importBuffer_cb _hidl_cb) {
+ // TODO(b/118614157): implement buffer import
+ _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
}
} // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
new file mode 100644
index 0000000..14ea95c
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -0,0 +1,41 @@
+/*
+ * 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_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::Return;
+
+class BufferClient : public IBufferClient {
+public:
+ Return<void> duplicate(duplicate_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index b273e5b..5e0cff0 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -17,8 +17,8 @@
#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
-#include <android/hardware/graphics/common/1.2/types.h>
namespace android {
namespace frameworks {
@@ -26,17 +26,16 @@
namespace V1_0 {
namespace implementation {
-using ::android::sp;
using ::android::hardware::hidl_handle;
using ::android::hardware::Return;
using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
-using ::android::hidl::base::V1_0::IBase;
class BufferHubService : public IBufferHub {
public:
- Return<void> allocateBuffer(const HardwareBufferDescription& /*description*/,
- allocateBuffer_cb /*hidl_cb*/) override;
- Return<sp<IBase>> importBuffer(const hidl_handle& /*nativeHandle*/) override;
+ Return<void> allocateBuffer(const HardwareBufferDescription& description,
+ const uint32_t userMetadataSize,
+ allocateBuffer_cb _hidl_cb) override;
+ Return<void> importBuffer(const hidl_handle& nativeHandle, importBuffer_cb _hidl_cb) override;
};
} // namespace implementation
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
new file mode 100644
index 0000000..250bbee
--- /dev/null
+++ b/services/gpuservice/Android.bp
@@ -0,0 +1,74 @@
+filegroup {
+ name: "gpuservice_sources",
+ srcs: [
+ "GpuService.cpp",
+ ],
+}
+
+filegroup {
+ name: "gpuservice_binary_sources",
+ srcs: ["main_gpuservice.cpp"],
+}
+
+cc_defaults {
+ name: "gpuservice_defaults",
+ cflags: [
+ "-DLOG_TAG=\"GpuService\"",
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ cppflags: ["-std=c++1z"],
+ srcs: [
+ ":gpuservice_sources",
+ ],
+ include_dirs: [
+ "frameworks/native/vulkan/vkjson",
+ "frameworks/native/vulkan/include",
+ ],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ "libvulkan",
+ ],
+ static_libs: [
+ "libvkjson",
+ ],
+}
+
+cc_defaults {
+ name: "gpuservice_production_defaults",
+ defaults: ["gpuservice_defaults"],
+ cflags: [
+ "-fvisibility=hidden",
+ "-fwhole-program-vtables", // requires ThinLTO
+ ],
+ lto: {
+ thin: true,
+ },
+}
+
+cc_defaults {
+ name: "gpuservice_binary",
+ defaults: ["gpuservice_defaults"],
+ whole_static_libs: [
+ "libsigchain",
+ ],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ ldflags: ["-Wl,--export-dynamic"],
+}
+
+cc_binary {
+ name: "gpuservice",
+ defaults: ["gpuservice_binary"],
+ init_rc: ["gpuservice.rc"],
+ srcs: [":gpuservice_binary_sources"],
+}
diff --git a/services/surfaceflinger/GpuService.cpp b/services/gpuservice/GpuService.cpp
similarity index 83%
rename from services/surfaceflinger/GpuService.cpp
rename to services/gpuservice/GpuService.cpp
index 71052fb..e4ca6bc 100644
--- a/services/surfaceflinger/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -23,10 +23,7 @@
namespace android {
-// ----------------------------------------------------------------------------
-
-class BpGpuService : public BpInterface<IGpuService>
-{
+class BpGpuService : public BpInterface<IGpuService> {
public:
explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
};
@@ -34,19 +31,15 @@
IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService");
status_t BnGpuService::onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags)
-{
+ Parcel* reply, uint32_t flags) {
status_t status;
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
int err = data.readFileDescriptor();
- int argc = data.readInt32();
- Vector<String16> args;
- for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
- args.add(data.readString16());
- }
+ std::vector<String16> args;
+ data.readString16Vector(&args);
sp<IBinder> unusedCallback;
sp<IResultReceiver> resultReceiver;
if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK)
@@ -64,20 +57,17 @@
}
}
-// ----------------------------------------------------------------------------
-
namespace {
status_t cmd_help(int out);
status_t cmd_vkjson(int out, int err);
}
-const char* const GpuService::SERVICE_NAME = "gpu";
+const char* const GpuService::SERVICE_NAME = "gpuservice";
-GpuService::GpuService() {}
+GpuService::GpuService() = default;
status_t GpuService::shellCommand(int /*in*/, int out, int err,
- Vector<String16>& args)
-{
+ std::vector<String16>& args) {
ALOGV("GpuService::shellCommand");
for (size_t i = 0, n = args.size(); i < n; i++)
ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string());
@@ -93,8 +83,6 @@
return BAD_VALUE;
}
-// ----------------------------------------------------------------------------
-
namespace {
status_t cmd_help(int out) {
diff --git a/services/surfaceflinger/GpuService.h b/services/gpuservice/GpuService.h
similarity index 80%
rename from services/surfaceflinger/GpuService.h
rename to services/gpuservice/GpuService.h
index b8c28d2..e2b396e 100644
--- a/services/surfaceflinger/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GPUSERVICE_H
#define ANDROID_GPUSERVICE_H
+#include <vector>
+
#include <binder/IInterface.h>
#include <cutils/compiler.h>
@@ -34,22 +36,21 @@
class BnGpuService: public BnInterface<IGpuService> {
protected:
virtual status_t shellCommand(int in, int out, int err,
- Vector<String16>& args) = 0;
+ std::vector<String16>& args) = 0;
- virtual status_t onTransact(uint32_t code, const Parcel& data,
+ status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0) override;
};
-class GpuService : public BnGpuService
-{
+class GpuService : public BnGpuService {
public:
static const char* const SERVICE_NAME ANDROID_API;
GpuService() ANDROID_API;
protected:
- virtual status_t shellCommand(int in, int out, int err,
- Vector<String16>& args) override;
+ status_t shellCommand(int in, int out, int err,
+ std::vector<String16>& args) override;
};
} // namespace android
diff --git a/services/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc
new file mode 100644
index 0000000..d23cf46
--- /dev/null
+++ b/services/gpuservice/gpuservice.rc
@@ -0,0 +1,4 @@
+service gpuservice /system/bin/gpuservice
+ class core
+ user gpu_service
+ group graphics
diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp
new file mode 100644
index 0000000..64aafca
--- /dev/null
+++ b/services/gpuservice/main_gpuservice.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <sys/resource.h>
+#include "GpuService.h"
+
+using namespace android;
+
+int main(int /* argc */, char** /* argv */) {
+ signal(SIGPIPE, SIG_IGN);
+
+ // publish GpuService
+ sp<GpuService> gpuservice = new GpuService();
+ sp<IServiceManager> sm(defaultServiceManager());
+ sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
+
+ // limit the number of binder threads to 4.
+ ProcessState::self()->setThreadPoolMaxThreadCount(4);
+
+ // start the thread pool
+ sp<ProcessState> ps(ProcessState::self());
+ ps->startThreadPool();
+ ps->giveThreadPoolName();
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 0e75d7f..f168db9 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -19,10 +19,6 @@
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
],
- include_dirs: [
- "frameworks/native/vulkan/vkjson",
- "frameworks/native/vulkan/include",
- ],
shared_libs: [
"android.frameworks.vr.composer@1.0",
"android.hardware.configstore-utils",
@@ -59,13 +55,11 @@
"libtimestats_proto",
"libui",
"libutils",
- "libvulkan",
],
static_libs: [
"librenderengine",
"libserviceutils",
"libtrace_proto",
- "libvkjson",
"libvr_manager",
"libvrflinger",
],
@@ -132,7 +126,6 @@
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
"FrameTracker.cpp",
- "GpuService.cpp",
"Layer.cpp",
"LayerBE.cpp",
"LayerProtoHelper.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b35bd6c..c2f15dd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -229,15 +229,14 @@
getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
+void BufferLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t supportedPerFrameMetadata) {
// Apply this display's projection's viewport to the visible region
// before giving it to the HWC HAL.
- const ui::Transform& tr = display->getTransform();
- const auto& viewport = display->getViewport();
- Region visible = tr.transform(visibleRegion.intersect(viewport));
- const auto displayId = display->getId();
+ Region visible = transform.transform(visibleRegion.intersect(viewport));
+
if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+ ALOGE("[%s] failed to setPerFrameData: no HWC layer found for display %" PRIu64,
mName.string(), displayId);
return;
}
@@ -290,7 +289,7 @@
}
const HdrMetadata& metadata = getDrawingHdrMetadata();
- error = hwcLayer->setPerFrameMetadata(display->getSupportedPerFrameMetadata(), metadata);
+ error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata);
if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
to_string(error).c_str(), static_cast<int32_t>(error));
@@ -303,10 +302,10 @@
}
getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
- getBE().compositionInfo.hwc.supportedPerFrameMetadata = display->getSupportedPerFrameMetadata();
+ getBE().compositionInfo.hwc.supportedPerFrameMetadata = supportedPerFrameMetadata;
getBE().compositionInfo.hwc.colorTransform = getColorTransform();
- setHwcLayerBuffer(display);
+ setHwcLayerBuffer(displayId);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -318,10 +317,10 @@
return hasReadyFrame();
}
-bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+bool BufferLayer::onPostComposition(const std::optional<DisplayId>& displayId,
+ const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) {
-
// mFrameLatencyNeeded is true when a new frame was latched for the
// composition.
if (!mFrameLatencyNeeded) return false;
@@ -352,11 +351,10 @@
if (presentFence->isValid()) {
mTimeStats.setPresentFence(layerID, mCurrentFrameNumber, presentFence);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
- } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
+ } else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- const nsecs_t actualPresentTime =
- mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
mTimeStats.setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 187b34f..f352256 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -80,10 +80,12 @@
bool isHdrY410() const override;
- void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
bool onPreComposition(nsecs_t refreshStartTime) override;
- bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+ bool onPostComposition(const std::optional<DisplayId>& displayId,
+ const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) override;
@@ -145,7 +147,7 @@
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& display) = 0;
+ virtual void setHwcLayerBuffer(DisplayId displayId) = 0;
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index ef09fd7..78ab23a 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -325,8 +325,7 @@
return NO_ERROR;
}
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto displayId = display->getId();
+void BufferQueueLayer::setHwcLayerBuffer(DisplayId displayId) {
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
@@ -353,6 +352,11 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
+ // Report the timestamp to the Scheduler.
+ if (mFlinger->mUseScheduler) {
+ mFlinger->mScheduler->addNewFrameTimestamp(item.mTimestamp, item.mIsAutoTimestamp);
+ }
+
Mutex::Autolock lock(mQueueItemLock);
// Reset the frame number tracker when we receive the first buffer after
// a frame number reset
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 3b93191..ae0b705 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -94,8 +94,7 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
- // -----------------------------------------------------------------------
+ void setHwcLayerBuffer(DisplayId displayId) override;
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 2ada701..ea64ca7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -554,8 +554,7 @@
return NO_ERROR;
}
-void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto displayId = display->getId();
+void BufferStateLayer::setHwcLayerBuffer(DisplayId displayId) {
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 47a046d..315d5af 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -122,8 +122,8 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
- // -----------------------------------------------------------------------
+ void setHwcLayerBuffer(DisplayId displayId) override;
+
private:
void onFirstRef() override;
bool willPresentCurrentTransaction() const;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 263f872..ad716ef 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -57,13 +57,12 @@
return !isHiddenByPolicy() && getAlpha() > 0.0f;
}
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
- const ui::Transform& tr = display->getTransform();
- const auto& viewport = display->getViewport();
- Region visible = tr.transform(visibleRegion.intersect(viewport));
- const auto displayId = display->getId();
+void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
+ Region visible = transform.transform(visibleRegion.intersect(viewport));
+
if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+ ALOGE("[%s] failed to setPerFrameData: no HWC layer found for display %" PRIu64,
mName.string(), displayId);
return;
}
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 2c10357..d1b1697 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -33,7 +33,10 @@
bool useIdentityTransform);
bool isVisible() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
+
+ bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
protected:
FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 44e843e..ca49f6c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -32,6 +32,6 @@
return !isHiddenByPolicy();
}
-void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&) {}
+void ContainerLayer::setPerFrameData(DisplayId, const ui::Transform&, const Rect&, int32_t) {}
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 8eddc7f..413844b 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -33,9 +33,12 @@
bool useIdentityTransform) override;
bool isVisible() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
bool isCreatedFromMainThread() const override { return true; }
+
+ bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 91b18c9..7c5c1bc 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -212,15 +212,14 @@
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
- DisplayDevice::DisplayType type, int32_t id)
- : flinger(flinger), displayToken(displayToken), type(type), id(id) {}
+ const std::optional<DisplayId>& displayId)
+ : flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
: lastCompositionHadVisibleLayers(false),
mFlinger(args.flinger),
- mType(args.type),
- mId(args.id),
mDisplayToken(args.displayToken),
+ mId(args.displayId),
mNativeWindow(args.nativeWindow),
mDisplaySurface(args.displaySurface),
mSurface{std::move(args.renderSurface)},
@@ -228,6 +227,7 @@
mDisplayHeight(args.displayHeight),
mDisplayInstallOrientation(args.displayInstallOrientation),
mPageFlipCount(0),
+ mIsVirtual(args.isVirtual),
mIsSecure(args.isSecure),
mLayerStack(NO_LAYER_STACK),
mOrientation(),
@@ -240,7 +240,8 @@
mHasHdr10(false),
mHasHLG(false),
mHasDolbyVision(false),
- mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
+ mSupportedPerFrameMetadata(args.supportedPerFrameMetadata),
+ mIsPrimary(args.isPrimary) {
populateColorModes(args.hwcColorModes);
ALOGE_IF(!mNativeWindow, "No native window was set for display");
@@ -293,16 +294,12 @@
DisplayDevice::~DisplayDevice() = default;
void DisplayDevice::disconnect(HWComposer& hwc) {
- if (mId >= 0) {
- hwc.disconnectDisplay(mId);
- mId = -1;
+ if (mId) {
+ hwc.disconnectDisplay(*mId);
+ mId.reset();
}
}
-bool DisplayDevice::isValid() const {
- return mFlinger != nullptr;
-}
-
int DisplayDevice::getWidth() const {
return mDisplayWidth;
}
@@ -334,9 +331,11 @@
status_t DisplayDevice::prepareFrame(HWComposer& hwc,
std::vector<CompositionInfo>& compositionData) {
- status_t error = hwc.prepare(*this, compositionData);
- if (error != NO_ERROR) {
- return error;
+ if (mId) {
+ status_t error = hwc.prepare(*mId, compositionData);
+ if (error != NO_ERROR) {
+ return error;
+ }
}
DisplaySurface::CompositionType compositionType;
@@ -600,7 +599,7 @@
// need to take care of primary display rotation for mGlobalTransform
// for case if the panel is not installed aligned with device orientation
- if (mType == DisplayType::DISPLAY_PRIMARY) {
+ if (isPrimary()) {
DisplayDevice::orientationToTransfrom(
(orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1),
w, h, &R);
@@ -648,7 +647,7 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = mId >= 0 ? base::StringPrintf("%d, ", mId) : std::string();
+ const auto id = mId ? base::StringPrintf("%" PRIu64 ", ", *mId) : std::string();
return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
mDisplayName.c_str());
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 152d0ec..9ec7666 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <memory>
+#include <optional>
#include <string>
#include <unordered_map>
@@ -37,6 +38,7 @@
#include <utils/String8.h>
#include <utils/Timers.h>
+#include "DisplayHardware/DisplayIdentification.h"
#include "RenderArea.h"
struct ANativeWindow;
@@ -66,25 +68,15 @@
Region undefinedRegion;
bool lastCompositionHadVisibleLayers;
- enum DisplayType {
- DISPLAY_ID_INVALID = -1,
- DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY,
- DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL,
- DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL,
- NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
- };
-
enum {
NO_LAYER_STACK = 0xFFFFFFFF,
};
explicit DisplayDevice(DisplayDeviceCreationArgs&& args);
-
~DisplayDevice();
- // whether this is a valid object. An invalid DisplayDevice is returned
- // when an non existing id is requested
- bool isValid() const;
+ bool isVirtual() const { return mIsVirtual; }
+ bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
@@ -118,11 +110,9 @@
bool needsFiltering() const { return mNeedsFiltering; }
uint32_t getLayerStack() const { return mLayerStack; }
- int32_t getDisplayType() const { return mType; }
- bool isPrimary() const { return mType == DISPLAY_PRIMARY; }
- bool isVirtual() const { return mType == DISPLAY_VIRTUAL; }
- int32_t getId() const { return mId; }
- const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
+
+ const std::optional<DisplayId>& getId() const { return mId; }
+ const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
@@ -207,13 +197,10 @@
void dump(String8& result) const;
private:
- /*
- * Constants, set during initialization
- */
- sp<SurfaceFlinger> mFlinger;
- DisplayType mType;
- int32_t mId;
- wp<IBinder> mDisplayToken;
+ const sp<SurfaceFlinger> mFlinger;
+ const wp<IBinder> mDisplayToken;
+
+ std::optional<DisplayId> mId;
// ANativeWindow this display is rendering into
sp<ANativeWindow> mNativeWindow;
@@ -225,7 +212,9 @@
const int mDisplayInstallOrientation;
mutable uint32_t mPageFlipCount;
std::string mDisplayName;
- bool mIsSecure;
+
+ const bool mIsVirtual;
+ const bool mIsSecure;
/*
* Can only accessed from the main thread, these members
@@ -299,13 +288,16 @@
const ui::ColorMode mode, const ui::RenderIntent intent);
std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
+
+ // TODO(b/74619554): Remove special cases for primary display.
+ const bool mIsPrimary;
};
struct DisplayDeviceState {
- bool isVirtual() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
+ bool isVirtual() const { return !displayId.has_value(); }
int32_t sequenceId = sNextSequenceId++;
- DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_ID_INVALID;
+ std::optional<DisplayId> displayId;
sp<IGraphicBufferProducer> surface;
uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
Rect viewport;
@@ -324,13 +316,13 @@
// We use a constructor to ensure some of the values are set, without
// assuming a default value.
DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
- DisplayDevice::DisplayType type, int32_t id);
+ const std::optional<DisplayId>& displayId);
const sp<SurfaceFlinger> flinger;
const wp<IBinder> displayToken;
- const DisplayDevice::DisplayType type;
- const int32_t id;
+ const std::optional<DisplayId> displayId;
+ bool isVirtual{false};
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<DisplaySurface> displaySurface;
@@ -343,6 +335,7 @@
int32_t supportedPerFrameMetadata{0};
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
int initialPowerMode{HWC_POWER_MODE_NORMAL};
+ bool isPrimary{false};
};
class DisplayRenderArea : public RenderArea {
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index dcc4138..ec240f3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -33,6 +33,9 @@
constexpr size_t kEdidHeaderLength = 5;
+constexpr uint16_t kFallbackEdidManufacturerId = 0;
+constexpr uint16_t kVirtualEdidManufacturerId = 0xffffu;
+
std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) {
if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) {
return {};
@@ -165,7 +168,8 @@
return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt;
}
-std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData& data) {
+std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
+ uint8_t port, const DisplayIdentificationData& data) {
if (!isEdid(data)) {
ALOGE("Display identification data has unknown format.");
return {};
@@ -179,7 +183,16 @@
// Hash display name instead of using product code or serial number, since the latter have been
// observed to change on some displays with multiple inputs.
const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
- return getEdidDisplayId(port, edid->manufacturerId, hash);
+ return DisplayIdentificationInfo{getEdidDisplayId(port, edid->manufacturerId, hash),
+ std::string(edid->displayName)};
+}
+
+DisplayId getFallbackDisplayId(uint8_t port) {
+ return getEdidDisplayId(port, kFallbackEdidManufacturerId, 0);
+}
+
+DisplayId getVirtualDisplayId(uint32_t id) {
+ return getEdidDisplayId(0, kVirtualEdidManufacturerId, id);
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 379f2d3..1f2e789 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -19,6 +19,7 @@
#include <array>
#include <cstdint>
#include <optional>
+#include <string>
#include <string_view>
#include <vector>
@@ -27,6 +28,11 @@
using DisplayId = uint64_t;
using DisplayIdentificationData = std::vector<uint8_t>;
+struct DisplayIdentificationInfo {
+ DisplayId id;
+ std::string name;
+};
+
// NUL-terminated plug and play ID.
using PnpId = std::array<char, 4>;
@@ -40,6 +46,10 @@
std::optional<Edid> parseEdid(const DisplayIdentificationData&);
std::optional<PnpId> getPnpId(uint16_t manufacturerId);
-std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData&);
+std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
+ uint8_t port, const DisplayIdentificationData&);
+
+DisplayId getFallbackDisplayId(uint8_t port);
+DisplayId getVirtualDisplayId(uint32_t id);
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index e6d7834..f3f8d9d 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -52,26 +52,25 @@
*
*/
-FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
- const sp<IGraphicBufferConsumer>& consumer) :
- ConsumerBase(consumer),
- mDisplayType(disp),
- mCurrentBufferSlot(-1),
- mCurrentBuffer(),
- mCurrentFence(Fence::NO_FENCE),
- mHwc(hwc),
- mHasPendingRelease(false),
- mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mPreviousBuffer()
-{
- ALOGV("Creating for display %d", disp);
+FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId,
+ const sp<IGraphicBufferConsumer>& consumer)
+ : ConsumerBase(consumer),
+ mDisplayId(displayId),
+ mCurrentBufferSlot(-1),
+ mCurrentBuffer(),
+ mCurrentFence(Fence::NO_FENCE),
+ mHwc(hwc),
+ mHasPendingRelease(false),
+ mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mPreviousBuffer() {
+ ALOGV("Creating for display %" PRIu64, displayId);
mName = "FramebufferSurface";
mConsumer->setConsumerName(mName);
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
- const auto& activeConfig = mHwc.getActiveConfig(disp);
+ const auto& activeConfig = mHwc.getActiveConfig(displayId);
mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
activeConfig->getHeight());
mConsumer->setMaxAcquiredBufferCount(
@@ -142,8 +141,7 @@
mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
&outSlot, &outBuffer);
outDataspace = static_cast<Dataspace>(item.mDataSpace);
- status_t result =
- mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
+ status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
if (result != NO_ERROR) {
ALOGE("error posting framebuffer: %d", result);
return result;
@@ -161,7 +159,7 @@
void FramebufferSurface::onFrameCommitted() {
if (mHasPendingRelease) {
- sp<Fence> fence = mHwc.getPresentFence(mDisplayType);
+ sp<Fence> fence = mHwc.getPresentFence(mDisplayId);
if (fence->isValid()) {
status_t result = addReleaseFence(mPreviousBufferSlot,
mPreviousBuffer, fence);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 0fd8e9e..2431dfd 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
+#include "DisplayIdentification.h"
#include "DisplaySurface.h"
#include "HWComposerBufferCache.h"
@@ -38,7 +39,8 @@
class FramebufferSurface : public ConsumerBase,
public DisplaySurface {
public:
- FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
+ FramebufferSurface(HWComposer& hwc, DisplayId displayId,
+ const sp<IGraphicBufferConsumer>& consumer);
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
@@ -63,8 +65,7 @@
status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer,
sp<Fence>& outFence, ui::Dataspace& outDataspace);
- // mDisplayType must match one of the HWC display types
- int mDisplayType;
+ const DisplayId mDisplayId;
// mCurrentBufferIndex is the slot index of the current buffer or
// INVALID_BUFFER_SLOT to indicate that either there is no current buffer
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d827fd2..4c472b8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -58,15 +58,15 @@
ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
#define LOG_DISPLAY_ERROR(displayId, msg) \
- ALOGE("%s failed for display %d: %s", __FUNCTION__, displayId, msg)
+ ALOGE("%s failed for display %" PRIu64 ": %s", __FUNCTION__, displayId, msg)
-#define LOG_HWC_ERROR(what, error, displayId) \
- ALOGE("%s: %s failed for display %d: %s (%d)", __FUNCTION__, what, displayId, \
+#define LOG_HWC_ERROR(what, error, displayId) \
+ ALOGE("%s: %s failed for display %" PRIu64 ": %s (%d)", __FUNCTION__, what, displayId, \
to_string(error).c_str(), static_cast<int32_t>(error))
#define RETURN_IF_INVALID_DISPLAY(displayId, ...) \
do { \
- if (!isValidDisplay(displayId)) { \
+ if (mDisplayData.count(displayId) == 0) { \
LOG_DISPLAY_ERROR(displayId, "Invalid display"); \
return __VA_ARGS__; \
} \
@@ -92,7 +92,9 @@
HWComposer::HWComposer(std::unique_ptr<android::Hwc2::Composer> composer)
: mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}
-HWComposer::~HWComposer() = default;
+HWComposer::~HWComposer() {
+ mDisplayData.clear();
+}
void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
int32_t sequenceId) {
@@ -116,11 +118,6 @@
return mHwcDevice->getCapabilities().count(capability) > 0;
}
-bool HWComposer::isValidDisplay(int32_t displayId) const {
- return static_cast<size_t>(displayId) < mDisplayData.size() &&
- mDisplayData[displayId].hwcDisplay;
-}
-
void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
bool valid = true;
switch (from) {
@@ -146,52 +143,50 @@
}
}
-std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
- HWC2::Connection connection) {
- if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
- ALOGE("Invalid display type of %d", displayType);
- return {};
- }
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
+ HWC2::Connection connection) {
+ std::optional<DisplayIdentificationInfo> info;
- ALOGV("hotplug: %" PRIu64 ", %s %s", hwcDisplayId,
- displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
- to_string(connection).c_str());
- mHwcDevice->onHotplug(hwcDisplayId, connection);
-
- std::optional<DisplayId> displayId;
-
- if (connection == HWC2::Connection::Connected) {
- uint8_t port;
- DisplayIdentificationData data;
- if (getDisplayIdentificationData(hwcDisplayId, &port, &data)) {
- displayId = generateDisplayId(port, data);
- ALOGE_IF(!displayId, "Failed to generate stable ID for display %" PRIu64, hwcDisplayId);
+ if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
+ info = DisplayIdentificationInfo{*displayId, std::string()};
+ } else {
+ if (connection == HWC2::Connection::Disconnected) {
+ ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
+ return {};
}
+
+ info = onHotplugConnect(hwcDisplayId);
+ if (!info) return {};
}
+ ALOGV("%s: %s %s display %" PRIu64 " with HWC ID %" PRIu64, __FUNCTION__,
+ to_string(connection).c_str(),
+ hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external", info->id, hwcDisplayId);
+
+ mHwcDevice->onHotplug(hwcDisplayId, connection);
+
// Disconnect is handled through HWComposer::disconnectDisplay via
// SurfaceFlinger's onHotplugReceived callback handling
if (connection == HWC2::Connection::Connected) {
- mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
- mHwcDisplaySlots[hwcDisplayId] = displayType;
+ mDisplayData[info->id].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
+ mPhysicalDisplayIdMap[hwcDisplayId] = info->id;
}
- return displayId;
+ return info;
}
-bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplayId) {
- const auto it = mHwcDisplaySlots.find(hwcDisplayId);
- if (it == mHwcDisplaySlots.end()) {
- LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid display");
+bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) {
+ const auto displayId = toPhysicalDisplayId(hwcDisplayId);
+ if (!displayId) {
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
return false;
}
- const int32_t displayId = it->second;
- RETURN_IF_INVALID_DISPLAY(displayId, false);
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
- const auto& displayData = mDisplayData[displayId];
+ const auto& displayData = mDisplayData[*displayId];
if (displayData.isVirtual) {
- LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
+ LOG_DISPLAY_ERROR(*displayId, "Invalid operation on virtual display");
return false;
}
@@ -202,31 +197,26 @@
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
- if (timestamp == mLastHwVSync[displayId]) {
- ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
- timestamp);
+ if (timestamp == mLastHwVSync[*displayId]) {
+ ALOGW("Ignoring duplicate VSYNC event from HWC for display %" PRIu64 " (t=%" PRId64 ")",
+ *displayId, timestamp);
return false;
}
- mLastHwVSync[displayId] = timestamp;
+ mLastHwVSync[*displayId] = timestamp;
}
- if (outDisplayId) {
- *outDisplayId = displayId;
- }
-
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", displayId);
- ATRACE_INT(tag, ++mVSyncCounts[displayId] & 1);
+ const auto tag = "HW_VSYNC_" + std::to_string(*displayId);
+ ATRACE_INT(tag.c_str(), ++mVSyncCounts[*displayId] & 1);
return true;
}
-status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
- ui::PixelFormat* format, int32_t *outId) {
+std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
+ ui::PixelFormat* format) {
if (mRemainingHwcVirtualDisplays == 0) {
ALOGE("%s: No remaining virtual displays", __FUNCTION__);
- return NO_MEMORY;
+ return {};
}
if (SurfaceFlinger::maxVirtualDisplaySize != 0 &&
@@ -234,41 +224,33 @@
height > SurfaceFlinger::maxVirtualDisplaySize)) {
ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width,
height, SurfaceFlinger::maxVirtualDisplaySize);
- return INVALID_OPERATION;
+ return {};
}
-
HWC2::Display* display;
auto error = mHwcDevice->createVirtualDisplay(width, height, format,
&display);
if (error != HWC2::Error::None) {
ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
- return NO_MEMORY;
+ return {};
}
- size_t displaySlot = 0;
- if (!mFreeDisplaySlots.empty()) {
- displaySlot = *mFreeDisplaySlots.begin();
- mFreeDisplaySlots.erase(displaySlot);
- } else if (mDisplayData.size() < INT32_MAX) {
- // Don't bother allocating a slot larger than we can return
- displaySlot = mDisplayData.size();
- mDisplayData.resize(displaySlot + 1);
+ DisplayId displayId;
+ if (mFreeVirtualDisplayIds.empty()) {
+ displayId = getVirtualDisplayId(mNextVirtualDisplayId++);
} else {
- ALOGE("%s: Unable to allocate a display slot", __FUNCTION__);
- return NO_MEMORY;
+ displayId = *mFreeVirtualDisplayIds.begin();
+ mFreeVirtualDisplayIds.erase(displayId);
}
- auto& displayData = mDisplayData[displaySlot];
+ auto& displayData = mDisplayData[displayId];
displayData.hwcDisplay = display;
displayData.isVirtual = true;
--mRemainingHwcVirtualDisplays;
- *outId = static_cast<int32_t>(displaySlot);
-
- return NO_ERROR;
+ return displayId;
}
-HWC2::Layer* HWComposer::createLayer(int32_t displayId) {
+HWC2::Layer* HWComposer::createLayer(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
auto display = mDisplayData[displayId].hwcDisplay;
@@ -278,7 +260,7 @@
return layer;
}
-void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) {
+void HWComposer::destroyLayer(DisplayId displayId, HWC2::Layer* layer) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto display = mDisplayData[displayId].hwcDisplay;
@@ -286,7 +268,8 @@
RETURN_IF_HWC_ERROR(error, displayId);
}
-nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const {
+nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, 0);
// this returns the last refresh timestamp.
// if the last one is not available, we estimate it based on
// the refresh period and whatever closest timestamp we have.
@@ -296,17 +279,17 @@
return now - ((now - mLastHwVSync[displayId]) % vsyncPeriod);
}
-bool HWComposer::isConnected(int32_t displayId) const {
+bool HWComposer::isConnected(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, false);
- return mDisplayData[displayId].hwcDisplay->isConnected();
+ return mDisplayData.at(displayId).hwcDisplay->isConnected();
}
-std::vector<std::shared_ptr<const HWC2::Display::Config>>
- HWComposer::getConfigs(int32_t displayId) const {
+std::vector<std::shared_ptr<const HWC2::Display::Config>> HWComposer::getConfigs(
+ DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
- auto& displayData = mDisplayData[displayId];
- auto configs = mDisplayData[displayId].hwcDisplay->getConfigs();
+ const auto& displayData = mDisplayData.at(displayId);
+ auto configs = displayData.hwcDisplay->getConfigs();
if (displayData.configMap.empty()) {
for (size_t i = 0; i < configs.size(); ++i) {
displayData.configMap[i] = configs[i];
@@ -315,12 +298,12 @@
return configs;
}
-std::shared_ptr<const HWC2::Display::Config>
- HWComposer::getActiveConfig(int32_t displayId) const {
+std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
+ DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
std::shared_ptr<const HWC2::Display::Config> config;
- auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfig(&config);
if (error == HWC2::Error::BadConfig) {
LOG_DISPLAY_ERROR(displayId, "No active config");
return nullptr;
@@ -336,11 +319,11 @@
return config;
}
-int HWComposer::getActiveConfigIndex(int32_t displayId) const {
+int HWComposer::getActiveConfigIndex(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, -1);
int index;
- auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfigIndex(&index);
if (error == HWC2::Error::BadConfig) {
LOG_DISPLAY_ERROR(displayId, "No active config");
return -1;
@@ -356,17 +339,17 @@
return index;
}
-std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const {
+std::vector<ui::ColorMode> HWComposer::getColorModes(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
std::vector<ui::ColorMode> modes;
- auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getColorModes(&modes);
RETURN_IF_HWC_ERROR(error, displayId, {});
return modes;
}
-status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode,
- ui::RenderIntent renderIntent) {
+status_t HWComposer::setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+ ui::RenderIntent renderIntent) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -379,8 +362,7 @@
return NO_ERROR;
}
-
-void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
+void HWComposer::setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
@@ -401,37 +383,30 @@
displayData.vsyncEnabled = enabled;
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", displayId);
- ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
+ const auto tag = "HW_VSYNC_ON_" + std::to_string(displayId);
+ ATRACE_INT(tag.c_str(), enabled == HWC2::Vsync::Enable ? 1 : 0);
}
}
-status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
- ui::Dataspace dataspace) {
+status_t HWComposer::setClientTarget(DisplayId displayId, uint32_t slot,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
+ ui::Dataspace dataspace) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- ALOGV("setClientTarget for display %d", displayId);
+ ALOGV("setClientTarget for display %" PRIu64, displayId);
auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace);
RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
return NO_ERROR;
}
-status_t HWComposer::prepare(DisplayDevice& display,
- std::vector<CompositionInfo>& compositionData) {
+status_t HWComposer::prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) {
ATRACE_CALL();
- Mutex::Autolock _l(mDisplayLock);
- const auto displayId = display.getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
- ALOGV("Skipping HWComposer prepare for non-HWC display");
- return NO_ERROR;
- }
-
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ Mutex::Autolock _l(mDisplayLock);
+
auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
if (!hwcDisplay->isConnected()) {
@@ -501,7 +476,8 @@
changedTypes[&*hwcLayer]);
compositionInfo.compositionType = changedTypes[&*hwcLayer];
compositionInfo.layer->mLayer->setCompositionType(displayId,
- compositionInfo.compositionType, false);
+ compositionInfo.compositionType,
+ false);
}
switch (compositionInfo.compositionType) {
@@ -540,49 +516,48 @@
return NO_ERROR;
}
-bool HWComposer::hasDeviceComposition(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasDeviceComposition(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are never composed by
// the device
return false;
}
- RETURN_IF_INVALID_DISPLAY(displayId, false);
- return mDisplayData[displayId].hasDeviceComposition;
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
+ return mDisplayData.at(*displayId).hasDeviceComposition;
}
-bool HWComposer::hasFlipClientTargetRequest(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are never composed by
// the device
return false;
}
- RETURN_IF_INVALID_DISPLAY(displayId, false);
- return ((static_cast<uint32_t>(mDisplayData[displayId].displayRequests) &
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
+ return ((static_cast<uint32_t>(mDisplayData.at(*displayId).displayRequests) &
static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
}
-bool HWComposer::hasClientComposition(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasClientComposition(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are always composed by
// the client
return true;
}
- RETURN_IF_INVALID_DISPLAY(displayId, true);
- return mDisplayData[displayId].hasClientComposition;
+ RETURN_IF_INVALID_DISPLAY(*displayId, true);
+ return mDisplayData.at(*displayId).hasClientComposition;
}
-sp<Fence> HWComposer::getPresentFence(int32_t displayId) const {
+sp<Fence> HWComposer::getPresentFence(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
- return mDisplayData[displayId].lastPresentFence;
+ return mDisplayData.at(displayId).lastPresentFence;
}
-sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
- HWC2::Layer* layer) const {
+sp<Fence> HWComposer::getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
- auto displayFences = mDisplayData[displayId].releaseFences;
+ auto displayFences = mDisplayData.at(displayId).releaseFences;
if (displayFences.count(layer) == 0) {
ALOGV("getLayerReleaseFence: Release fence not found");
return Fence::NO_FENCE;
@@ -590,7 +565,7 @@
return displayFences[layer];
}
-status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) {
+status_t HWComposer::presentAndGetReleaseFences(DisplayId displayId) {
ATRACE_CALL();
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -618,8 +593,7 @@
return NO_ERROR;
}
-status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) {
- ALOGV("setPowerMode(%d, %d)", displayId, intMode);
+status_t HWComposer::setPowerMode(DisplayId displayId, int32_t intMode) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto& displayData = mDisplayData[displayId];
@@ -675,7 +649,7 @@
return NO_ERROR;
}
-status_t HWComposer::setActiveConfig(int32_t displayId, size_t configId) {
+status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -689,8 +663,7 @@
return NO_ERROR;
}
-status_t HWComposer::setColorTransform(int32_t displayId,
- const mat4& transform) {
+status_t HWComposer::setColorTransform(DisplayId displayId, const mat4& transform) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -702,26 +675,34 @@
return NO_ERROR;
}
-void HWComposer::disconnectDisplay(int32_t displayId) {
+void HWComposer::disconnectDisplay(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
// If this was a virtual display, add its slot back for reuse by future
// virtual displays
if (displayData.isVirtual) {
- mFreeDisplaySlots.insert(displayId);
+ mFreeVirtualDisplayIds.insert(displayId);
++mRemainingHwcVirtualDisplays;
}
const auto hwcDisplayId = displayData.hwcDisplay->getId();
- mHwcDisplaySlots.erase(hwcDisplayId);
- displayData = DisplayData();
+ mPhysicalDisplayIdMap.erase(hwcDisplayId);
+ mDisplayData.erase(displayId);
+ mVSyncCounts.erase(displayId);
+
+ // TODO(b/74619554): Select internal/external display from remaining displays.
+ if (hwcDisplayId == mInternalHwcDisplayId) {
+ mInternalHwcDisplayId.reset();
+ } else if (hwcDisplayId == mExternalHwcDisplayId) {
+ mExternalHwcDisplayId.reset();
+ }
mHwcDevice->destroyDisplay(hwcDisplayId);
}
-status_t HWComposer::setOutputBuffer(int32_t displayId,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
+status_t HWComposer::setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buffer) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto& displayData = mDisplayData[displayId];
@@ -735,13 +716,12 @@
return NO_ERROR;
}
-void HWComposer::clearReleaseFences(int32_t displayId) {
+void HWComposer::clearReleaseFences(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId);
mDisplayData[displayId].releaseFences.clear();
}
-status_t HWComposer::getHdrCapabilities(
- int32_t displayId, HdrCapabilities* outCapabilities) {
+status_t HWComposer::getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
@@ -750,22 +730,22 @@
return NO_ERROR;
}
-int32_t HWComposer::getSupportedPerFrameMetadata(int32_t displayId) const {
+int32_t HWComposer::getSupportedPerFrameMetadata(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, 0);
- return mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata();
+ return mDisplayData.at(displayId).hwcDisplay->getSupportedPerFrameMetadata();
}
-std::vector<ui::RenderIntent> HWComposer::getRenderIntents(int32_t displayId,
- ui::ColorMode colorMode) const {
+std::vector<ui::RenderIntent> HWComposer::getRenderIntents(DisplayId displayId,
+ ui::ColorMode colorMode) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
std::vector<ui::RenderIntent> renderIntents;
- auto error = mDisplayData[displayId].hwcDisplay->getRenderIntents(colorMode, &renderIntents);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getRenderIntents(colorMode, &renderIntents);
RETURN_IF_HWC_ERROR(error, displayId, {});
return renderIntents;
}
-mat4 HWComposer::getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace) {
+mat4 HWComposer::getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace) {
RETURN_IF_INVALID_DISPLAY(displayId, {});
mat4 matrix;
@@ -806,12 +786,67 @@
result.append(mHwcDevice->dump().c_str());
}
-std::optional<hwc2_display_t>
-HWComposer::getHwcDisplayId(int32_t displayId) const {
- if (!isValidDisplay(displayId)) {
+std::optional<DisplayId> HWComposer::toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const {
+ if (const auto it = mPhysicalDisplayIdMap.find(hwcDisplayId);
+ it != mPhysicalDisplayIdMap.end()) {
+ return it->second;
+ }
+ return {};
+}
+
+std::optional<hwc2_display_t> HWComposer::fromPhysicalDisplayId(DisplayId displayId) const {
+ if (const auto it = mDisplayData.find(displayId);
+ it != mDisplayData.end() && !it->second.isVirtual) {
+ return it->second.hwcDisplay->getId();
+ }
+ return {};
+}
+
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) {
+ if (isUsingVrComposer() && mInternalHwcDisplayId) {
+ ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId);
return {};
}
- return mDisplayData[displayId].hwcDisplay->getId();
+
+ uint8_t port;
+ DisplayIdentificationData data;
+ const bool hasMultiDisplaySupport = getDisplayIdentificationData(hwcDisplayId, &port, &data);
+
+ if (mPhysicalDisplayIdMap.empty()) {
+ mHasMultiDisplaySupport = hasMultiDisplaySupport;
+ ALOGI("Switching to %s multi-display mode",
+ hasMultiDisplaySupport ? "generalized" : "legacy");
+ } else if (mHasMultiDisplaySupport && !hasMultiDisplaySupport) {
+ ALOGE("Ignoring connection of display %" PRIu64 " without identification data",
+ hwcDisplayId);
+ return {};
+ }
+
+ std::optional<DisplayIdentificationInfo> info;
+
+ if (mHasMultiDisplaySupport) {
+ info = parseDisplayIdentificationData(port, data);
+ ALOGE_IF(!info, "Failed to parse identification data for display %" PRIu64, hwcDisplayId);
+ } else if (mInternalHwcDisplayId && mExternalHwcDisplayId) {
+ ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId);
+ return {};
+ } else {
+ ALOGW_IF(hasMultiDisplaySupport, "Ignoring identification data for display %" PRIu64,
+ hwcDisplayId);
+ port = mInternalHwcDisplayId ? HWC_DISPLAY_EXTERNAL : HWC_DISPLAY_PRIMARY;
+ }
+
+ if (!mInternalHwcDisplayId) {
+ mInternalHwcDisplayId = hwcDisplayId;
+ } else if (!mExternalHwcDisplayId) {
+ mExternalHwcDisplayId = hwcDisplayId;
+ }
+
+ if (info) return info;
+
+ return DisplayIdentificationInfo{getFallbackDisplayId(port),
+ hwcDisplayId == mInternalHwcDisplayId ? "Internal display"
+ : "External display"};
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 4777ca9..5074c2c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -34,7 +34,8 @@
#include <memory>
#include <optional>
-#include <set>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include "DisplayIdentification.h"
@@ -82,101 +83,94 @@
bool hasCapability(HWC2::Capability capability) const;
- // 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,
- ui::PixelFormat* format, int32_t* outId);
+ // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
+ std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
+ ui::PixelFormat* format);
// Attempts to create a new layer on this display
- HWC2::Layer* createLayer(int32_t displayId);
+ HWC2::Layer* createLayer(DisplayId displayId);
// Destroy a previously created layer
- void destroyLayer(int32_t displayId, HWC2::Layer* layer);
+ void destroyLayer(DisplayId displayId, HWC2::Layer* layer);
// Asks the HAL what it can do
- status_t prepare(DisplayDevice& display,
- std::vector<CompositionInfo>& compositionData);
+ status_t prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData);
- status_t setClientTarget(int32_t displayId, uint32_t slot,
- const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
+ status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
// Present layers to the display and read releaseFences.
- status_t presentAndGetReleaseFences(int32_t displayId);
+ status_t presentAndGetReleaseFences(DisplayId displayId);
// set power mode
- status_t setPowerMode(int32_t displayId, int mode);
+ status_t setPowerMode(DisplayId displayId, int mode);
// set active config
- status_t setActiveConfig(int32_t displayId, size_t configId);
+ status_t setActiveConfig(DisplayId displayId, size_t configId);
// Sets a color transform to be applied to the result of composition
- status_t setColorTransform(int32_t displayId, const mat4& transform);
+ status_t setColorTransform(DisplayId displayId, const mat4& transform);
// reset state when an external, non-virtual display is disconnected
- void disconnectDisplay(int32_t displayId);
+ void disconnectDisplay(DisplayId displayId);
// does this display have layers handled by HWC
- bool hasDeviceComposition(int32_t displayId) const;
+ bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const;
// does this display have pending request to flip client target
- bool hasFlipClientTargetRequest(int32_t displayId) const;
+ bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const;
// does this display have layers handled by GLES
- bool hasClientComposition(int32_t displayId) const;
+ bool hasClientComposition(const std::optional<DisplayId>& displayId) const;
// get the present fence received from the last call to present.
- sp<Fence> getPresentFence(int32_t displayId) const;
+ sp<Fence> getPresentFence(DisplayId displayId) const;
// Get last release fence for the given layer
- sp<Fence> getLayerReleaseFence(int32_t displayId,
- HWC2::Layer* layer) const;
+ sp<Fence> getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const;
// Set the output buffer and acquire fence for a virtual display.
// Returns INVALID_OPERATION if displayId is not a virtual display.
- status_t setOutputBuffer(int32_t displayId, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& buf);
+ status_t setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buffer);
// After SurfaceFlinger has retrieved the release fences for all the frames,
// it can call this to clear the shared pointers in the release fence map
- void clearReleaseFences(int32_t displayId);
+ void clearReleaseFences(DisplayId displayId);
// Fetches the HDR capabilities of the given display
- status_t getHdrCapabilities(int32_t displayId, HdrCapabilities* outCapabilities);
+ status_t getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities);
- int32_t getSupportedPerFrameMetadata(int32_t displayId) const;
+ int32_t getSupportedPerFrameMetadata(DisplayId displayId) const;
// Returns the available RenderIntent of the given display.
- std::vector<ui::RenderIntent> getRenderIntents(int32_t displayId, ui::ColorMode colorMode) const;
+ std::vector<ui::RenderIntent> getRenderIntents(DisplayId displayId,
+ ui::ColorMode colorMode) const;
- mat4 getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace);
+ mat4 getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace);
// Events handling ---------------------------------------------------------
- // Returns true if successful, false otherwise. The
- // DisplayDevice::DisplayType of the display is returned as an output param.
- bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplay);
- std::optional<DisplayId> onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
- HWC2::Connection connection);
+ // Returns stable display ID (and display name on connection of new or previously disconnected
+ // display), or std::nullopt if hotplug event was ignored.
+ std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId,
+ HWC2::Connection connection);
- void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
+ bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp);
+ void setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled);
- // Query display parameters. Pass in a display index (e.g.
- // HWC_DISPLAY_PRIMARY).
- nsecs_t getRefreshTimestamp(int32_t displayId) const;
- bool isConnected(int32_t displayId) const;
+ nsecs_t getRefreshTimestamp(DisplayId displayId) const;
+ bool isConnected(DisplayId displayId) const;
// Non-const because it can update configMap inside of mDisplayData
- std::vector<std::shared_ptr<const HWC2::Display::Config>>
- getConfigs(int32_t displayId) const;
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(DisplayId displayId) const;
- std::shared_ptr<const HWC2::Display::Config>
- getActiveConfig(int32_t displayId) const;
- int getActiveConfigIndex(int32_t displayId) const;
+ std::shared_ptr<const HWC2::Display::Config> getActiveConfig(DisplayId displayId) const;
+ int getActiveConfigIndex(DisplayId displayId) const;
- std::vector<ui::ColorMode> getColorModes(int32_t displayId) const;
+ std::vector<ui::ColorMode> getColorModes(DisplayId displayId) const;
- status_t setActiveColorMode(int32_t displayId, ui::ColorMode mode,
- ui::RenderIntent renderIntent);
+ status_t setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+ ui::RenderIntent renderIntent);
bool isUsingVrComposer() const;
@@ -185,12 +179,19 @@
android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
- std::optional<hwc2_display_t> getHwcDisplayId(int32_t displayId) const;
+ // TODO(b/74619554): Remove special cases for internal/external display.
+ std::optional<hwc2_display_t> getInternalHwcDisplayId() const { return mInternalHwcDisplayId; }
+ std::optional<hwc2_display_t> getExternalHwcDisplayId() const { return mExternalHwcDisplayId; }
+
+ std::optional<DisplayId> toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const;
+ std::optional<hwc2_display_t> fromPhysicalDisplayId(DisplayId displayId) const;
+
private:
// For unit tests
friend TestableSurfaceFlinger;
- bool isValidDisplay(int32_t displayId) const;
+ std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
+
static void validateChange(HWC2::Composition from, HWC2::Composition to);
struct cb_context;
@@ -215,21 +216,30 @@
HWC2::Error presentError;
};
- std::unique_ptr<HWC2::Device> mHwcDevice;
- std::vector<DisplayData> mDisplayData{HWC_NUM_PHYSICAL_DISPLAY_TYPES};
- std::set<size_t> mFreeDisplaySlots;
- std::unordered_map<hwc2_display_t, int32_t> mHwcDisplaySlots;
+ std::unordered_map<DisplayId, DisplayData> mDisplayData;
+
+ // This must be destroyed before mDisplayData, because destructor may call back into HWComposer
+ // and look up DisplayData.
+ std::unique_ptr<HWC2::Device> mHwcDevice;
+
+ std::unordered_map<hwc2_display_t, DisplayId> mPhysicalDisplayIdMap;
+ std::optional<hwc2_display_t> mInternalHwcDisplayId;
+ std::optional<hwc2_display_t> mExternalHwcDisplayId;
+ bool mHasMultiDisplaySupport = false;
+
// protect mDisplayData from races between prepare and dump
mutable Mutex mDisplayLock;
cb_context* mCBContext = nullptr;
- size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]{0, 0};
+ std::unordered_map<DisplayId, size_t> mVSyncCounts;
+
+ std::unordered_set<uint32_t> mFreeVirtualDisplayIds;
+ uint32_t mNextVirtualDisplayId = 0;
uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
// protected by mLock
mutable Mutex mLock;
- mutable std::unordered_map<int32_t, nsecs_t> mLastHwVSync{
- {{HWC_DISPLAY_PRIMARY, 0}, {HWC_DISPLAY_EXTERNAL, 0}}};
+ mutable std::unordered_map<DisplayId, nsecs_t> mLastHwVSync;
// thread-safe
mutable Mutex mVsyncLock;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index c111a27..27d3dc5 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -48,34 +48,34 @@
}
}
-VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
- const sp<IGraphicBufferProducer>& sink,
- const sp<IGraphicBufferProducer>& bqProducer,
- const sp<IGraphicBufferConsumer>& bqConsumer,
- const std::string& name)
-: ConsumerBase(bqConsumer),
- mHwc(hwc),
- mDisplayId(dispId),
- mDisplayName(name),
- mSource{},
- mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
- mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
- mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
- mProducerSlotSource(0),
- mProducerBuffers(),
- mQueueBufferOutput(),
- mSinkBufferWidth(0),
- mSinkBufferHeight(0),
- mCompositionType(COMPOSITION_UNKNOWN),
- mFbFence(Fence::NO_FENCE),
- mOutputFence(Fence::NO_FENCE),
- mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mDbgState(DBG_STATE_IDLE),
- mDbgLastCompositionType(COMPOSITION_UNKNOWN),
- mMustRecompose(false),
- mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv)
-{
+VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc,
+ const std::optional<DisplayId>& displayId,
+ const sp<IGraphicBufferProducer>& sink,
+ const sp<IGraphicBufferProducer>& bqProducer,
+ const sp<IGraphicBufferConsumer>& bqConsumer,
+ const std::string& name)
+ : ConsumerBase(bqConsumer),
+ mHwc(hwc),
+ mDisplayId(displayId),
+ mDisplayName(name),
+ mSource{},
+ mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
+ mProducerSlotSource(0),
+ mProducerBuffers(),
+ mQueueBufferOutput(),
+ mSinkBufferWidth(0),
+ mSinkBufferHeight(0),
+ mCompositionType(COMPOSITION_UNKNOWN),
+ mFbFence(Fence::NO_FENCE),
+ mOutputFence(Fence::NO_FENCE),
+ mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mDbgState(DBG_STATE_IDLE),
+ mDbgLastCompositionType(COMPOSITION_UNKNOWN),
+ mMustRecompose(false),
+ mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) {
mSource[SOURCE_SINK] = sink;
mSource[SOURCE_SCRATCH] = bqProducer;
@@ -116,8 +116,9 @@
}
status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
mMustRecompose = mustRecompose;
@@ -129,8 +130,9 @@
}
status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN,
"Unexpected prepareFrame() in %s state", dbgStateStr());
@@ -177,8 +179,9 @@
}
status_t VirtualDisplaySurface::advanceFrame() {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
if (mCompositionType == COMPOSITION_HWC) {
VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
@@ -211,7 +214,7 @@
// At this point we know the output buffer acquire fence,
// so update HWC state with it.
- mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer);
+ mHwc.setOutputBuffer(*mDisplayId, mOutputFence, outBuffer);
status_t result = NO_ERROR;
if (fbBuffer != nullptr) {
@@ -221,22 +224,23 @@
&hwcSlot, &hwcBuffer);
// TODO: Correctly propagate the dataspace from GL composition
- result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence,
- hwcBuffer, ui::Dataspace::UNKNOWN);
+ result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
+ ui::Dataspace::UNKNOWN);
}
return result;
}
void VirtualDisplaySurface::onFrameCommitted() {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return;
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
"Unexpected onFrameCommitted() in %s state", dbgStateStr());
mDbgState = DBG_STATE_IDLE;
- sp<Fence> retireFence = mHwc.getPresentFence(mDisplayId);
+ sp<Fence> retireFence = mHwc.getPresentFence(*mDisplayId);
if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
// release the scratch buffer back to the pool
Mutex::Autolock lock(mMutex);
@@ -291,8 +295,9 @@
status_t VirtualDisplaySurface::requestBuffer(int pslot,
sp<GraphicBuffer>* outBuf) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected requestBuffer pslot=%d in %s state",
@@ -313,7 +318,7 @@
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
- LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
+ LOG_FATAL_IF(!mDisplayId);
status_t result =
mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
@@ -359,7 +364,7 @@
PixelFormat format, uint64_t usage,
uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
- if (mDisplayId < 0) {
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge,
outTimestamps);
}
@@ -446,8 +451,9 @@
status_t VirtualDisplaySurface::queueBuffer(int pslot,
const QueueBufferInput& input, QueueBufferOutput* output) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected queueBuffer(pslot=%d) in %s state", pslot,
@@ -504,8 +510,9 @@
status_t VirtualDisplaySurface::cancelBuffer(int pslot,
const sp<Fence>& fence) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
@@ -616,6 +623,8 @@
}
status_t VirtualDisplaySurface::refreshOutputBuffer() {
+ LOG_FATAL_IF(!mDisplayId);
+
if (mOutputProducerSlot >= 0) {
mSource[SOURCE_SINK]->cancelBuffer(
mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
@@ -633,8 +642,8 @@
// until after GLES calls queueBuffer(). So here we just set the buffer
// (for use in HWC prepare) but not the fence; we'll call this again with
// the proper fence once we have it.
- result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE,
- mProducerBuffers[mOutputProducerSlot]);
+ result = mHwc.setOutputBuffer(*mDisplayId, Fence::NO_FENCE,
+ mProducerBuffers[mOutputProducerSlot]);
return result;
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 4bd4d0f..33678df 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+#include <optional>
#include <string>
+#include "DisplayIdentification.h"
#include "DisplaySurface.h"
#include "HWComposerBufferCache.h"
@@ -75,11 +77,10 @@
public BnGraphicBufferProducer,
private ConsumerBase {
public:
- VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
- const sp<IGraphicBufferProducer>& sink,
- const sp<IGraphicBufferProducer>& bqProducer,
- const sp<IGraphicBufferConsumer>& bqConsumer,
- const std::string& name);
+ VirtualDisplaySurface(HWComposer& hwc, const std::optional<DisplayId>& displayId,
+ const sp<IGraphicBufferProducer>& sink,
+ const sp<IGraphicBufferProducer>& bqProducer,
+ const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name);
//
// DisplaySurface interface
@@ -154,7 +155,7 @@
// Immutable after construction
//
HWComposer& mHwc;
- const int32_t mDisplayId;
+ const std::optional<DisplayId> mDisplayId;
const std::string mDisplayName;
sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
uint32_t mDefaultOutputFormat;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c1f0587..421c9d0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -196,9 +196,9 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::createHwcLayer(HWComposer* hwc, int32_t displayId) {
+bool Layer::createHwcLayer(HWComposer* hwc, DisplayId displayId) {
LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(displayId) != 0,
- "Already have a layer for display %d", displayId);
+ "Already have a layer for display %" PRIu64, displayId);
auto layer = std::shared_ptr<HWC2::Layer>(
hwc->createLayer(displayId),
[hwc, displayId](HWC2::Layer* layer) {
@@ -214,7 +214,7 @@
return true;
}
-bool Layer::destroyHwcLayer(int32_t displayId) {
+bool Layer::destroyHwcLayer(DisplayId displayId) {
if (getBE().mHwcLayers.count(displayId) == 0) {
return false;
}
@@ -461,12 +461,13 @@
void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
const auto displayId = display->getId();
- if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setGeometry: no HWC layer found (%d)",
- mName.string(), displayId);
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ if (!hasHwcLayer(*displayId)) {
+ ALOGE("[%s] failed to setGeometry: no HWC layer found for display %" PRIu64, mName.string(),
+ *displayId);
return;
}
- auto& hwcInfo = getBE().mHwcLayers[displayId];
+ auto& hwcInfo = getBE().mHwcLayers[*displayId];
// enable this layer
hwcInfo.forceClientComposition = false;
@@ -618,7 +619,7 @@
if (orientation & ui::Transform::ROT_INVALID) {
// we can only handle simple transformation
hwcInfo.forceClientComposition = true;
- getBE().mHwcLayers[displayId].compositionType = HWC2::Composition::Client;
+ getBE().mHwcLayers[*displayId].compositionType = HWC2::Composition::Client;
} else {
auto transform = static_cast<HWC2::Transform>(orientation);
hwcInfo.transform = transform;
@@ -632,18 +633,18 @@
}
}
-void Layer::forceClientComposition(int32_t displayId) {
+void Layer::forceClientComposition(DisplayId displayId) {
if (getBE().mHwcLayers.count(displayId) == 0) {
- ALOGE("forceClientComposition: no HWC layer found (%d)", displayId);
+ ALOGE("forceClientComposition: no HWC layer found (display %" PRIu64 ")", displayId);
return;
}
getBE().mHwcLayers[displayId].forceClientComposition = true;
}
-bool Layer::getForceClientComposition(int32_t displayId) {
+bool Layer::getForceClientComposition(DisplayId displayId) {
if (getBE().mHwcLayers.count(displayId) == 0) {
- ALOGE("getForceClientComposition: no HWC layer found (%d)", displayId);
+ ALOGE("getForceClientComposition: no HWC layer found (display %" PRIu64 ")", displayId);
return false;
}
@@ -652,7 +653,7 @@
void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
const auto displayId = display->getId();
- if (getBE().mHwcLayers.count(displayId) == 0 ||
+ if (getBE().mHwcLayers.count(*displayId) == 0 ||
getCompositionType(displayId) != HWC2::Composition::Cursor) {
return;
}
@@ -675,8 +676,8 @@
auto position = displayTransform.transform(frame);
auto error =
- (getBE().mHwcLayers[displayId].layer)->setCursorPosition(
- position.left, position.top);
+ getBE().mHwcLayers[*displayId].layer->setCursorPosition(position.left, position.top);
+
ALOGE_IF(error != HWC2::Error::None,
"[%s] Failed to set cursor position "
"to (%d, %d): %s (%d)",
@@ -708,7 +709,7 @@
clearWithOpenGL(renderArea, 0, 0, 0, 0);
}
-void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc) {
+void Layer::setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc) {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setCompositionType called without a valid HWC layer");
return;
@@ -731,16 +732,20 @@
}
}
-HWC2::Composition Layer::getCompositionType(int32_t displayId) const {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+HWC2::Composition Layer::getCompositionType(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// If we're querying the composition type for a display that does not
// have a HWC counterpart, then it will always be Client
return HWC2::Composition::Client;
}
- return getBE().mHwcLayers[displayId].compositionType;
+ if (getBE().mHwcLayers.count(*displayId) == 0) {
+ ALOGE("getCompositionType called with an invalid HWC layer");
+ return HWC2::Composition::Invalid;
+ }
+ return getBE().mHwcLayers.at(*displayId).compositionType;
}
-void Layer::setClearClientTarget(int32_t displayId, bool clear) {
+void Layer::setClearClientTarget(DisplayId displayId, bool clear) {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setClearClientTarget called without a valid HWC layer");
return;
@@ -748,7 +753,7 @@
getBE().mHwcLayers[displayId].clearClientTarget = clear;
}
-bool Layer::getClearClientTarget(int32_t displayId) const {
+bool Layer::getClearClientTarget(DisplayId displayId) const {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("getClearClientTarget called without a valid HWC layer");
return false;
@@ -1417,7 +1422,7 @@
result.append("-----------------------------\n");
}
-void Layer::miniDump(String8& result, int32_t displayId) const {
+void Layer::miniDump(String8& result, DisplayId displayId) const {
if (getBE().mHwcLayers.count(displayId) == 0) {
return;
}
@@ -1981,7 +1986,7 @@
}
}
-void Layer::writeToProto(LayerProto* layerInfo, int32_t displayId) {
+void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
if (!hasHwcLayer(displayId)) {
return;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index dc9ab3d..e829a03 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -38,6 +38,7 @@
#include <cstdint>
#include <list>
+#include <optional>
#include <vector>
#include "Client.h"
@@ -360,7 +361,7 @@
void writeToProto(LayerProto* layerInfo,
LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
- void writeToProto(LayerProto* layerInfo, int32_t displayId);
+ void writeToProto(LayerProto* layerInfo, DisplayId displayId);
virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -386,16 +387,17 @@
virtual bool isHdrY410() const { return false; }
void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
- void forceClientComposition(int32_t displayId);
- bool getForceClientComposition(int32_t displayId);
- virtual void setPerFrameData(const sp<const DisplayDevice>& display) = 0;
+ void forceClientComposition(DisplayId displayId);
+ bool getForceClientComposition(DisplayId displayId);
+ virtual void setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t supportedPerFrameMetadata) = 0;
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc = true);
- HWC2::Composition getCompositionType(int32_t displayId) const;
- void setClearClientTarget(int32_t displayId, bool clear);
- bool getClearClientTarget(int32_t displayId) const;
+ void setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc = true);
+ HWC2::Composition getCompositionType(const std::optional<DisplayId>& displayId) const;
+ void setClearClientTarget(DisplayId displayId, bool clear);
+ bool getClearClientTarget(DisplayId displayId) const;
void updateCursorPosition(const sp<const DisplayDevice>& display);
/*
@@ -410,13 +412,14 @@
* called before composition.
* returns true if the layer has pending updates.
*/
- virtual bool onPreComposition(nsecs_t /*refreshStartTime*/) { return true; }
+ virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- virtual bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+ virtual bool onPostComposition(const std::optional<DisplayId>& /*displayId*/,
+ const std::shared_ptr<FenceTime>& /*glDoneFence*/,
const std::shared_ptr<FenceTime>& /*presentFence*/,
const CompositorTiming& /*compositorTiming*/) {
return false;
@@ -501,24 +504,24 @@
// -----------------------------------------------------------------------
- bool createHwcLayer(HWComposer* hwc, int32_t displayId);
- bool destroyHwcLayer(int32_t displayId);
+ bool createHwcLayer(HWComposer* hwc, DisplayId displayId);
+ bool destroyHwcLayer(DisplayId displayId);
void destroyAllHwcLayers();
- bool hasHwcLayer(int32_t displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
+ bool hasHwcLayer(DisplayId displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
- HWC2::Layer* getHwcLayer(int32_t displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+ HWC2::Layer* getHwcLayer(DisplayId displayId) {
+ if (!hasHwcLayer(displayId)) {
return nullptr;
}
return getBE().mHwcLayers[displayId].layer.get();
}
- bool setHwcLayer(int32_t hwcId) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+ bool setHwcLayer(DisplayId displayId) {
+ if (!hasHwcLayer(displayId)) {
return false;
}
- getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[hwcId].layer;
+ getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[displayId].layer;
return true;
}
@@ -533,7 +536,7 @@
/* always call base class first */
static void miniDumpHeader(String8& result);
- void miniDump(String8& result, int32_t displayId) const;
+ void miniDump(String8& result, DisplayId displayId) const;
void dumpFrameStats(String8& result) const;
void dumpFrameEvents(String8& result);
void clearFrameStats();
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 463c46c..3f5134e 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -24,6 +24,7 @@
#include <renderengine/Texture.h>
#include <ui/Region.h>
+#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWComposerBufferCache.h"
#include "SurfaceFlinger.h"
@@ -41,7 +42,7 @@
std::shared_ptr<LayerBE> layer;
struct {
std::shared_ptr<HWC2::Layer> hwcLayer;
- int32_t displayId = -1;
+ DisplayId displayId;
sp<Fence> fence;
HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
Rect displayFrame;
@@ -123,12 +124,11 @@
HWC2::Transform transform;
};
-
// A layer can be attached to multiple displays when operating in mirror mode
// (a.k.a: when several displays are attached with equal layerStack). In this
// case we need to keep track. In non-mirror mode, a layer will have only one
- // HWCInfo. This map key is a display layerStack.
- std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+ // HWCInfo.
+ std::unordered_map<DisplayId, HWCInfo> mHwcLayers;
CompositionInfo compositionInfo;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 18a8bb1..4286cc9 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "Scheduler.h"
#include <cinttypes>
#include <cstdint>
#include <memory>
+#include <numeric>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
@@ -27,6 +30,7 @@
#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
+#include <utils/Trace.h>
#include "DispSync.h"
#include "DispSyncSource.h"
@@ -196,4 +200,58 @@
mPrimaryDispSync->setIgnorePresentFences(ignore);
}
+void Scheduler::makeHWSyncAvailable(bool makeAvailable) {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ mHWVsyncAvailable = makeAvailable;
+}
+
+void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp) {
+ ATRACE_INT("AutoTimestamp", isAutoTimestamp);
+ // Video does not have timestamp automatically set, so we discard timestamps that are
+ // coming in from other sources for now.
+ if (isAutoTimestamp) {
+ return;
+ }
+ int64_t differenceMs = (newFrameTimestamp - mPreviousFrameTimestamp) / 1000000;
+ mPreviousFrameTimestamp = newFrameTimestamp;
+
+ if (differenceMs < 10 || differenceMs > 100) {
+ // Dismiss noise.
+ return;
+ }
+ ATRACE_INT("TimestampDiff", differenceMs);
+
+ mTimeDifferences[mCounter % ARRAY_SIZE] = differenceMs;
+ mCounter++;
+ nsecs_t average = calculateAverage();
+ ATRACE_INT("TimestampAverage", average);
+
+ // TODO(b/113612090): This are current numbers from trial and error while running videos
+ // from YouTube at 24, 30, and 60 fps.
+ if (average > 14 && average < 18) {
+ ATRACE_INT("FPS", 60);
+ } else if (average > 31 && average < 34) {
+ ATRACE_INT("FPS", 30);
+ updateFrameSkipping(1);
+ return;
+ } else if (average > 39 && average < 42) {
+ ATRACE_INT("FPS", 24);
+ }
+ updateFrameSkipping(0);
+}
+
+nsecs_t Scheduler::calculateAverage() const {
+ nsecs_t sum = std::accumulate(mTimeDifferences.begin(), mTimeDifferences.end(), 0);
+ return (sum / ARRAY_SIZE);
+}
+
+void Scheduler::updateFrameSkipping(const int64_t skipCount) {
+ ATRACE_INT("FrameSkipCount", skipCount);
+ if (mSkipCount != skipCount) {
+ // Only update DispSync if it hasn't been updated yet.
+ mPrimaryDispSync->setRefreshSkipCount(skipCount);
+ mSkipCount = skipCount;
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fdafe58..dd1f24b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -102,6 +102,8 @@
void addResyncSample(const nsecs_t timestamp);
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
+ void makeHWSyncAvailable(bool makeAvailable);
+ void addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp);
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
@@ -110,6 +112,9 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ nsecs_t calculateAverage() const;
+ void updateFrameSkipping(const int64_t skipCount);
+
// TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
// should make request to Scheduler to compute next refresh.
friend class BufferQueueLayer;
@@ -133,6 +138,18 @@
std::unique_ptr<DispSync> mPrimaryDispSync;
std::unique_ptr<EventControlThread> mEventControlThread;
+
+ // TODO(b/113612090): The following set of variables needs to be revised. For now, this is
+ // a proof of concept. We turn on frame skipping if the difference between the timestamps
+ // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz.
+ nsecs_t mPreviousFrameTimestamp = 0;
+ // Keeping track of whether we are skipping the refresh count. If we want to
+ // simulate 30Hz rendering, we skip every other frame, and this variable is set
+ // to 1.
+ int64_t mSkipCount = 0;
+ static constexpr size_t ARRAY_SIZE = 30;
+ std::array<int64_t, ARRAY_SIZE> mTimeDifferences;
+ size_t mCounter = 0;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7871971..9af5fd8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -105,8 +105,6 @@
#include <layerproto/LayerProtoParser.h>
-#define DISPLAY_COUNT 1
-
namespace android {
using namespace android::hardware::configstore;
@@ -173,6 +171,11 @@
bool mLocked;
};
+// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
+bool validateCompositionDataspace(Dataspace dataspace) {
+ return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
+}
+
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -191,7 +194,6 @@
bool SurfaceFlinger::hasSyncFramework;
bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
-// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
bool SurfaceFlinger::hasWideColorDisplay;
int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
bool SurfaceFlinger::useColorManagement;
@@ -247,7 +249,6 @@
mLayersRemoved(false),
mLayersAdded(false),
mBootTime(systemTime()),
- mDisplayTokens(),
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
@@ -313,6 +314,8 @@
wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
});
}
+ mDefaultCompositionDataspace = defaultCompositionDataspace;
+ mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
useContextPriority = getBool<ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::useContextPriority>(true);
@@ -482,40 +485,49 @@
sp<BBinder> token = new DisplayToken(this);
Mutex::Autolock _l(mStateLock);
- DisplayDeviceState info;
- info.type = DisplayDevice::DISPLAY_VIRTUAL;
- info.displayName = displayName;
- info.isSecure = secure;
- mCurrentState.displays.add(token, info);
- mInterceptor->saveDisplayCreation(info);
+ // Display ID is assigned when virtual display is allocated by HWC.
+ DisplayDeviceState state;
+ state.isSecure = secure;
+ state.displayName = displayName;
+ mCurrentState.displays.add(token, state);
+ mInterceptor->saveDisplayCreation(state);
return token;
}
void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) {
Mutex::Autolock _l(mStateLock);
- ssize_t idx = mCurrentState.displays.indexOfKey(displayToken);
- if (idx < 0) {
+ ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
+ if (index < 0) {
ALOGE("destroyDisplay: Invalid display token %p", displayToken.get());
return;
}
- const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- if (!info.isVirtual()) {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ if (!state.isVirtual()) {
ALOGE("destroyDisplay called for non-virtual display");
return;
}
- mInterceptor->saveDisplayDeletion(info.sequenceId);
- mCurrentState.displays.removeItemsAt(idx);
+ mInterceptor->saveDisplayDeletion(state.sequenceId);
+ mCurrentState.displays.removeItemsAt(index);
setTransactionFlags(eDisplayTransactionNeeded);
}
sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
- if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
- ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
+ std::optional<DisplayId> displayId;
+
+ if (id == HWC_DISPLAY_PRIMARY) {
+ displayId = getInternalDisplayId();
+ } else if (id == HWC_DISPLAY_EXTERNAL) {
+ displayId = getExternalDisplayId();
+ }
+
+ if (!displayId) {
+ ALOGE("%s: Invalid display %d", __FUNCTION__, id);
return nullptr;
}
- return mDisplayTokens[id];
+
+ return getPhysicalDisplayToken(*displayId);
}
status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
@@ -598,8 +610,10 @@
// start the EventThread
if (mUseScheduler) {
- mScheduler = getFactory().createScheduler(
- [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
+ mScheduler = getFactory().createScheduler([this](bool enabled) {
+ setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
+ });
+
mAppConnectionHandle =
mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
[this] { resyncWithRateLimit(); },
@@ -659,7 +673,7 @@
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
- LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getId()),
+ LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
"Internal display is disconnected.");
// make the default display GLContext current so that we can create textures
@@ -682,7 +696,7 @@
};
mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
getHwComposer()
- .getHwcDisplayId(display->getId())
+ .fromPhysicalDisplayId(*display->getId())
.value_or(0),
vrFlingerRequestDisplayCallback);
if (!mVrFlinger) {
@@ -691,7 +705,7 @@
}
mEventControlThread = getFactory().createEventControlThread(
- [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
+ [this](bool enabled) { setVsyncEnabled(EventThread::DisplayType::Primary, enabled); });
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -717,8 +731,8 @@
// and apply this saturation matrix on Display P3 content. Unless the risk of applying
// such saturation matrix on Display P3 is understood fully, the API should always return
// identify matrix.
- mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(display->getId(),
- Dataspace::SRGB_LINEAR);
+ mEnhancedSaturationMatrix =
+ getHwComposer().getDataspaceSaturationMatrix(*display->getId(), Dataspace::SRGB_LINEAR);
// we will apply this on Display P3.
if (mEnhancedSaturationMatrix != mat4()) {
@@ -805,16 +819,9 @@
return BAD_VALUE;
}
- int32_t type = NAME_NOT_FOUND;
- for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
- if (displayToken == mDisplayTokens[i]) {
- type = i;
- break;
- }
- }
-
- if (type < 0) {
- return type;
+ const auto displayId = getPhysicalDisplayId(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
}
// TODO: Not sure if display density should handled by SF any longer
@@ -838,7 +845,7 @@
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
- for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
+ for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
DisplayInfo info = DisplayInfo();
float xdpi = hwConfig->getDpiX();
@@ -850,7 +857,7 @@
info.viewportW = info.w;
info.viewportH = info.h;
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (displayId == getInternalDisplayId()) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
if (density == 0) {
@@ -906,7 +913,7 @@
// All non-virtual displays are currently considered secure.
info.secure = true;
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
+ if (displayId == getInternalDisplayId() &&
primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
@@ -922,7 +929,6 @@
return BAD_VALUE;
}
- // FIXME for now we always return stats for the primary display.
if (mUseScheduler) {
mScheduler->getDisplayStatInfo(stats);
} else {
@@ -943,18 +949,21 @@
}
void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
int currentMode = display->getActiveConfig();
if (mode == currentMode) {
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set config for virtual display");
- return;
- }
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(mode);
- getHwComposer().setActiveConfig(display->getDisplayType(), mode);
+ getHwComposer().setActiveConfig(*displayId, mode);
}
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -979,29 +988,23 @@
return NO_ERROR;
}
+
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
Vector<ColorMode>* outColorModes) {
if (!displayToken || !outColorModes) {
return BAD_VALUE;
}
- int32_t type = NAME_NOT_FOUND;
- for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
- if (displayToken == mDisplayTokens[i]) {
- type = i;
- break;
- }
- }
-
- if (type < 0) {
- return type;
+ const auto displayId = getPhysicalDisplayId(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
}
std::vector<ColorMode> modes;
{
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
- modes = getHwComposer().getColorModes(type);
+ modes = getHwComposer().getColorModes(*displayId);
}
outColorModes->clear();
std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
@@ -1018,6 +1021,11 @@
void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& display, ColorMode mode,
Dataspace dataSpace, RenderIntent renderIntent) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
ColorMode currentMode = display->getActiveColorMode();
Dataspace currentDataSpace = display->getCompositionDataSpace();
RenderIntent currentRenderIntent = display->getActiveRenderIntent();
@@ -1027,19 +1035,17 @@
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set config for virtual display");
- return;
- }
-
display->setActiveColorMode(mode);
display->setCompositionDataSpace(dataSpace);
display->setActiveRenderIntent(renderIntent);
- getHwComposer().setActiveColorMode(display->getDisplayType(), mode, renderIntent);
- ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ getHwComposer().setActiveColorMode(*displayId, mode, renderIntent);
+
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), display=%" PRIu64,
decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent, display->getDisplayType());
+ renderIntent, *displayId);
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
@@ -1170,9 +1176,9 @@
Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
Dataspace* outWideColorGamutDataspace,
ui::PixelFormat* outWideColorGamutPixelFormat) const {
- *outDataspace = defaultCompositionDataspace;
+ *outDataspace = mDefaultCompositionDataspace;
*outPixelFormat = defaultCompositionPixelFormat;
- *outWideColorGamutDataspace = wideColorGamutCompositionDataspace;
+ *outWideColorGamutDataspace = mWideColorGamutCompositionDataspace;
*outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
return NO_ERROR;
}
@@ -1249,18 +1255,22 @@
if (makeAvailable) {
mHWVsyncAvailable = true;
+ // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
+ if (mUseScheduler) {
+ mScheduler->makeHWSyncAvailable(true);
+ }
} else if (!mHWVsyncAvailable) {
// Hardware vsync is not currently available, so abort the resync
// attempt for now
return;
}
- const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- if (!getHwComposer().isConnected(displayId)) {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId || !getHwComposer().isConnected(*displayId)) {
return;
}
- const auto activeConfig = getHwComposer().getActiveConfig(displayId);
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
if (mUseScheduler) {
@@ -1311,12 +1321,11 @@
return;
}
- int32_t type;
- if (!getBE().mHwc->onVsync(hwcDisplayId, timestamp, &type)) {
+ if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
return;
}
- if (type != DisplayDevice::DISPLAY_PRIMARY) {
+ if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
// For now, we don't do anything with external display vsyncs.
return;
}
@@ -1379,11 +1388,13 @@
repaintEverything();
}
-void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
+void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
- getHwComposer().setVsyncEnabled(disp,
- enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ if (const auto displayId = getInternalDisplayId()) {
+ getHwComposer().setVsyncEnabled(*displayId,
+ enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ }
}
// Note: it is assumed the caller holds |mStateLock| when this is called
@@ -1454,7 +1465,7 @@
setPowerModeInternal(display, currentDisplayPowerMode, /*stateLockHeld*/ true);
// Reset the timing values to account for the period of the swapped in HWC
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -1595,24 +1606,25 @@
mGeometryInvalid = false;
for (const auto& [token, display] : mDisplays) {
const auto displayId = display->getId();
- if (displayId >= 0) {
- const Vector<sp<Layer>>& currentLayers(
- display->getVisibleLayersSortedByZ());
- for (size_t i = 0; i < currentLayers.size(); i++) {
- const auto& layer = currentLayers[i];
+ if (!displayId) {
+ continue;
+ }
- if (!layer->hasHwcLayer(displayId)) {
- if (!layer->createHwcLayer(getBE().mHwc.get(), displayId)) {
- layer->forceClientComposition(displayId);
- continue;
- }
- }
+ const Vector<sp<Layer>>& currentLayers = display->getVisibleLayersSortedByZ();
+ for (size_t i = 0; i < currentLayers.size(); i++) {
+ const auto& layer = currentLayers[i];
- layer->setGeometry(display, i);
- if (mDebugDisableHWC || mDebugRegion) {
- layer->forceClientComposition(displayId);
+ if (!layer->hasHwcLayer(*displayId)) {
+ if (!layer->createHwcLayer(&getHwComposer(), *displayId)) {
+ layer->forceClientComposition(*displayId);
+ continue;
}
}
+
+ layer->setGeometry(display, i);
+ if (mDebugDisableHWC || mDebugRegion) {
+ layer->forceClientComposition(*displayId);
+ }
}
}
}
@@ -1620,41 +1632,43 @@
// Set the per-frame data
for (const auto& [token, display] : mDisplays) {
const auto displayId = display->getId();
- if (displayId < 0) {
+ if (!displayId) {
continue;
}
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
- status_t result = getBE().mHwc->setColorTransform(displayId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
- "display %d: %d", displayId, result);
+ status_t result =
+ getHwComposer().setColorTransform(*displayId, mDrawingState.colorMatrix);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %" PRIu64 ": %d",
+ *displayId, result);
}
for (auto& layer : display->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
!display->hasHDR10Support()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
!display->hasHLGSupport()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
}
// TODO(b/111562338) remove when composer 2.3 is shipped.
if (layer->hasColorTransform()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
}
- if (layer->getForceClientComposition(displayId)) {
+ if (layer->getForceClientComposition(*displayId)) {
ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(displayId, HWC2::Composition::Client);
+ layer->setCompositionType(*displayId, HWC2::Composition::Client);
continue;
}
- layer->setPerFrameData(display);
+ layer->setPerFrameData(*displayId, display->getTransform(), display->getViewport(),
+ display->getSupportedPerFrameMetadata());
}
if (useColorManagement) {
@@ -1674,10 +1688,14 @@
for (auto& layer : display->getVisibleLayersSortedByZ()) {
const auto displayId = display->getId();
layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
- if (!layer->setHwcLayer(displayId)) {
- ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+
+ if (displayId) {
+ if (!layer->setHwcLayer(*displayId)) {
+ ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+ }
+ layer->getBE().compositionInfo.hwc.displayId = *displayId;
}
- layer->getBE().compositionInfo.hwc.displayId = displayId;
+
getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
layer->getBE().compositionInfo.hwc.hwcLayer = nullptr;
}
@@ -1837,7 +1855,7 @@
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFence =
- display ? getHwComposer().getPresentFence(display->getId()) : Fence::NO_FENCE;
+ display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
getBE().mDisplayTimeline.push(presentFenceTime);
@@ -1860,8 +1878,8 @@
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
- bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ bool frameLatched = layer->onPostComposition(display->getId(), glCompositionDoneFenceTime,
+ presentFenceTime, compositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
@@ -1881,7 +1899,7 @@
}
if (!hasSyncFramework) {
- if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
+ if (display && getHwComposer().isConnected(*display->getId()) && display->isPoweredOn()) {
if (mUseScheduler) {
mScheduler->enableHardwareVsync();
} else {
@@ -1896,10 +1914,10 @@
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else if (display && getHwComposer().isConnected(display->getId())) {
+ } else if (display && getHwComposer().isConnected(*display->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(display->getId());
+ const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId());
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
@@ -1912,8 +1930,7 @@
mTimeStats.setPresentFenceGlobal(presentFenceTime);
- if (display && getHwComposer().isConnected(display->getId()) &&
- display->getPowerMode() == HWC_POWER_MODE_OFF) {
+ if (display && getHwComposer().isConnected(*display->getId()) && !display->isPoweredOn()) {
return;
}
@@ -1970,6 +1987,7 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool hwcLayerDestroyed = false;
+ const auto displayId = display->getId();
if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
@@ -1979,13 +1997,13 @@
} else {
// Clear out the HWC layer if this layer was
// previously visible, but no longer is
- hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
+ hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
}
} else {
// WM changes display->layerStack upon sleep/awake.
// Here we make sure we delete the HWC layers even if
// WM changed their layer stack.
- hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
+ hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
}
// If a layer is not going to get a release fence because
@@ -2110,12 +2128,11 @@
// emit any black frames until a layer is added to the layer stack.
bool mustRecompose = dirty && !(empty && wasEmpty);
- ALOGV_IF(display->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
- "id[%d]: %s composition (%sdirty %sempty %swasEmpty)", display->getId(),
- mustRecompose ? "doing" : "skipping",
- dirty ? "+" : "-",
- empty ? "+" : "-",
- wasEmpty ? "+" : "-");
+ const char flagPrefix[] = {'-', '+'};
+ static_cast<void>(flagPrefix);
+ ALOGV_IF(display->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
+ __FUNCTION__, mustRecompose ? "doing" : "skipping", display->getDebugName().c_str(),
+ flagPrefix[dirty], flagPrefix[empty], flagPrefix[wasEmpty]);
display->beginFrame(mustRecompose);
@@ -2132,10 +2149,8 @@
status_t result = display->prepareFrame(getHwComposer(),
getBE().mCompositionInfo[display->getDisplayToken()]);
- ALOGE_IF(result != NO_ERROR,
- "prepareFrame for display %d failed:"
- " %d (%s)",
- display->getId(), result, strerror(-result));
+ ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
+ display->getDebugName().c_str(), result, strerror(-result));
}
void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
@@ -2158,8 +2173,9 @@
void SurfaceFlinger::postFrame()
{
// |mStateLock| not needed as we are on the main thread
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
- uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (display && getHwComposer().isConnected(*display->getId())) {
+ uint32_t flipCount = display->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
logFrameStats();
}
@@ -2175,8 +2191,8 @@
if (display->isPoweredOn()) {
const auto displayId = display->getId();
- if (displayId >= 0) {
- getBE().mHwc->presentAndGetReleaseFences(displayId);
+ if (displayId) {
+ getHwComposer().presentAndGetReleaseFences(*displayId);
}
display->onSwapBuffersCompleted();
display->makeCurrent();
@@ -2186,9 +2202,9 @@
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
- auto hwcLayer = layer->getHwcLayer(displayId);
- if (displayId >= 0) {
- releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer);
+ if (displayId && layer->hasHwcLayer(*displayId)) {
+ releaseFence = getHwComposer().getLayerReleaseFence(*displayId,
+ layer->getHwcLayer(*displayId));
}
// If the layer was client composited in the previous frame, we
@@ -2208,14 +2224,15 @@
// display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
if (!display->getLayersNeedingFences().isEmpty()) {
- sp<Fence> presentFence = getBE().mHwc->getPresentFence(displayId);
+ sp<Fence> presentFence =
+ displayId ? getBE().mHwc->getPresentFence(*displayId) : Fence::NO_FENCE;
for (auto& layer : display->getLayersNeedingFences()) {
layer->getBE().onLayerDisplayed(presentFence);
}
}
- if (displayId >= 0) {
- getBE().mHwc->clearReleaseFences(displayId);
+ if (displayId) {
+ getHwComposer().clearReleaseFences(*displayId);
}
}
}
@@ -2250,72 +2267,36 @@
// here the transaction has been committed
}
-DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t hwcDisplayId,
- 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
- // displays are not already connected to determine the type. If we don't
- // have a connected primary display, we assume the new display is meant to
- // be the primary display, and then if we don't have an external display,
- // we assume it is that.
- const auto primaryHwcDisplayId = getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
- const auto externalHwcDisplayId =
- getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
- if (primaryHwcDisplayId && primaryHwcDisplayId == hwcDisplayId) {
- return DisplayDevice::DISPLAY_PRIMARY;
- } else if (externalHwcDisplayId && externalHwcDisplayId == hwcDisplayId) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- } else if (connection == HWC2::Connection::Connected && !primaryHwcDisplayId) {
- return DisplayDevice::DISPLAY_PRIMARY;
- } else if (connection == HWC2::Connection::Connected && !externalHwcDisplayId) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- }
-
- return DisplayDevice::DISPLAY_ID_INVALID;
-}
-
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
for (const auto& event : mPendingHotplugEvents) {
- auto displayType = determineDisplayType(event.hwcDisplayId, event.connection);
- if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
- ALOGW("Unable to determine the display type for display %" PRIu64, event.hwcDisplayId);
- continue;
- }
+ const std::optional<DisplayIdentificationInfo> info =
+ getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
- if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
- ALOGE("External displays are not supported by the vr hardware composer.");
+ if (!info) {
continue;
}
- const auto displayId =
- getBE().mHwc->onHotplug(event.hwcDisplayId, displayType, event.connection);
- if (displayId) {
- ALOGV("Display %" PRIu64 " has stable ID %" PRIu64, event.hwcDisplayId, *displayId);
- }
-
if (event.connection == HWC2::Connection::Connected) {
- if (!mDisplayTokens[displayType].get()) {
- ALOGV("Creating built in display %d", displayType);
- mDisplayTokens[displayType] = new BBinder();
- DisplayDeviceState info;
- info.type = displayType;
- info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
- "Built-in Screen" : "External Screen";
- info.isSecure = true; // All physical displays are currently considered secure.
- mCurrentState.displays.add(mDisplayTokens[displayType], info);
- mInterceptor->saveDisplayCreation(info);
+ if (!mPhysicalDisplayTokens.count(info->id)) {
+ ALOGV("Creating display %" PRIu64, info->id);
+ mPhysicalDisplayTokens[info->id] = new BBinder();
+ DisplayDeviceState state;
+ state.displayId = info->id;
+ state.isSecure = true; // All physical displays are currently considered secure.
+ state.displayName = info->name;
+ mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+ mInterceptor->saveDisplayCreation(state);
}
} else {
- ALOGV("Removing built in display %d", displayType);
+ ALOGV("Removing display %" PRIu64, info->id);
- ssize_t idx = mCurrentState.displays.indexOfKey(mDisplayTokens[displayType]);
- if (idx >= 0) {
- const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- mInterceptor->saveDisplayDeletion(info.sequenceId);
- mCurrentState.displays.removeItemsAt(idx);
+ ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+ if (index >= 0) {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ mInterceptor->saveDisplayDeletion(state.sequenceId);
+ mCurrentState.displays.removeItemsAt(index);
}
- mDisplayTokens[displayType].clear();
+ mPhysicalDisplayTokens.erase(info->id);
}
processDisplayChangesLocked();
@@ -2325,31 +2306,36 @@
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
- const wp<IBinder>& displayToken, int32_t displayId, const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
- DisplayDeviceCreationArgs creationArgs(this, displayToken, state.type, displayId);
+ const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
+ const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface,
+ const sp<IGraphicBufferProducer>& producer) {
+ DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
+ creationArgs.isVirtual = state.isVirtual();
creationArgs.isSecure = state.isSecure;
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
- if (useColorManagement && displayId >= 0) {
- std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
+ const bool isInternalDisplay = displayId && displayId == getInternalDisplayId();
+ creationArgs.isPrimary = isInternalDisplay;
+
+ if (useColorManagement && displayId) {
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (ColorMode colorMode : modes) {
if (isWideColorMode(colorMode)) {
creationArgs.hasWideColorGamut = true;
}
std::vector<RenderIntent> renderIntents =
- getHwComposer().getRenderIntents(displayId, colorMode);
+ getHwComposer().getRenderIntents(*displayId, colorMode);
creationArgs.hwcColorModes.emplace(colorMode, renderIntents);
}
}
- if (displayId >= 0) {
- getHwComposer().getHdrCapabilities(displayId, &creationArgs.hdrCapabilities);
+ if (displayId) {
+ getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities);
creationArgs.supportedPerFrameMetadata =
- getHwComposer().getSupportedPerFrameMetadata(displayId);
+ getHwComposer().getSupportedPerFrameMetadata(*displayId);
}
auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);
@@ -2360,7 +2346,7 @@
* Create our display's surface
*/
std::unique_ptr<renderengine::Surface> renderSurface = getRenderEngine().createSurface();
- renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
+ renderSurface->setCritical(isInternalDisplay);
renderSurface->setAsync(state.isVirtual());
renderSurface->setNativeWindow(nativeWindow.get());
creationArgs.displayWidth = renderSurface->getWidth();
@@ -2378,9 +2364,8 @@
nativeWindow->setSwapInterval(nativeWindow.get(), 0);
}
- creationArgs.displayInstallOrientation = state.type == DisplayDevice::DISPLAY_PRIMARY
- ? primaryDisplayOrientation
- : DisplayState::eOrientationDefault;
+ creationArgs.displayInstallOrientation =
+ isInternalDisplay ? primaryDisplayOrientation : DisplayState::eOrientationDefault;
// virtual displays are always considered enabled
creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
@@ -2399,9 +2384,11 @@
}
setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
RenderIntent::COLORIMETRIC);
- if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
- display->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+ if (!state.isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
}
+
display->setLayerStack(state.layerStack);
display->setProjection(state.orientation, state.viewport, state.frame);
display->setDisplayName(state.displayName);
@@ -2427,6 +2414,10 @@
for (size_t i = 0; i < dc;) {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < 0) {
+ // Save display IDs before disconnecting.
+ const auto internalDisplayId = getInternalDisplayId();
+ const auto externalDisplayId = getExternalDisplayId();
+
// in drawing state but not in current state
// Call makeCurrent() on the primary display so we can
// be sure that nothing associated with this display
@@ -2437,14 +2428,14 @@
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
display->disconnect(getHwComposer());
}
- if (draw[i].type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (internalDisplayId && internalDisplayId == draw[i].displayId) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::Primary, false);
} else {
mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
}
- } else if (draw[i].type == DisplayDevice::DISPLAY_EXTERNAL) {
+ } else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::External, false);
@@ -2502,14 +2493,14 @@
sp<IGraphicBufferConsumer> bqConsumer;
getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);
- int32_t displayId = -1;
+ std::optional<DisplayId> displayId;
if (state.isVirtual()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
if (state.surface != nullptr) {
// Allow VR composer to use virtual displays.
- if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
+ if (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()) {
int width = 0;
int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
@@ -2521,14 +2512,14 @@
ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
auto format = static_cast<ui::PixelFormat>(intFormat);
- getBE().mHwc->allocateVirtualDisplay(width, height, &format,
- &displayId);
+ displayId =
+ getHwComposer().allocateVirtualDisplay(width, height, &format);
}
// TODO: Plumb requested format back up to consumer
sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(*getBE().mHwc, displayId, state.surface,
+ new VirtualDisplaySurface(getHwComposer(), displayId, state.surface,
bqProducer, bqConsumer,
state.displayName);
@@ -2541,8 +2532,9 @@
"surface is provided (%p), ignoring it",
state.surface.get());
- displayId = state.type;
- dispSurface = new FramebufferSurface(*getBE().mHwc, displayId, bqConsumer);
+ displayId = state.displayId;
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
producer = bqProducer;
}
@@ -2552,7 +2544,9 @@
setupNewDisplayDeviceInternal(displayToken, displayId, state,
dispSurface, producer));
if (!state.isVirtual()) {
- if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
+ if (displayId == getInternalDisplayId()) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::Primary,
@@ -2561,7 +2555,7 @@
mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
true);
}
- } else if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+ } else if (displayId == getExternalDisplayId()) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::External,
@@ -2715,7 +2709,7 @@
void SurfaceFlinger::updateCursorAsync()
{
for (const auto& [token, display] : mDisplays) {
- if (display->getId() < 0) {
+ if (!display->getId()) {
continue;
}
@@ -2739,7 +2733,11 @@
// abandon the buffer queue.
if (l->isRemovedFromCurrentState()) {
l->destroyAllHwcLayers();
- l->releasePendingBuffer(systemTime());
+ // destroyAllHwcLayers traverses to children, but releasePendingBuffer
+ // doesn't in other scenarios. So we have to traverse explicitly here.
+ l->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* child) {
+ child->releasePendingBuffer(systemTime());
+ });
}
}
mLayersPendingRemoval.clear();
@@ -3107,8 +3105,9 @@
case HWC2::Composition::Device:
case HWC2::Composition::Sideband:
case HWC2::Composition::SolidColor: {
+ LOG_ALWAYS_FATAL_IF(!displayId);
const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(displayId) && !firstLayer &&
+ if (layer->getClearClientTarget(*displayId) && !firstLayer &&
layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
hasClientComposition) {
// never clear the very first layer since we're
@@ -3826,7 +3825,7 @@
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
- const auto displayToken = mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY];
+ const auto displayToken = getInternalDisplayToken();
if (!displayToken) return;
// reset screen orientation and use primary layer stack
@@ -3850,7 +3849,7 @@
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL, /*stateLockHeld*/ false);
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -3867,16 +3866,18 @@
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
bool stateLockHeld) {
- const int32_t displayId = display->getId();
- ALOGD("Setting power mode %d on display %d", mode, displayId);
-
- int currentMode = display->getPowerMode();
- if (mode == currentMode) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set power mode for virtual display");
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
+ ALOGD("Setting power mode %d on display %" PRIu64, mode, *displayId);
+
+ int currentMode = display->getPowerMode();
+ if (mode == currentMode) {
return;
}
@@ -3892,12 +3893,10 @@
mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).sequenceId, mode);
}
- int32_t type = display->getDisplayType();
if (currentMode == HWC_POWER_MODE_OFF) {
// Turn on the display
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
} else {
@@ -3928,7 +3927,6 @@
} else {
disableHardwareVsync(true); // also cancels any in-progress resync
}
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
} else {
@@ -3936,15 +3934,14 @@
}
}
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
} else if (mode == HWC_POWER_MODE_DOZE ||
mode == HWC_POWER_MODE_NORMAL) {
// Update display while dozing
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
} else {
@@ -3960,24 +3957,23 @@
} else {
disableHardwareVsync(true); // also cancels any in-progress resync
}
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
} else {
mEventThread->onScreenReleased();
}
}
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
} else {
ALOGE("Attempting to set unknown power mode: %d\n", mode);
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
}
if (display->isPrimary()) {
mTimeStats.setPowerMode(mode);
}
- ALOGD("Finished setting power mode %d on display %d", mode, displayId);
+ ALOGD("Finished setting power mode %d on display %" PRIu64, mode, *displayId);
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
@@ -4156,9 +4152,9 @@
index++;
}
- if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- getHwComposer().isConnected(displayId)) {
- const auto activeConfig = getBE().mHwc->getActiveConfig(displayId);
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
result.appendFormat("%" PRId64 "\n", period);
}
@@ -4299,13 +4295,17 @@
void SurfaceFlinger::dumpDisplayIdentificationData(String8& result) const {
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- const auto hwcDisplayId = getHwComposer().getHwcDisplayId(displayId);
+ const auto displayId = display->getId();
+ if (!displayId) {
+ continue;
+ }
+ const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
if (!hwcDisplayId) {
continue;
}
- result.appendFormat("Display %d (HWC display %" PRIu64 "): ", displayId, *hwcDisplayId);
+ result.appendFormat("Display %" PRIu64 " (HWC display %" PRIu64 "): ", *displayId,
+ *hwcDisplayId);
uint8_t port;
DisplayIdentificationData data;
if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
@@ -4336,7 +4336,6 @@
result.append(edid->displayName.data(), edid->displayName.length());
result.append("\"\n");
}
- result.append("\n");
}
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
@@ -4348,13 +4347,13 @@
// TODO: print out if wide-color mode is active or not
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
- result.appendFormat("Display %d color modes:\n", displayId);
- std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
+ result.appendFormat("Display %" PRIu64 " color modes:\n", *displayId);
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (auto&& mode : modes) {
result.appendFormat(" %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
@@ -4410,11 +4409,12 @@
layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
- const int32_t displayId = display.getId();
+ const auto displayId = display.getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(displayId)) {
+ if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, displayId);
+ layer->writeToProto(layerProto, *displayId);
}
});
@@ -4468,25 +4468,19 @@
const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
- if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- getHwComposer().isConnected(displayId)) {
- const auto activeConfig = getHwComposer().getActiveConfig(displayId);
- result.appendFormat("Display %d: "
- "app phase %" PRId64 " ns, "
- "sf phase %" PRId64 " ns, "
- "early app phase %" PRId64 " ns, "
- "early sf phase %" PRId64 " ns, "
- "early app gl phase %" PRId64 " ns, "
- "early sf gl phase %" PRId64 " ns, "
- "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- displayId,
- vsyncPhaseOffsetNs,
- sfVsyncPhaseOffsetNs,
- appEarlyOffset,
- sfEarlyOffset,
- appEarlyGlOffset,
- sfEarlyGlOffset,
- dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+ result.appendFormat("Display %" PRIu64 ": app phase %" PRId64 " ns, "
+ "sf phase %" PRId64 " ns, "
+ "early app phase %" PRId64 " ns, "
+ "early sf phase %" PRId64 " ns, "
+ "early app gl phase %" PRId64 " ns, "
+ "early sf gl phase %" PRId64 " ns, "
+ "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+ *displayId, vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset,
+ sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
+ dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
}
result.append("\n");
@@ -4539,12 +4533,9 @@
result.append("SurfaceFlinger global state:\n");
colorizer.reset(result);
- HWComposer& hwc(getHwComposer());
- const auto display = getDefaultDisplayDeviceLocked();
-
getBE().mRenderEngine->dump(result);
- if (display) {
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
display->undefinedRegion.dump(result, "undefinedRegion");
result.appendFormat(" orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
display->isPoweredOn());
@@ -4553,8 +4544,9 @@
" gpu_to_cpu_unsupported : %d\n",
mTransactionFlags.load(), !mGpuToCpuSupported);
- if (display) {
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
result.appendFormat(" refresh-rate : %f fps\n"
" x-dpi : %f\n"
" y-dpi : %f\n",
@@ -4586,14 +4578,14 @@
* HWC layer minidump
*/
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
- result.appendFormat("Display %d HWC layers:\n", displayId);
+ result.appendFormat("Display %" PRIu64 " HWC layers:\n", *displayId);
Layer::miniDumpHeader(result);
- mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, displayId); });
+ mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, *displayId); });
result.append("\n");
}
@@ -4606,7 +4598,7 @@
bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
result.appendFormat(" h/w composer %s\n",
hwcDisabled ? "disabled" : "enabled");
- hwc.dump(result);
+ getHwComposer().dump(result);
/*
* Dump gralloc state
@@ -4624,7 +4616,7 @@
}
}
-const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int32_t displayId) {
+const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
// Note: mStateLock is held here
for (const auto& [token, display] : mDisplays) {
if (display->getId() == displayId) {
@@ -4632,7 +4624,7 @@
}
}
- ALOGE("%s: Invalid display %d", __FUNCTION__, displayId);
+ ALOGE("%s: Invalid display %" PRIu64, __FUNCTION__, displayId);
static const Vector<sp<Layer>> empty;
return empty;
}
@@ -4766,9 +4758,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1030 are currently use for backdoors. The code
+ // Numbers from 1000 to 1031 are currently use for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1030) {
+ if (code >= 1000 && code <= 1031) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5022,6 +5014,38 @@
reply->writeBool(useColorManagement);
return NO_ERROR;
}
+ // Override default composition data space
+ // adb shell service call SurfaceFlinger 1031 i32 1 DATASPACE_NUMBER DATASPACE_NUMBER \
+ // && adb shell stop zygote && adb shell start zygote
+ // to restore: adb shell service call SurfaceFlinger 1031 i32 0 && \
+ // adb shell stop zygote && adb shell start zygote
+ case 1031: {
+ Mutex::Autolock _l(mStateLock);
+ n = data.readInt32();
+ if (n) {
+ n = data.readInt32();
+ if (n) {
+ Dataspace dataspace = static_cast<Dataspace>(n);
+ if (!validateCompositionDataspace(dataspace)) {
+ return BAD_VALUE;
+ }
+ mDefaultCompositionDataspace = dataspace;
+ }
+ n = data.readInt32();
+ if (n) {
+ Dataspace dataspace = static_cast<Dataspace>(n);
+ if (!validateCompositionDataspace(dataspace)) {
+ return BAD_VALUE;
+ }
+ mWideColorGamutCompositionDataspace = dataspace;
+ }
+ } else {
+ // restore composition data space.
+ mDefaultCompositionDataspace = defaultCompositionDataspace;
+ mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
+ }
+ return NO_ERROR;
+ }
}
}
return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 18e1ca1..6ffe025 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -77,10 +77,11 @@
#include <map>
#include <mutex>
#include <queue>
+#include <set>
#include <string>
#include <thread>
+#include <unordered_map>
#include <utility>
-#include "RenderArea.h"
#include <layerproto/LayerProtoHeader.h>
@@ -349,7 +350,7 @@
// enable/disable h/w composer event
// TODO: this should be made accessible only to EventThread
- void setVsyncEnabled(int disp, int enabled);
+ void setVsyncEnabled(EventThread::DisplayType displayType, bool enabled);
// called on the main thread by MessageQueue when an internal message
// is received
@@ -358,7 +359,7 @@
// for debugging only
// TODO: this should be made accessible only to HWComposer
- const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id);
+ const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
renderengine::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
@@ -664,7 +665,10 @@
}
sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
- return getDisplayDeviceLocked(mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY]);
+ if (const auto token = getInternalDisplayToken()) {
+ return getDisplayDeviceLocked(token);
+ }
+ return nullptr;
}
// mark a region of a layer stack dirty. this updates the dirty
@@ -729,10 +733,8 @@
/* ------------------------------------------------------------------------
* Display management
*/
- DisplayDevice::DisplayType determineDisplayType(hwc2_display_t hwcDisplayId,
- HWC2::Connection connection) const;
sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
- int32_t displayId,
+ const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer);
@@ -764,6 +766,37 @@
}
private:
+ sp<IBinder> getPhysicalDisplayToken(DisplayId displayId) const {
+ const auto it = mPhysicalDisplayTokens.find(displayId);
+ return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
+ }
+
+ std::optional<DisplayId> getPhysicalDisplayId(const sp<IBinder>& displayToken) const {
+ for (const auto& [id, token] : mPhysicalDisplayTokens) {
+ if (token == displayToken) {
+ return id;
+ }
+ }
+ return {};
+ }
+
+ // TODO(b/74619554): Remove special cases for primary display.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ }
+
+ std::optional<DisplayId> getInternalDisplayId() const {
+ const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
+ return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+ }
+
+ // TODO(b/74619554): Remove special cases for external display.
+ std::optional<DisplayId> getExternalDisplayId() const {
+ const auto hwcDisplayId = getHwComposer().getExternalHwcDisplayId();
+ return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+ }
+
void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
@@ -841,7 +874,7 @@
std::unique_ptr<VSyncSource> mSfEventThreadSource;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
std::unique_ptr<EventControlThread> mEventControlThread;
- sp<IBinder> mDisplayTokens[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
+ std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
VSyncModulator mVsyncModulator;
@@ -944,6 +977,9 @@
// Applied on Display P3 layers when the render intent is non-colorimetric.
mat4 mEnhancedSaturationMatrix;
+ ui::Dataspace mDefaultCompositionDataspace;
+ ui::Dataspace mWideColorGamutCompositionDataspace;
+
SurfaceFlingerBE mBE;
bool mUseScheduler = false;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 57bda5a..7faaff6 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -495,8 +495,10 @@
DisplayCreation* creation(increment->mutable_display_creation());
creation->set_id(info.sequenceId);
creation->set_name(info.displayName);
- creation->set_type(info.type);
creation->set_is_secure(info.isSecure);
+ if (info.displayId) {
+ creation->set_display_id(*info.displayId);
+ }
}
void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t sequenceId) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index ace7c1b..9730e8c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -173,8 +173,8 @@
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
+ const std::string& layerName = layerRecord.layerName;
if (prevTimeRecord.ready) {
- const std::string& layerName = layerRecord.layerName;
if (!mTimeStats.stats.count(layerName)) {
mTimeStats.stats[layerName].layerName = layerName;
mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,6 +220,18 @@
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
+
+ // Output additional trace points to track frame time.
+ ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
+ ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
+ timeRecords[0].frameTime.acquireTime);
+ ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
+ timeRecords[0].frameTime.latchTime);
+ ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
+ timeRecords[0].frameTime.desiredTime);
+ ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
+ timeRecords[0].frameTime.presentTime);
+
prevTimeRecord = timeRecords[0];
timeRecords.pop_front();
layerRecord.waitData--;
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 9c2edca..92ae87b 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -28,7 +28,6 @@
#include <cutils/sched_policy.h>
#include <displayservice/DisplayService.h>
#include <hidl/LegacySupport.h>
-#include "GpuService.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
@@ -104,10 +103,6 @@
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
- // publish GpuService
- sp<GpuService> gpuservice = new GpuService();
- sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
-
startDisplayService(); // dependency on SF getting registered above
struct sched_param param = {0};
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 1352df5..09bb8c5 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -65,6 +65,7 @@
constexpr hwc2_layer_t HWC_LAYER = 5000;
constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
+constexpr DisplayId DEFAULT_DISPLAY_ID = 42;
constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
@@ -226,12 +227,13 @@
static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
static void setupPreconditions(CompositionTest* test) {
- FakeHwcDisplayInjector(DisplayDevice::DISPLAY_PRIMARY, HWC2::DisplayType::Physical)
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
+ true /* isPrimary */)
.setCapabilities(&test->mDefaultCapabilities)
.inject(&test->mFlinger, test->mComposer);
- test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DisplayDevice::DISPLAY_PRIMARY,
- DisplayDevice::DISPLAY_PRIMARY)
+ test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
+ false /* isVirtual */, true /* isPrimary */)
.setDisplaySize(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
.setDisplaySurface(test->mDisplaySurface)
.setRenderSurface(std::unique_ptr<renderengine::Surface>(
@@ -553,10 +555,6 @@
IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
.Times(1);
- // TODO: ColorLayer::onPreComposition() always returns true, triggering an
- // extra layer update in SurfaceFlinger::preComposition(). This seems
- // wrong on the surface.
- EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
}
static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
@@ -749,7 +747,9 @@
EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
.WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
- layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), test->mDisplay->getId());
+ const auto displayId = test->mDisplay->getId();
+ ASSERT_TRUE(displayId);
+ layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), *displayId);
Mock::VerifyAndClear(test->mComposer);
@@ -762,8 +762,10 @@
static void cleanupInjectedLayers(CompositionTest* test) {
EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
.WillOnce(Return(Error::NONE));
+ const auto displayId = test->mDisplay->getId();
+ ASSERT_TRUE(displayId);
for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
- layer->destroyHwcLayer(test->mDisplay->getId());
+ layer->destroyHwcLayer(*displayId);
}
test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
}
@@ -951,7 +953,7 @@
struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
static void setupLayerState(CompositionTest*, sp<Layer> layer) {
- layer->forceClientComposition(DisplayDevice::DISPLAY_PRIMARY);
+ layer->forceClientComposition(DEFAULT_DISPLAY_ID);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 4f1c99e..55995d0 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -68,32 +68,44 @@
} // namespace
+const DisplayIdentificationData& getInternalEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kInternalEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getExternalEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kExternalEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getExternalEedid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kExternalEedid);
+ return data;
+}
+
TEST(DisplayIdentificationTest, isEdid) {
EXPECT_FALSE(isEdid({}));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kInternalEdid)));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEdid)));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEedid)));
+ EXPECT_TRUE(isEdid(getInternalEdid()));
+ EXPECT_TRUE(isEdid(getExternalEdid()));
+ EXPECT_TRUE(isEdid(getExternalEedid()));
}
TEST(DisplayIdentificationTest, parseEdid) {
- auto data = asDisplayIdentificationData(kInternalEdid);
- auto edid = parseEdid(data);
+ auto edid = parseEdid(getInternalEdid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x4ca3u, edid->manufacturerId);
EXPECT_STREQ("SEC", edid->pnpId.data());
// ASCII text should be used as fallback if display name and serial number are missing.
EXPECT_EQ("121AT11-801", edid->displayName);
- data = asDisplayIdentificationData(kExternalEdid);
- edid = parseEdid(data);
+ edid = parseEdid(getExternalEdid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x22f0u, edid->manufacturerId);
EXPECT_STREQ("HWP", edid->pnpId.data());
EXPECT_EQ("HP ZR30w", edid->displayName);
- data = asDisplayIdentificationData(kExternalEedid);
- edid = parseEdid(data);
+ edid = parseEdid(getExternalEedid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x4c2du, edid->manufacturerId);
EXPECT_STREQ("SAM", edid->pnpId.data());
@@ -105,7 +117,7 @@
EXPECT_FALSE(parseEdid({}));
// Display name must be printable.
- auto data = asDisplayIdentificationData(kExternalEdid);
+ auto data = getExternalEdid();
data[97] = '\x1b';
auto edid = parseEdid(data);
ASSERT_TRUE(edid);
@@ -128,20 +140,32 @@
EXPECT_STREQ("SAM", getPnpId(0x4c2du).value_or(PnpId{}).data());
}
-TEST(DisplayIdentificationTest, generateDisplayId) {
- const auto primaryId = generateDisplayId(0, asDisplayIdentificationData(kInternalEdid));
- ASSERT_TRUE(primaryId);
+TEST(DisplayIdentificationTest, parseDisplayIdentificationData) {
+ const auto primaryInfo = parseDisplayIdentificationData(0, getInternalEdid());
+ ASSERT_TRUE(primaryInfo);
- const auto secondaryId = generateDisplayId(1, asDisplayIdentificationData(kExternalEdid));
- ASSERT_TRUE(secondaryId);
+ const auto secondaryInfo = parseDisplayIdentificationData(1, getExternalEdid());
+ ASSERT_TRUE(secondaryInfo);
- const auto tertiaryId = generateDisplayId(2, asDisplayIdentificationData(kExternalEedid));
- ASSERT_TRUE(tertiaryId);
+ const auto tertiaryInfo = parseDisplayIdentificationData(2, getExternalEedid());
+ ASSERT_TRUE(tertiaryInfo);
// Display IDs should be unique.
- EXPECT_NE(primaryId, secondaryId);
- EXPECT_NE(primaryId, tertiaryId);
- EXPECT_NE(secondaryId, tertiaryId);
+ EXPECT_NE(primaryInfo->id, secondaryInfo->id);
+ EXPECT_NE(primaryInfo->id, tertiaryInfo->id);
+ EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
+}
+
+TEST(DisplayIdentificationTest, getFallbackDisplayId) {
+ // Manufacturer ID should be invalid.
+ ASSERT_FALSE(getPnpId(getFallbackDisplayId(0)));
+ ASSERT_FALSE(getPnpId(getFallbackDisplayId(0xffu)));
+}
+
+TEST(DisplayIdentificationTest, getVirtualDisplayId) {
+ // Manufacturer ID should be invalid.
+ ASSERT_FALSE(getPnpId(getVirtualDisplayId(0)));
+ ASSERT_FALSE(getPnpId(getVirtualDisplayId(0xffff'ffffu)));
}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
new file mode 100644
index 0000000..1c8e5cc
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
@@ -0,0 +1,27 @@
+/*
+ * 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 "DisplayHardware/DisplayIdentification.h"
+
+namespace android {
+
+const DisplayIdentificationData& getInternalEdid();
+const DisplayIdentificationData& getExternalEdid();
+const DisplayIdentificationData& getExternalEedid();
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index d32627a..2e90a59 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -17,12 +17,16 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <type_traits>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <ui/DebugUtils.h>
+
+#include "DisplayIdentificationTest.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplaySurface.h"
@@ -75,9 +79,11 @@
#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
-BOOL_SUBSTITUTE(Critical);
BOOL_SUBSTITUTE(Async);
+BOOL_SUBSTITUTE(Critical);
+BOOL_SUBSTITUTE(Primary);
BOOL_SUBSTITUTE(Secure);
+BOOL_SUBSTITUTE(Virtual);
/* ------------------------------------------------------------------------
*
@@ -98,7 +104,7 @@
// --------------------------------------------------------------------
// Postcondition helpers
- bool hasHwcDisplay(hwc2_display_t displayId);
+ bool hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId);
bool hasTransactionFlagSet(int flag);
bool hasDisplayDevice(sp<IBinder> displayToken);
sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
@@ -204,8 +210,8 @@
});
}
-bool DisplayTransactionTest::hasHwcDisplay(hwc2_display_t displayId) {
- return mFlinger.mutableHwcDisplaySlots().count(displayId) == 1;
+bool DisplayTransactionTest::hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId) {
+ return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
}
bool DisplayTransactionTest::hasTransactionFlagSet(int flag) {
@@ -240,20 +246,67 @@
*
*/
-template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType displayId, int width,
- int height, Critical critical, Async async, Secure secure, int grallocUsage>
+template <typename PhysicalDisplay>
+struct PhysicalDisplayId {};
+
+template <DisplayId displayId>
+using VirtualDisplayId = std::integral_constant<DisplayId, displayId>;
+
+struct NoDisplayId {};
+
+template <typename>
+struct IsPhysicalDisplayId : std::bool_constant<false> {};
+
+template <typename PhysicalDisplay>
+struct IsPhysicalDisplayId<PhysicalDisplayId<PhysicalDisplay>> : std::bool_constant<true> {};
+
+template <typename>
+struct DisplayIdGetter;
+
+template <typename PhysicalDisplay>
+struct DisplayIdGetter<PhysicalDisplayId<PhysicalDisplay>> {
+ static std::optional<DisplayId> get() {
+ if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+ return getFallbackDisplayId(static_cast<bool>(PhysicalDisplay::PRIMARY)
+ ? HWC_DISPLAY_PRIMARY
+ : HWC_DISPLAY_EXTERNAL);
+ }
+
+ const auto info =
+ parseDisplayIdentificationData(PhysicalDisplay::PORT,
+ PhysicalDisplay::GET_IDENTIFICATION_DATA());
+ return info ? std::make_optional(info->id) : std::nullopt;
+ }
+};
+
+template <DisplayId displayId>
+struct DisplayIdGetter<VirtualDisplayId<displayId>> {
+ static std::optional<DisplayId> get() { return displayId; }
+};
+
+template <>
+struct DisplayIdGetter<NoDisplayId> {
+ static std::optional<DisplayId> get() { return {}; }
+};
+
+// DisplayIdType can be:
+// 1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
+// 2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
+// 3) NoDisplayId for virtual display without HWC backing.
+template <typename DisplayIdType, int width, int height, Critical critical, Async async,
+ Secure secure, Primary primary, int grallocUsage>
struct DisplayVariant {
+ using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+
// The display width and height
static constexpr int WIDTH = width;
static constexpr int HEIGHT = height;
static constexpr int GRALLOC_USAGE = grallocUsage;
- // The type for this display
- static constexpr DisplayDevice::DisplayType TYPE = type;
- static_assert(TYPE != DisplayDevice::DISPLAY_ID_INVALID);
-
- static constexpr DisplayDevice::DisplayType DISPLAY_ID = displayId;
+ // Whether the display is virtual or physical
+ static constexpr Virtual VIRTUAL =
+ IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
// When creating native window surfaces for the framebuffer, whether those should be critical
static constexpr Critical CRITICAL = critical;
@@ -264,8 +317,14 @@
// Whether the display should be treated as secure
static constexpr Secure SECURE = secure;
+ // Whether the display is primary
+ static constexpr Primary PRIMARY = primary;
+
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
- auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, DISPLAY_ID);
+ auto injector =
+ FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
+ static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+
injector.setSecure(static_cast<bool>(SECURE));
return injector;
}
@@ -306,7 +365,8 @@
}
};
-template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant>
+template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant,
+ typename PhysicalDisplay = void>
struct HwcDisplayVariant {
// The display id supplied by the HWC
static constexpr hwc2_display_t HWC_DISPLAY_ID = hwcDisplayId;
@@ -325,7 +385,10 @@
// Called by tests to inject a HWC display setup
static void injectHwcDisplay(DisplayTransactionTest* test) {
- FakeHwcDisplayInjector(DisplayVariant::TYPE, HWC_DISPLAY_TYPE)
+ const auto displayId = DisplayVariant::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ FakeHwcDisplayInjector(*displayId, HWC_DISPLAY_TYPE,
+ static_cast<bool>(DisplayVariant::PRIMARY))
.setHwcDisplayId(HWC_DISPLAY_ID)
.setWidth(DisplayVariant::WIDTH)
.setHeight(DisplayVariant::HEIGHT)
@@ -362,8 +425,16 @@
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_Y, _))
.WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
- .WillRepeatedly(Return(Error::UNSUPPORTED));
+
+ if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
+ SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
+ Return(Error::NONE)));
+ } else {
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillOnce(Return(Error::UNSUPPORTED));
+ }
}
// Called by tests to set up HWC call expectations
@@ -373,50 +444,67 @@
}
};
-struct NonHwcDisplayVariant {
- static void injectHwcDisplay(DisplayTransactionTest*) {}
-
- static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
- }
-};
-
// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
-template <hwc2_display_t hwcDisplayId, DisplayDevice::DisplayType type, int width, int height,
+template <hwc2_display_t hwcDisplayId, typename PhysicalDisplay, int width, int height,
Critical critical>
struct PhysicalDisplayVariant
- : public DisplayVariant<type, type, width, height, critical, Async::FALSE, Secure::TRUE,
- GRALLOC_USAGE_PHYSICAL_DISPLAY>,
- public HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
- DisplayVariant<type, type, width, height, critical, Async::FALSE,
- Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {};
+ : DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height, critical, Async::FALSE,
+ Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+ HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
+ DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height,
+ critical, Async::FALSE, Secure::TRUE,
+ PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+ PhysicalDisplay> {};
+
+template <bool hasIdentificationData>
+struct PrimaryDisplay {
+ static constexpr Primary PRIMARY = Primary::TRUE;
+ static constexpr uint8_t PORT = 255;
+ static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+ static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
+};
+
+template <bool hasIdentificationData>
+struct ExternalDisplay {
+ static constexpr Primary PRIMARY = Primary::FALSE;
+ static constexpr uint8_t PORT = 254;
+ static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+ static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
+};
+
+struct TertiaryDisplay {
+ static constexpr Primary PRIMARY = Primary::FALSE;
+};
// A primary display is a physical display that is critical
using PrimaryDisplayVariant =
- PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>;
+ PhysicalDisplayVariant<1001, PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
// An external display is physical display that is not critical.
using ExternalDisplayVariant =
- PhysicalDisplayVariant<1002, DisplayDevice::DISPLAY_EXTERNAL, 1920, 1280, Critical::FALSE>;
+ PhysicalDisplayVariant<1002, ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
using TertiaryDisplayVariant =
- PhysicalDisplayVariant<1003, DisplayDevice::DISPLAY_EXTERNAL, 1600, 1200, Critical::FALSE>;
+ PhysicalDisplayVariant<1003, TertiaryDisplay, 1600, 1200, Critical::FALSE>;
// A virtual display not supported by the HWC.
constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
template <int width, int height, Secure secure>
struct NonHwcVirtualDisplayVariant
- : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
- width, height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>,
- public NonHwcDisplayVariant {
- using Base = DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
- width, height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+ : DisplayVariant<NoDisplayId, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
+ using Base = DisplayVariant<NoDisplayId, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+
+ static void injectHwcDisplay(DisplayTransactionTest*) {}
+
+ static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
+ }
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
Base::setupNativeWindowSurfaceCreationCallExpectations(test);
@@ -429,14 +517,14 @@
template <int width, int height, Secure secure>
struct HwcVirtualDisplayVariant
- : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
- height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
- public HwcDisplayVariant<1010, HWC2::DisplayType::Virtual,
- NonHwcVirtualDisplayVariant<width, height, secure>> {
- using Base =
- DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
- height, Critical::FALSE, Async::TRUE, secure, GRALLOC_USAGE_HW_COMPOSER>;
+ : DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
+ HwcDisplayVariant<
+ 1010, HWC2::DisplayType::Virtual,
+ DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
+ using Base = DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
using Self = HwcVirtualDisplayVariant<width, height, secure>;
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
@@ -850,8 +938,8 @@
// The display should have been added to the current state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& display = getCurrentDisplayState(displayToken);
- EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
- EXPECT_EQ(false, display.isSecure);
+ EXPECT_TRUE(display.isVirtual());
+ EXPECT_FALSE(display.isSecure);
EXPECT_EQ(name.string(), display.displayName);
// --------------------------------------------------------------------
@@ -881,8 +969,8 @@
// The display should have been added to the current state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& display = getCurrentDisplayState(displayToken);
- EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
- EXPECT_EQ(true, display.isSecure);
+ EXPECT_TRUE(display.isVirtual());
+ EXPECT_TRUE(display.isSecure);
EXPECT_EQ(name.string(), display.displayName);
// --------------------------------------------------------------------
@@ -1002,9 +1090,12 @@
*/
class GetBestColorModeTest : public DisplayTransactionTest {
public:
+ static constexpr DisplayId DEFAULT_DISPLAY_ID = 777;
+
GetBestColorModeTest()
: DisplayTransactionTest(),
- mInjector(FakeDisplayDeviceInjector(mFlinger, DisplayDevice::DISPLAY_PRIMARY, 0)) {}
+ mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
+ true /* isPrimary */)) {}
void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
@@ -1127,18 +1218,22 @@
// Invocation
DisplayDeviceState state;
- state.type = Case::Display::TYPE;
+ state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get();
state.isSecure = static_cast<bool>(Case::Display::SECURE);
- auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::TYPE, state,
- displaySurface, producer);
+ auto device =
+ mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::DISPLAY_ID::get(),
+ state, displaySurface, producer);
// --------------------------------------------------------------------
// Postconditions
ASSERT_TRUE(device != nullptr);
- EXPECT_EQ(Case::Display::TYPE, device->getDisplayType());
+ EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
@@ -1166,11 +1261,14 @@
}
TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
- // We need to resize this so that the HWC thinks the virtual display
- // is something it created.
- mFlinger.mutableHwcDisplayData().resize(3);
+ using Case = HwcVirtualDisplayCase;
- setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
+ // Insert display data so that the HWC thinks it created the virtual display.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
+
+ setupNewDisplayDeviceInternalTest<Case>();
}
TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
@@ -1258,7 +1356,7 @@
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
EXPECT_CALL(*mEventThread,
- onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+ onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
? EventThread::DisplayType::Primary
: EventThread::DisplayType::External,
true))
@@ -1269,7 +1367,7 @@
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
EXPECT_CALL(*mEventThread,
- onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+ onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
? EventThread::DisplayType::Primary
: EventThread::DisplayType::External,
false))
@@ -1282,30 +1380,35 @@
ASSERT_TRUE(hasDisplayDevice(displayToken));
const auto& device = getDisplayDevice(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
- EXPECT_EQ(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY, device->isPrimary());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
// The display should have been set up in the current display state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& current = getCurrentDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, current.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get(),
+ current.displayId);
// The display should have been set up in the drawing display state
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, draw.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get(),
+ draw.displayId);
}
template <typename Case>
void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
// HWComposer should have an entry for the display
- EXPECT_TRUE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should be set up as a built-in display.
- static_assert(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "Must use a valid physical display type index for the fixed-size array");
- auto& displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- ASSERT_TRUE(displayToken != nullptr);
+ // SF should have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1);
+ auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[*displayId];
verifyDisplayIsConnected<Case>(displayToken);
}
@@ -1371,7 +1474,7 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
}
template <typename Case>
@@ -1407,13 +1510,12 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should not be set up as a built-in display.
- ASSERT_TRUE(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
- auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- EXPECT_TRUE(displayToken == nullptr);
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0);
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
@@ -1500,13 +1602,12 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should not be set up as a primary built-in display.
- ASSERT_TRUE(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
- auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- EXPECT_TRUE(displayToken == nullptr);
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0);
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
@@ -1545,10 +1646,10 @@
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
- static_assert(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "Display type must be a built-in display");
- EXPECT_NE(existing.token(), mFlinger.mutableDisplayTokens()[Case::Display::TYPE]);
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1);
+ EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[*displayId]);
// A new display should be connected in its place
@@ -1578,13 +1679,12 @@
// surface(producer)
sp<BBinder> displayToken = new BBinder();
- DisplayDeviceState info;
- info.type = Case::Display::TYPE;
- info.isSecure = static_cast<bool>(Case::Display::SECURE);
+ DisplayDeviceState state;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
- info.surface = surface;
- mFlinger.mutableCurrentState().displays.add(displayToken, info);
+ state.surface = surface;
+ mFlinger.mutableCurrentState().displays.add(displayToken, state);
// --------------------------------------------------------------------
// Call Expectations
@@ -1646,11 +1746,10 @@
// surface.
sp<BBinder> displayToken = new BBinder();
- DisplayDeviceState info;
- info.type = Case::Display::TYPE;
- info.isSecure = static_cast<bool>(Case::Display::SECURE);
+ DisplayDeviceState state;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
- mFlinger.mutableCurrentState().displays.add(displayToken, info);
+ mFlinger.mutableCurrentState().displays.add(displayToken, state);
// --------------------------------------------------------------------
// Call Expectations
@@ -1669,7 +1768,7 @@
// The drawing display state will be set from the current display state.
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, draw.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
@@ -1679,7 +1778,9 @@
// Preconditions
// A virtual display is set up but is removed from the current state.
- mFlinger.mutableHwcDisplayData().resize(3);
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
Case::Display::injectHwcDisplay(this);
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
existing.inject();
@@ -2799,9 +2900,10 @@
// --------------------------------------------------------------------
// Preconditions
- // We need to resize this so that the HWC thinks the virtual display
- // is something it created.
- mFlinger.mutableHwcDisplayData().resize(3);
+ // Insert display data so that the HWC thinks it created the virtual display.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
// A virtual display device is set up
Case::Display::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index c3534e8..b046e4a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -178,10 +178,6 @@
layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
}
- void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
- layer->getBE().mHwcLayers[DisplayDevice::DISPLAY_PRIMARY].compositionType = type;
- };
-
void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
layer->mPotentialCursor = potentialCursor;
}
@@ -200,7 +196,8 @@
auto resetDisplayState() { return mFlinger->resetDisplayState(); }
- auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken, int32_t displayId,
+ auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
+ const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
@@ -263,7 +260,6 @@
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
auto& mutableDisplays() { return mFlinger->mDisplays; }
- auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
auto& mutableEventQueue() { return mFlinger->mEventQueue; }
@@ -273,6 +269,7 @@
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+ auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
@@ -280,8 +277,13 @@
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
- auto& mutableHwcDisplayData() { return mFlinger->getBE().mHwc->mDisplayData; }
- auto& mutableHwcDisplaySlots() { return mFlinger->getBE().mHwc->mHwcDisplaySlots; }
+ auto& mutableHwcDisplayData() { return mFlinger->getHwComposer().mDisplayData; }
+ auto& mutableHwcPhysicalDisplayIdMap() {
+ return mFlinger->getHwComposer().mPhysicalDisplayIdMap;
+ }
+
+ auto& mutableInternalHwcDisplayId() { return mFlinger->getHwComposer().mInternalHwcDisplayId; }
+ auto& mutableExternalHwcDisplayId() { return mFlinger->getHwComposer().mExternalHwcDisplayId; }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
@@ -333,8 +335,9 @@
static constexpr int32_t DEFAULT_DPI = 320;
static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
- FakeHwcDisplayInjector(DisplayDevice::DisplayType type, HWC2::DisplayType hwcDisplayType)
- : mType(type), mHwcDisplayType(hwcDisplayType) {}
+ FakeHwcDisplayInjector(DisplayId displayId, HWC2::DisplayType hwcDisplayType,
+ bool isPrimary)
+ : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {}
auto& setHwcDisplayId(hwc2_display_t displayId) {
mHwcDisplayId = displayId;
@@ -403,17 +406,22 @@
display->mutableConfigs().emplace(mActiveConfig, config.build());
display->mutableIsConnected() = true;
- ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType));
- flinger->mutableHwcDisplayData()[mType] = HWComposer::DisplayData();
- flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get();
- flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType);
+ flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = display.get();
+
+ if (mHwcDisplayType == HWC2::DisplayType::Physical) {
+ flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, mDisplayId);
+ (mIsPrimary ? flinger->mutableInternalHwcDisplayId()
+ : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
+ }
flinger->mFakeHwcDisplays.push_back(std::move(display));
}
private:
- DisplayDevice::DisplayType mType;
- HWC2::DisplayType mHwcDisplayType;
+ const DisplayId mDisplayId;
+ const HWC2::DisplayType mHwcDisplayType;
+ const bool mIsPrimary;
+
hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
int32_t mWidth = DEFAULT_WIDTH;
int32_t mHeight = DEFAULT_HEIGHT;
@@ -427,10 +435,13 @@
class FakeDisplayDeviceInjector {
public:
- FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, DisplayDevice::DisplayType type,
- int32_t displayId)
- : mFlinger(flinger),
- mCreationArgs(flinger.mFlinger.get(), mDisplayToken, type, displayId) {}
+ FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
+ const std::optional<DisplayId>& displayId, bool isVirtual,
+ bool isPrimary)
+ : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
+ mCreationArgs.isVirtual = isVirtual;
+ mCreationArgs.isPrimary = isPrimary;
+ }
sp<IBinder> token() const { return mDisplayToken; }
@@ -497,7 +508,7 @@
sp<DisplayDevice> inject() {
DisplayDeviceState state;
- state.type = mCreationArgs.type;
+ state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
state.isSecure = mCreationArgs.isSecure;
sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
@@ -505,9 +516,9 @@
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
- if (state.type >= DisplayDevice::DISPLAY_PRIMARY &&
- state.type < DisplayDevice::DISPLAY_VIRTUAL) {
- mFlinger.mutableDisplayTokens()[state.type] = mDisplayToken;
+ if (!mCreationArgs.isVirtual) {
+ LOG_ALWAYS_FATAL_IF(!state.displayId);
+ mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
}
return device;
diff --git a/services/thermalservice/Android.bp b/services/thermalservice/Android.bp
deleted file mode 100644
index 2812c13..0000000
--- a/services/thermalservice/Android.bp
+++ /dev/null
@@ -1,63 +0,0 @@
-subdirs = [
- "libthermalcallback"
-]
-
-cc_library {
- name: "libthermalservice",
-
- srcs: [
- "aidl/android/os/IThermalEventListener.aidl",
- "aidl/android/os/IThermalService.aidl",
- "aidl/android/os/Temperature.cpp",
- ],
- aidl: {
- include_dirs: ["frameworks/native/services/thermalservice/aidl"],
- export_aidl_headers: true,
- },
- export_include_dirs: ["aidl"],
-
- shared_libs: [
- "libbinder",
- "libutils",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
-
-cc_binary {
- name: "thermalserviced",
-
- srcs: [
- "ThermalService.cpp",
- "thermalserviced.cpp",
- ],
-
- include_dirs: ["frameworks/native"],
-
- shared_libs: [
- "libbase",
- "libthermalservice",
- "libbinder",
- "libutils",
- "libthermalcallback",
- "android.hardware.thermal@1.1",
- "android.hardware.thermal@2.0",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
-
- init_rc: ["thermalservice.rc"],
-}
diff --git a/services/thermalservice/ThermalService.cpp b/services/thermalservice/ThermalService.cpp
deleted file mode 100644
index b1a80de..0000000
--- a/services/thermalservice/ThermalService.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ThermalService.h"
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android/os/IThermalEventListener.h>
-#include <android/os/IThermalService.h>
-#include <android/os/Temperature.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/PermissionCache.h>
-#include <log/log.h>
-#include <private/android_filesystem_config.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-
-namespace android {
-namespace os {
-
-/**
- * Dump thermal service
- * @param fd file descriptor for dumping
- * @param args not used
- */
-status_t ThermalService::dump(int fd, const Vector<String16>& /* args */) {
- status_t ret = OK;
- std::string result;
- const IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_SHELL) &&
- !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
- result = android::base::
- StringPrintf("Permission Denial: can't dump ThermalService from pid=%d, uid=%d\n",
- pid, uid);
- ret = PERMISSION_DENIED;
- } else {
- Mutex::Autolock _l(mListenersLock);
- result = android::base::StringPrintf("ThermalEventListener registered: %d\n",
- (int)mListeners.size());
- }
- if (!android::base::WriteStringToFd(result, fd)) {
- SLOGE("Failed to dump fd: %d", fd);
- ret = FDS_NOT_ALLOWED;
- }
- return ret;
-}
-
-/**
- * Notify registered listeners of a thermal throttling start/stop event.
- * @param temperature the temperature at which the event was generated
- */
-binder::Status ThermalService::notifyThrottling(
- const bool isThrottling, const Temperature& temperature) {
- Mutex::Autolock _l(mListenersLock);
-
- mThrottled = isThrottling;
- mThrottleTemperature = temperature;
-
- for (size_t i = 0; i < mListeners.size(); i++) {
- mListeners[i]->notifyThrottling(isThrottling, temperature);
- }
- return binder::Status::ok();
-}
-
-/**
- * Query whether the system is currently thermal throttling.
- * @return true if currently thermal throttling, else false
- */
-binder::Status ThermalService::isThrottling(bool* _aidl_return) {
- Mutex::Autolock _l(mListenersLock);
- *_aidl_return = mThrottled;
- return binder::Status::ok();
-}
-
-/**
- * Register a new thermal event listener.
- * @param listener the client's IThermalEventListener instance to which
- * notifications are to be sent
- */
-binder::Status ThermalService::registerThermalEventListener(
- const sp<IThermalEventListener>& listener) {
- {
- if (listener == NULL) {
- return binder::Status::ok();
- }
- Mutex::Autolock _l(mListenersLock);
- // check whether this is a duplicate
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) ==
- IInterface::asBinder(listener)) {
- return binder::Status::ok();
- }
- }
-
- mListeners.add(listener);
- IInterface::asBinder(listener)->linkToDeath(this);
- }
-
- return binder::Status::ok();
-}
-
-/**
- * Unregister a previously-registered thermal event listener.
- * @param listener the client's IThermalEventListener instance to which
- * notifications are to no longer be sent
- */
-binder::Status ThermalService::unregisterThermalEventListener(
- const sp<IThermalEventListener>& listener) {
- if (listener == NULL) {
- return binder::Status::ok();
- }
- Mutex::Autolock _l(mListenersLock);
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) ==
- IInterface::asBinder(listener)) {
- IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
- mListeners.removeAt(i);
- break;
- }
- }
-
- return binder::Status::ok();
-}
-
-void ThermalService::binderDied(const wp<IBinder>& who) {
- Mutex::Autolock _l(mListenersLock);
-
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == who) {
- mListeners.removeAt(i);
- break;
- }
- }
-}
-
-/**
- * Publish the supplied ThermalService to servicemanager.
- */
-void ThermalService::publish(
- const sp<ThermalService>& service) {
- defaultServiceManager()->addService(String16("thermalservice"),
- service);
-}
-
-} // namespace os
-} // namespace android
diff --git a/services/thermalservice/ThermalService.h b/services/thermalservice/ThermalService.h
deleted file mode 100644
index d3da900..0000000
--- a/services/thermalservice/ThermalService.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_THERMALSERVICE_THERMALSERVICE_H
-#define ANDROID_THERMALSERVICE_THERMALSERVICE_H
-
-#include <android/os/BnThermalService.h>
-#include <android/os/IThermalEventListener.h>
-#include <android/os/Temperature.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace os {
-
-class ThermalService : public BnThermalService,
- public IBinder::DeathRecipient {
-public:
- ThermalService() : mThrottled(false) {};
- void publish(const sp<ThermalService>& service);
- binder::Status notifyThrottling(
- const bool isThrottling, const Temperature& temperature);
- status_t dump(int fd, const Vector<String16>& args) override;
-
-private:
- Mutex mListenersLock;
- Vector<sp<IThermalEventListener> > mListeners;
- bool mThrottled;
- Temperature mThrottleTemperature;
-
- binder::Status registerThermalEventListener(
- const sp<IThermalEventListener>& listener);
- binder::Status unregisterThermalEventListener(
- const sp<IThermalEventListener>& listener);
- binder::Status isThrottling(bool* _aidl_return);
- void binderDied(const wp<IBinder>& who);
-};
-
-}; // namespace os
-}; // namespace android
-
-#endif // ANDROID_THERMALSERVICE_THERMALSERVICE_H
diff --git a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
deleted file mode 100644
index 050325e..0000000
--- a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.Temperature;
-
-/**
- * Listener for thermal events.
- * {@hide}
- */
-oneway interface IThermalEventListener {
- /**
- * Called when a thermal throttling start/stop event is received.
- * @param temperature the temperature at which the event was generated.
- */
- void notifyThrottling(
- in boolean isThrottling, in Temperature temperature);
-}
diff --git a/services/thermalservice/aidl/android/os/IThermalService.aidl b/services/thermalservice/aidl/android/os/IThermalService.aidl
deleted file mode 100644
index e699202..0000000
--- a/services/thermalservice/aidl/android/os/IThermalService.aidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.IThermalEventListener;
-import android.os.Temperature;
-
-/** {@hide} */
-interface IThermalService {
- /**
- * Register a listener for thermal events.
- * @param listener the IThermalEventListener to be notified.
- * {@hide}
- */
- void registerThermalEventListener(in IThermalEventListener listener);
- /**
- * Unregister a previously-registered listener for thermal events.
- * @param listener the IThermalEventListener to no longer be notified.
- * {@hide}
- */
- void unregisterThermalEventListener(in IThermalEventListener listener);
- /**
- * Send a thermal throttling start/stop notification to all listeners.
- * @param temperature the temperature at which the event was generated.
- * {@hide}
- */
- oneway void notifyThrottling(
- in boolean isThrottling, in Temperature temperature);
- /**
- * Return whether system performance is currently thermal throttling.
- * {@hide}
- */
- boolean isThrottling();
-}
diff --git a/services/thermalservice/aidl/android/os/Temperature.aidl b/services/thermalservice/aidl/android/os/Temperature.aidl
deleted file mode 100644
index 0293c39..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.aidl
+++ /dev/null
@@ -1,5 +0,0 @@
-package android.os;
-
-/* Encodes a temperature used by ThermalService. */
-
-parcelable Temperature cpp_header "android/os/Temperature.h";
diff --git a/services/thermalservice/aidl/android/os/Temperature.cpp b/services/thermalservice/aidl/android/os/Temperature.cpp
deleted file mode 100644
index df207b7..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android/os/Temperature.h"
-
-#include <math.h>
-#include <stdint.h>
-#include <binder/Parcel.h>
-#include <hardware/thermal.h>
-#include <sys/types.h>
-#include <utils/Errors.h>
-
-namespace android {
-namespace os {
-
-Temperature::Temperature() : value_(NAN), type_(DEVICE_TEMPERATURE_UNKNOWN) {}
-
-Temperature::Temperature(const float value, const int type) :
- value_(value), type_(type) {}
-
-Temperature::~Temperature() {}
-
-/*
- * Parcel read/write code must be kept in sync with
- * frameworks/base/core/java/android/os/Temperature.java
- */
-
-status_t Temperature::readFromParcel(const Parcel* p) {
- value_ = p->readFloat();
- type_ = p->readInt32();
- return OK;
-}
-
-status_t Temperature::writeToParcel(Parcel* p) const {
- p->writeFloat(value_);
- p->writeInt32(type_);
- return OK;
-}
-
-} // namespace os
-} // namespace android
diff --git a/services/thermalservice/aidl/android/os/Temperature.h b/services/thermalservice/aidl/android/os/Temperature.h
deleted file mode 100644
index bbc5607..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
-#define ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
-
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace os {
-
-class Temperature : public Parcelable {
- public:
-
- Temperature();
- Temperature(const float value, const int type);
- ~Temperature() override;
-
- float getValue() const {return value_;};
- float getType() const {return type_;};
-
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
- private:
- // The value of the temperature as a float, or NAN if unknown.
- float value_;
- // The type of the temperature, an enum temperature_type from
- // hardware/thermal.h
- int type_;
-};
-
-} // namespace os
-} // namespace android
-
-#endif // ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
diff --git a/services/thermalservice/libthermalcallback/Android.bp b/services/thermalservice/libthermalcallback/Android.bp
deleted file mode 100644
index 312579c..0000000
--- a/services/thermalservice/libthermalcallback/Android.bp
+++ /dev/null
@@ -1,21 +0,0 @@
-cc_library_shared {
- name: "libthermalcallback",
- srcs: [
- "ThermalCallback.cpp",
- "ThermalChangedCallback.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- include_dirs: ["frameworks/native"],
- shared_libs: [
- "android.hardware.thermal@1.1",
- "android.hardware.thermal@2.0",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libthermalservice",
- "libutils",
- ],
-}
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.cpp b/services/thermalservice/libthermalcallback/ThermalCallback.cpp
deleted file mode 100644
index 0f3132c..0000000
--- a/services/thermalservice/libthermalcallback/ThermalCallback.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#define LOG_TAG "android.hardware.thermal.thermalcallback@1.1-impl"
-#include <log/log.h>
-
-#include <android/os/Temperature.h>
-#include <hardware/thermal.h>
-#include <cmath>
-#include "ThermalCallback.h"
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::os::ThermalService;
-using ::android::hardware::thermal::V1_0::TemperatureType;
-
-// Register a binder ThermalService object for sending events
-void ThermalCallback::registerThermalService(sp<ThermalService> thermalService)
-{
- mThermalService = thermalService;
-}
-
-// Methods from IThermalCallback::V1_1 follow.
-Return<void> ThermalCallback::notifyThrottling(
- bool isThrottling,
- const android::hardware::thermal::V1_0::Temperature& temperature) {
-
- // Convert HIDL IThermal Temperature to binder IThermalService Temperature.
- if (mThermalService != nullptr) {
- float value = NAN;
- int type = DEVICE_TEMPERATURE_UNKNOWN;
-
- switch(temperature.type) {
- case TemperatureType::CPU:
- type = DEVICE_TEMPERATURE_CPU;
- break;
- case TemperatureType::GPU:
- type = DEVICE_TEMPERATURE_GPU;
- break;
- case TemperatureType::BATTERY:
- type = DEVICE_TEMPERATURE_BATTERY;
- break;
- case TemperatureType::SKIN:
- type = DEVICE_TEMPERATURE_SKIN;
- break;
- case TemperatureType::UNKNOWN:
- default:
- type = DEVICE_TEMPERATURE_UNKNOWN;
- break;
- }
-
- value = temperature.currentValue == UNKNOWN_TEMPERATURE ? NAN :
- temperature.currentValue;
-
- android::os::Temperature thermal_svc_temp(value, type);
- mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
- } else {
- SLOGE("IThermalService binder service not created, drop throttling event");
- }
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace thermal
-} // namespace hardware
-} // namespace android
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.h b/services/thermalservice/libthermalcallback/ThermalCallback.h
deleted file mode 100644
index 3d72c68..0000000
--- a/services/thermalservice/libthermalcallback/ThermalCallback.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
-#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
-
-#include <android/hardware/thermal/1.1/IThermalCallback.h>
-#include <android/hardware/thermal/1.0/types.h>
-#include <android/os/Temperature.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::os::ThermalService;
-
-class ThermalCallback : public IThermalCallback {
- public:
- // Register a binder ThermalService object for sending events
- void registerThermalService(sp<ThermalService> thermalService);
-
- // Methods from IThermalCallback::V1_1 follow.
- Return<void> notifyThrottling(
- bool isThrottling,
- const android::hardware::thermal::V1_0::Temperature& temperature)
- override;
-
- private:
- // Our registered binder ThermalService object to use for sending events
- sp<android::os::ThermalService> mThermalService;
-};
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace thermal
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
diff --git a/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp b/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
deleted file mode 100644
index bb48387..0000000
--- a/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "android.hardware.thermal.thermalchangedcallback@2.0-impl"
-#include <log/log.h>
-
-#include <android/os/Temperature.h>
-#include <hardware/thermal.h>
-#include <cmath>
-#include "ThermalChangedCallback.h"
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::thermal::V2_0::TemperatureType;
-using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
-using ::android::os::ThermalService;
-
-// Register a binder ThermalService object for sending events
-void ThermalChangedCallback::registerThermalService(sp<ThermalService> thermalService) {
- mThermalService = thermalService;
-}
-
-// Methods from IThermalChangedCallback::V2_0 follow.
-Return<void> ThermalChangedCallback::notifyThrottling(
- const android::hardware::thermal::V2_0::Temperature& temperature) {
- // Convert HIDL IThermal Temperature to binder IThermalService Temperature.
- if (mThermalService != nullptr) {
- float value = NAN;
- int type = DEVICE_TEMPERATURE_UNKNOWN;
-
- switch (temperature.type) {
- case TemperatureType::CPU:
- type = DEVICE_TEMPERATURE_CPU;
- break;
- case TemperatureType::GPU:
- type = DEVICE_TEMPERATURE_GPU;
- break;
- case TemperatureType::BATTERY:
- type = DEVICE_TEMPERATURE_BATTERY;
- break;
- case TemperatureType::SKIN:
- type = DEVICE_TEMPERATURE_SKIN;
- break;
- case TemperatureType::UNKNOWN:
- default:
- type = DEVICE_TEMPERATURE_UNKNOWN;
- break;
- }
- bool isThrottling = (static_cast<size_t>(temperature.throttlingStatus) >=
- static_cast<size_t>(ThrottlingSeverity::SEVERE))
- ? true
- : false;
- value = temperature.value == UNKNOWN_TEMPERATURE ? NAN :
- temperature.value;
- android::os::Temperature thermal_svc_temp(value, type);
- mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
- } else {
- SLOGE("IThermalService binder service not created, drop throttling event");
- }
- return Void();
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
diff --git a/services/thermalservice/libthermalcallback/ThermalChangedCallback.h b/services/thermalservice/libthermalcallback/ThermalChangedCallback.h
deleted file mode 100644
index 03de049..0000000
--- a/services/thermalservice/libthermalcallback/ThermalChangedCallback.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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_HARDWARE_THERMAL_V1_1_THERMALCHANGEDCALLBACK_H
-#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCHANGEDCALLBACK_H
-
-#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
-#include <android/hardware/thermal/2.0/types.h>
-#include <android/os/Temperature.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::os::ThermalService;
-
-class ThermalChangedCallback : public IThermalChangedCallback {
-public:
- // Register a binder ThermalService object for sending events
- void registerThermalService(sp<ThermalService> thermalService);
-
- // Methods from I ThermalChangedCallback::V2_0 follow.
- Return<void> notifyThrottling(
- const android::hardware::thermal::V2_0::Temperature& temperature) override;
-
-private:
- // Our registered binder ThermalService object to use for sending events
- sp<android::os::ThermalService> mThermalService;
-};
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCHANGEDCALLBACK_H
diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc
deleted file mode 100644
index 5e20170..0000000
--- a/services/thermalservice/thermalservice.rc
+++ /dev/null
@@ -1,6 +0,0 @@
-service thermalservice /system/bin/thermalserviced
- class core
- user system
- group system
- onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks
diff --git a/services/thermalservice/thermalserviced.cpp b/services/thermalservice/thermalserviced.cpp
deleted file mode 100644
index 0bfaaff..0000000
--- a/services/thermalservice/thermalserviced.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "thermalserviced"
-#include <log/log.h>
-
-#include "ThermalService.h"
-#include "libthermalcallback/ThermalCallback.h"
-#include "libthermalcallback/ThermalChangedCallback.h"
-#include "thermalserviced.h"
-
-#include <android/hardware/thermal/1.1/IThermal.h>
-#include <android/hardware/thermal/2.0/IThermal.h>
-#include <android/hardware/thermal/2.0/types.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <hidl/HidlTransportSupport.h>
-
-using namespace android;
-using IThermal1_1 = ::android::hardware::thermal::V1_1::IThermal;
-using IThermal2_0 = ::android::hardware::thermal::V2_0::IThermal;
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::hidl_death_recipient;
-using ::android::hardware::Return;
-using ::android::hardware::thermal::V1_0::ThermalStatus;
-using ::android::hardware::thermal::V1_0::ThermalStatusCode;
-using ::android::hardware::thermal::V1_1::IThermalCallback;
-using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
-using ::android::hardware::thermal::V2_0::IThermalChangedCallback;
-using ::android::hardware::thermal::V2_0::TemperatureType;
-using ::android::hidl::base::V1_0::IBase;
-using ::android::os::ThermalService;
-
-namespace {
-
-// Our thermalserviced main object
-ThermalServiceDaemon* gThermalServiceDaemon;
-
-// Thermal HAL 1.1 client
-sp<IThermal1_1> gThermalHal1_1 = nullptr;
-// Thermal HAL 2.0 client
-sp<IThermal2_0> gThermalHal2_0 = nullptr;
-
-// Binder death notifier informing of Thermal HAL death.
-struct ThermalServiceDeathRecipient : hidl_death_recipient {
- virtual void serviceDied(
- uint64_t cookie __unused, const wp<IBase>& who __unused) {
- SLOGE("IThermal HAL died");
- gThermalHal1_1 = nullptr;
- gThermalHal2_0 = nullptr;
- gThermalServiceDaemon->getThermalHal();
- }
-};
-
-} // anonymous namespace
-
-void ThermalServiceDaemon::thermalServiceStartup() {
- // Binder IThermal1_1Service startup
- mThermalService = new android::os::ThermalService;
- mThermalService->publish(mThermalService);
- // Register IThermalService object to ThermalHAL callback
- if (mThermalCallback_2_0 != nullptr) {
- mThermalCallback_2_0->registerThermalService(mThermalService);
- } else if (mThermalCallback_1_1 != nullptr) {
- mThermalCallback_1_1->registerThermalService(mThermalService);
- }
- IPCThreadState::self()->joinThreadPool();
-}
-
-// Lookup Thermal HAL, register death notifier, register our
-// ThermalCallback with the Thermal HAL.
-void ThermalServiceDaemon::getThermalHal() {
- static sp<ThermalServiceDeathRecipient> gThermalHalDied = nullptr;
- // Binder death notifier for Thermal HAL
- if (gThermalHalDied == nullptr) {
- gThermalHalDied = new ThermalServiceDeathRecipient();
- }
-
- gThermalHal2_0 = IThermal2_0::getService();
- if (gThermalHal2_0 == nullptr) {
- SLOGW("Unable to get Thermal HAL V2.0, fallback to 1.1");
- gThermalHal1_1 = IThermal1_1::getService();
- if (gThermalHal1_1 == nullptr) {
- SLOGW("Unable to get Thermal HAL V1.1, vendor thermal event "
- "notification not available");
- return;
- }
- if (gThermalHalDied != nullptr) {
- gThermalHal1_1->linkToDeath(gThermalHalDied, 0x451F /* cookie */);
- }
-
- if (mThermalCallback_1_1 != nullptr) {
- Return<void> ret = gThermalHal1_1->registerThermalCallback(mThermalCallback_1_1);
- if (!ret.isOk()) {
- SLOGE("registerThermalCallback failed, status: %s", ret.description().c_str());
- }
- }
- } else {
- if (gThermalHalDied != nullptr) {
- gThermalHal2_0->linkToDeath(gThermalHalDied, 0x451F /* cookie */);
- }
-
- if (mThermalCallback_2_0 != nullptr) {
- Return<void> ret =
- gThermalHal2_0
- ->registerThermalChangedCallback(mThermalCallback_2_0, false,
- TemperatureType::SKIN, // not used
- [](ThermalStatus status) {
- if (ThermalStatusCode::SUCCESS !=
- status.code) {
- SLOGE("registerThermalChangedC"
- "allback failed, "
- "status: %s",
- status.debugMessage
- .c_str());
- }
- });
- if (!ret.isOk()) {
- SLOGE("registerThermalChangedCallback failed, status: %s",
- ret.description().c_str());
- }
- }
- }
-}
-
-ThermalServiceDaemon::~ThermalServiceDaemon() {
- if (mThermalCallback_2_0 != nullptr && gThermalHal2_0 != nullptr) {
- Return<void> ret =
- gThermalHal2_0
- ->unregisterThermalChangedCallback(
- mThermalCallback_2_0,
- [](ThermalStatus status) {
- if (ThermalStatusCode::SUCCESS !=
- status.code) {
- SLOGE("unregisterThermalChangedCallback failed, status: %s",
- status.debugMessage
- .c_str());
- }
- });
- if (!ret.isOk()) {
- SLOGE("unregisterThermalChangedCallback failed, status: %s", ret.description().c_str());
- }
- }
-}
-
-void ThermalServiceDaemon::thermalCallbackStartup() {
- // HIDL IThermal Callback startup
- // Need at least 2 threads in thread pool since we wait for dead HAL
- // to come back on the binder death notification thread and we need
- // another thread for the incoming service now available call.
- configureRpcThreadpool(2, false /* callerWillJoin */);
- mThermalCallback_1_1 = new ThermalCallback();
- mThermalCallback_2_0 = new ThermalChangedCallback();
- // Lookup Thermal HAL 1.1 and 2.0 to register our Callback.
- getThermalHal();
-}
-
-int main(int /*argc*/, char** /*argv*/) {
- gThermalServiceDaemon = new ThermalServiceDaemon();
- gThermalServiceDaemon->thermalCallbackStartup();
- gThermalServiceDaemon->thermalServiceStartup();
- /* NOTREACHED */
-}
diff --git a/services/thermalservice/thermalserviced.h b/services/thermalservice/thermalserviced.h
deleted file mode 100644
index ff7a483..0000000
--- a/services/thermalservice/thermalserviced.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_THERMALSERVICE_THERMALSERVICED_H
-#define ANDROID_THERMALSERVICE_THERMALSERVICED_H
-
-#include "ThermalService.h"
-#include "libthermalcallback/ThermalCallback.h"
-#include "libthermalcallback/ThermalChangedCallback.h"
-
-using namespace android;
-using ::android::hardware::thermal::V1_0::Temperature;
-using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
-using ::android::hardware::thermal::V2_0::implementation::ThermalChangedCallback;
-using ::android::os::ThermalService;
-
-class ThermalServiceDaemon {
- public:
- ~ThermalServiceDaemon();
- void thermalServiceStartup();
- void thermalCallbackStartup();
- void getThermalHal();
- ThermalServiceDaemon(){};
-
- private:
- sp<ThermalService> mThermalService;
- sp<ThermalCallback> mThermalCallback_1_1;
- sp<ThermalChangedCallback> mThermalCallback_2_0;
-};
-
-#endif // ANDROID_THERMALSERVICE_THERMALSERVICED_H
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index 74b549d..5d7d4e9 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -80,27 +80,35 @@
}
void ConsumerQueueChannel::RegisterNewBuffer(
- const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) {
- ALOGD_IF(TRACE,
- "ConsumerQueueChannel::RegisterNewBuffer: queue_id=%d buffer_id=%d "
- "slot=%zu silent=%d",
- buffer_id(), producer_channel->buffer_id(), slot, silent_);
+ const std::shared_ptr<ProducerChannel>& producer_channel,
+ size_t producer_slot) {
+ ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu silent=%d",
+ __FUNCTION__, buffer_id(), producer_channel->buffer_id(),
+ producer_slot, silent_);
// Only register buffers if the queue is not silent.
- if (!silent_) {
- pending_buffer_slots_.emplace(producer_channel, slot);
-
- // Signal the client that there is new buffer available.
- SignalAvailable();
+ if (silent_) {
+ return;
}
+
+ auto status = producer_channel->CreateConsumerStateMask();
+ if (!status.ok()) {
+ ALOGE("%s: Failed to create consumer state mask: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
+ return;
+ }
+ uint64_t consumer_state_mask = status.get();
+
+ pending_buffer_slots_.emplace(producer_channel, producer_slot,
+ consumer_state_mask);
+ // Signal the client that there is new buffer available.
+ SignalAvailable();
}
Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) {
std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles;
- ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers");
- ALOGD_IF(TRACE,
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: "
- "pending_buffer_slots=%zu",
+ ATRACE_NAME(__FUNCTION__);
+ ALOGD_IF(TRACE, "%s: pending_buffer_slots=%zu", __FUNCTION__,
pending_buffer_slots_.size());
// Indicate this is a silent queue that will not import buffers.
@@ -108,30 +116,30 @@
return ErrorStatus(EBADR);
while (!pending_buffer_slots_.empty()) {
- auto producer_channel = pending_buffer_slots_.front().first.lock();
- size_t producer_slot = pending_buffer_slots_.front().second;
+ auto producer_channel =
+ pending_buffer_slots_.front().producer_channel.lock();
+ size_t producer_slot = pending_buffer_slots_.front().producer_slot;
+ uint64_t consumer_state_mask =
+ pending_buffer_slots_.front().consumer_state_mask;
pending_buffer_slots_.pop();
// It's possible that the producer channel has expired. When this occurs,
// ignore the producer channel.
if (producer_channel == nullptr) {
- ALOGW(
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: producer "
- "channel has already been expired.");
+ ALOGW("%s: producer channel has already been expired.", __FUNCTION__);
continue;
}
- auto status = producer_channel->CreateConsumer(message);
+ auto status =
+ producer_channel->CreateConsumer(message, consumer_state_mask);
// If no buffers are imported successfully, clear available and return an
// error. Otherwise, return all consumer handles already imported
// successfully, but keep available bits on, so that the client can retry
// importing remaining consumer buffers.
if (!status) {
- ALOGE(
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: Failed create "
- "consumer: %s",
- status.GetErrorMessage().c_str());
+ ALOGE("%s: Failed create consumer: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
if (buffer_handles.empty()) {
ClearAvailable();
return status.error_status();
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
index 8f35437..3a81b03 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
@@ -3,8 +3,8 @@
#include <queue>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_queue_channel.h>
@@ -28,7 +28,8 @@
// Called by ProdcuerQueueChannel to notify consumer queue that a new
// buffer has been allocated.
void RegisterNewBuffer(
- const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot);
+ const std::shared_ptr<ProducerChannel>& producer_channel,
+ size_t producer_slot);
// Called after clients been signaled by service that new buffer has been
// allocated. Clients uses kOpConsumerQueueImportBuffers to import new
@@ -40,14 +41,29 @@
void OnProducerClosed();
private:
+ // Data structure to store relavant info of a newly allocated producer buffer
+ // so that consumer channel and buffer can be created later.
+ struct PendingBuffer {
+ PendingBuffer(std::shared_ptr<ProducerChannel> channel, size_t slot,
+ uint64_t mask) {
+ producer_channel = channel;
+ producer_slot = slot;
+ consumer_state_mask = mask;
+ }
+ PendingBuffer() = delete;
+
+ std::weak_ptr<ProducerChannel> producer_channel;
+ size_t producer_slot;
+ uint64_t consumer_state_mask;
+ };
+
std::shared_ptr<ProducerQueueChannel> GetProducer() const;
// Pointer to the producer channel.
std::weak_ptr<Channel> producer_;
// Tracks newly allocated buffer producers along with it's slot number.
- std::queue<std::pair<std::weak_ptr<ProducerChannel>, size_t>>
- pending_buffer_slots_;
+ std::queue<PendingBuffer> pending_buffer_slots_;
// Tracks how many buffers have this queue imported.
size_t capacity_;
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 5868b09..3ad9c70 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -53,7 +53,9 @@
BufferDescription<BorrowedHandle> GetBuffer(uint64_t client_state_mask);
- pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message);
+ pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message,
+ uint64_t consumer_state_mask);
+ pdx::Status<uint64_t> CreateConsumerStateMask();
pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message);
pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
@@ -93,7 +95,7 @@
LocalFence post_fence_;
LocalFence returned_fence_;
size_t user_metadata_size_; // size of user requested buffer buffer size.
- size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
+ size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
pdx::LocalHandle acquire_fence_fd_;
pdx::LocalHandle release_fence_fd_;
@@ -111,6 +113,10 @@
pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
pdx::Status<LocalFence> OnProducerGain(Message& message);
+ // Remove consumer from atomics in shared memory based on consumer_state_mask.
+ // This function is used for clean up for failures in CreateConsumer method.
+ void RemoveConsumerClientMask(uint64_t consumer_state_mask);
+
ProducerChannel(const ProducerChannel&) = delete;
void operator=(const ProducerChannel&) = delete;
};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 397c0ae..c6e8ea9 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -248,21 +248,7 @@
return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
}
-Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
- ATRACE_NAME("ProducerChannel::CreateConsumer");
- ALOGD_IF(TRACE,
- "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
- buffer_id(), producer_owns_);
-
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status) {
- ALOGE(
- "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
+Status<uint64_t> ProducerChannel::CreateConsumerStateMask() {
// Try find the next consumer state bit which has not been claimed by any
// consumer yet.
// memory_order_acquire is chosen here because all writes in other threads
@@ -277,7 +263,6 @@
"consumers per producer: 63.");
return ErrorStatus(E2BIG);
}
-
uint64_t updated_active_clients_bit_mask =
current_active_clients_bit_mask | client_state_mask;
// Set the updated value only if the current value stays the same as what was
@@ -286,28 +271,71 @@
// thread, and the modification will be visible in other threads that acquire
// active_clients_bit_mask_. If the comparison fails, load the result of
// all writes from all threads to updated_active_clients_bit_mask.
- if (!active_clients_bit_mask_->compare_exchange_weak(
- current_active_clients_bit_mask, updated_active_clients_bit_mask,
- std::memory_order_acq_rel, std::memory_order_acquire)) {
+ // Keep on finding the next available slient state mask until succeed or out
+ // of memory.
+ while (!active_clients_bit_mask_->compare_exchange_weak(
+ current_active_clients_bit_mask, updated_active_clients_bit_mask,
+ std::memory_order_acq_rel, std::memory_order_acquire)) {
ALOGE("Current active clients bit mask is changed to %" PRIx64
- ", which was expected to be %" PRIx64 ".",
+ ", which was expected to be %" PRIx64
+ ". Trying to generate a new client state mask to resolve race "
+ "condition.",
updated_active_clients_bit_mask, current_active_clients_bit_mask);
- return ErrorStatus(EBUSY);
+ client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+ current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
+ if (client_state_mask == 0ULL) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+ "consumers per producer: 63.");
+ return ErrorStatus(E2BIG);
+ }
+ updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | client_state_mask;
}
- auto consumer =
- std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
- client_state_mask, shared_from_this());
+ return {client_state_mask};
+}
+
+void ProducerChannel::RemoveConsumerClientMask(uint64_t consumer_state_mask) {
+ // Clear up the buffer state and fence state in case there is already
+ // something there due to possible race condition between producer post and
+ // consumer failed to create channel.
+ buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+ fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+
+ // Restore the consumer state bit and make it visible in other threads that
+ // acquire the active_clients_bit_mask_.
+ active_clients_bit_mask_->fetch_and(~consumer_state_mask,
+ std::memory_order_release);
+}
+
+Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(
+ Message& message, uint64_t consumer_state_mask) {
+ ATRACE_NAME("ProducerChannel::CreateConsumer");
+ ALOGD_IF(TRACE,
+ "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
+ buffer_id(), producer_owns_);
+
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
+ status.GetErrorMessage().c_str());
+ RemoveConsumerClientMask(consumer_state_mask);
+ return ErrorStatus(ENOMEM);
+ }
+
+ auto consumer = std::make_shared<ConsumerChannel>(
+ service(), buffer_id(), channel_id, consumer_state_mask,
+ shared_from_this());
const auto channel_status = service()->SetChannel(channel_id, consumer);
if (!channel_status) {
ALOGE(
"ProducerChannel::CreateConsumer: failed to set new consumer channel: "
"%s",
channel_status.GetErrorMessage().c_str());
- // Restore the consumer state bit and make it visible in other threads that
- // acquire the active_clients_bit_mask_.
- active_clients_bit_mask_->fetch_and(~client_state_mask,
- std::memory_order_release);
+ RemoveConsumerClientMask(consumer_state_mask);
return ErrorStatus(ENOMEM);
}
@@ -327,7 +355,11 @@
Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
ATRACE_NAME("ProducerChannel::OnNewConsumer");
ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
- return CreateConsumer(message);
+ auto status = CreateConsumerStateMask();
+ if (!status.ok()) {
+ return status.error_status();
+ }
+ return CreateConsumer(message, /*consumer_state_mask=*/status.get());
}
Status<void> ProducerChannel::OnProducerPost(Message&,
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 003775b..258b45b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -55,7 +55,6 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
"-Wall",
"-Werror",
- // mVrClient unused in vr_composer_client.cpp
"-Wno-error=unused-private-field",
// Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
"-Wno-sign-compare",
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 4b90031..786d5fa 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -19,6 +19,8 @@
#include <hardware/gralloc1.h>
#include <log/log.h>
+#include <memory>
+
#include "impl/vr_hwc.h"
#include "impl/vr_composer_client.h"
@@ -39,11 +41,11 @@
std::unique_ptr<ComposerCommandEngine>
VrComposerClient::createCommandEngine() {
- return std::unique_ptr<VrCommandEngine>(new VrCommandEngine(*this));
+ return std::make_unique<VrCommandEngine>(*this);
}
VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
- : ComposerCommandEngine(client.mHal, client.mResources.get()), mVrClient(client),
+ : ComposerCommandEngine(client.mHal, client.mResources.get()),
mVrHal(client.mVrHal) {}
VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 76b1c4f..de22640 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -54,7 +54,6 @@
IVrComposerClient::BufferMetadata readBufferMetadata();
- VrComposerClient& mVrClient;
android::dvr::VrHwc& mVrHal;
VrCommandEngine(const VrCommandEngine&) = delete;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 4065785..a24c889 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -12,16 +12,16 @@
#include <thread>
#include <utility>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include "stdio_filebuf.h"
-#include "string_trim.h"
#include "unique_file.h"
-using android::dvr::Trim;
+using android::base::Trim;
using android::dvr::UniqueFile;
using android::dvr::stdio_filebuf;
diff --git a/services/vr/performanced/string_trim.h b/services/vr/performanced/string_trim.h
deleted file mode 100644
index 7094e9f..0000000
--- a/services/vr/performanced/string_trim.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-#define ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-
-#include <functional>
-#include <locale>
-#include <string>
-
-namespace android {
-namespace dvr {
-
-// Trims whitespace from the left side of |subject| and returns the result as a
-// new string.
-inline std::string LeftTrim(std::string subject) {
- subject.erase(subject.begin(),
- std::find_if(subject.begin(), subject.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
- return subject;
-}
-
-// Trims whitespace from the right side of |subject| and returns the result as a
-// new string.
-inline std::string RightTrim(std::string subject) {
- subject.erase(std::find_if(subject.rbegin(), subject.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace)))
- .base(),
- subject.end());
- return subject;
-}
-
-// Trims whitespace from the both sides of |subject| and returns the result as a
-// new string.
-inline std::string Trim(std::string subject) {
- subject.erase(subject.begin(),
- std::find_if(subject.begin(), subject.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
- subject.erase(std::find_if(subject.rbegin(), subject.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace)))
- .base(),
- subject.end());
- return subject;
-}
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index bda1682..2fc96bf 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -10,10 +10,10 @@
#include <memory>
#include <sstream>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include "stdio_filebuf.h"
-#include "string_trim.h"
namespace {
@@ -102,7 +102,7 @@
// The status file has lines with the format <field>:<value>. Extract the
// value after the colon.
- return Trim(line.substr(offset + field.size() + 1));
+ return android::base::Trim(line.substr(offset + field.size() + 1));
}
}
@@ -123,7 +123,7 @@
}
std::string key = line.substr(0, offset);
- std::string value = Trim(line.substr(offset + 1));
+ std::string value = android::base::Trim(line.substr(offset + 1));
ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"",
key.c_str(), value.c_str());
@@ -156,7 +156,7 @@
std::string line = "";
std::getline(file_stream, line);
- return Trim(line);
+ return android::base::Trim(line);
} else {
return "";
}