diff options
152 files changed, 2465 insertions, 3309 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 032d0726e0..f1426b6bd0 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -47,6 +47,8 @@ on late-init chmod 0666 /sys/kernel/tracing/events/power/clock_set_rate/enable chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable + chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable + chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable chmod 0666 /sys/kernel/tracing/events/cpufreq_interactive/enable chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index ee32cb4495..4020480479 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -123,7 +123,6 @@ cc_binary { "lsmod", "lsof", "netstat", - "parse_radio_log", "printenv", "procrank", "screencap", @@ -146,6 +145,8 @@ cc_test { "tests/dumpstate_test.cpp", ], static_libs: ["libgmock"], + test_config: "dumpstate_test.xml", + data: [":dumpstate_test_fixture", "tests/testdata/**/*"] } cc_test { diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md index c818c05117..26dabbbcef 100644 --- a/cmds/dumpstate/README.md +++ b/cmds/dumpstate/README.md @@ -92,6 +92,12 @@ Then to restore the default version: adb shell setprop dumpstate.version default ``` +## To set Bugreport API workflow for bugreport + +``` +adb shell setprop settings_call_bugreport_api true +``` + ## Code style and formatting Use the style defined at the diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 8ba95266b6..cc745708c8 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1316,8 +1316,6 @@ static Dumpstate::RunStatus dumpstate() { RunCommand("FILESYSTEMS & FREE SPACE", {"df"}); - RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"}); - /* Binder state is expensive to look at as it uses a lot of memory. */ DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log"); DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log"); @@ -1796,22 +1794,21 @@ void Dumpstate::DumpstateBoard() { static void ShowUsage() { fprintf(stderr, - "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] " + "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] " "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" " -h: display this help message\n" " -b: play sound file instead of vibrate, at beginning of job\n" " -e: play sound file instead of vibrate, at end of job\n" - " -o: write to file (instead of stdout)\n" - " -d: append date to filename (requires -o)\n" - " -p: capture screenshot to filename.png (requires -o)\n" - " -z: generate zipped file (requires -o)\n" + " -d: append date to filename\n" + " -p: capture screenshot to filename.png\n" + " -z: generate zipped file\n" " -s: write output to control socket (for init)\n" - " -S: write file location to control socket (for init; requires -o and -z)\n" + " -S: write file location to control socket (for init; requires -z)\n" " -q: disable vibrate\n" - " -B: send broadcast when finished (requires -o)\n" + " -B: send broadcast when finished\n" " -P: send broadcast when started and update system properties on " - "progress (requires -o and -B)\n" - " -R: take bugreport in remote mode (requires -o, -z, -d and -B, " + "progress (requires -B)\n" + " -R: take bugreport in remote mode (requires -z, -d and -B, " "shouldn't be used with -P)\n" " -w: start binder service and make it wait for a call to startBugreport\n" " -v: prints the dumpstate header and exit\n"); @@ -2295,7 +2292,6 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) } } - // TODO: use helper function to convert argv into a string for (int i = 0; i < argc; i++) { args += argv[i]; if (i < argc - 1) { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index d02ec759a7..ae6a72171a 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -441,8 +441,7 @@ class Dumpstate { // Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_. std::string path_; - // TODO: If temporary this should be removed at the end. - // Full path of the temporary file containing the screenshot (when requested). + // Full path of the file containing the screenshot (when requested). std::string screenshot_path_; // Pointer to the zipped file. diff --git a/cmds/dumpstate/dumpstate_test.xml b/cmds/dumpstate/dumpstate_test.xml new file mode 100644 index 0000000000..e4e4a30a1e --- /dev/null +++ b/cmds/dumpstate/dumpstate_test.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 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. +--> +<configuration description="Config for dumpstate_test"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="dumpstate_test->/data/local/tmp/dumpstate_test" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="file-exclusion-filter-regex" value=".*/dumpstate_test_fixture" /> + <option name="file-exclusion-filter-regex" value=".*/tests/.*" /> + <option name="module-name" value="dumpstate_test" /> + </test> +</configuration> diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index c5d01fdf25..0e88e43258 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -105,9 +105,8 @@ class DumpstateBaseTest : public Test { protected: const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str()); - const std::string kFixturesPath = kTestPath + "/../dumpstate_test_fixture/"; - const std::string kTestDataPath = kFixturesPath + "tests/testdata/"; - const std::string kSimpleCommand = kFixturesPath + "dumpstate_test_fixture"; + const std::string kTestDataPath = kTestPath + "/tests/testdata/"; + const std::string kSimpleCommand = kTestPath + "/dumpstate_test_fixture"; const std::string kEchoCommand = "/system/bin/echo"; /* diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp index 0bb80dcfba..4cbf5776d3 100644 --- a/cmds/dumpstate/utils.cpp +++ b/cmds/dumpstate/utils.cpp @@ -733,6 +733,11 @@ int open_socket(const char *service) { struct sockaddr addr; socklen_t alen = sizeof(addr); int fd = accept(s, &addr, &alen); + + // Close socket just after accept(), to make sure that connect() by client will get error + // when the socket is used by the other services. + close(s); + if (fd < 0) { MYLOGE("accept(control socket): %s\n", strerror(errno)); return -1; diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index 654213f5e0..064a268d2e 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -151,6 +151,7 @@ cc_binary { shared_libs: [ "libbase", "libbinder", + "libcrypto", "liblog", "libprotobuf-cpp-full", "libselinux", @@ -163,6 +164,7 @@ cc_binary { "lib_apex_manifest_proto", "libavb", "libdm", + "libverity_tree", "libvold_binder", ], } diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index caac2e89a7..dd51898422 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -2107,10 +2107,15 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t CHECK_ARGUMENT_PATH(dexMetadataPath); std::lock_guard<std::recursive_mutex> lock(mLock); + const char* oat_dir = getCStr(outputPath); + const char* instruction_set = instructionSet.c_str(); + if (oat_dir != nullptr && !createOatDir(oat_dir, instruction_set).isOk()) { + // Can't create oat dir - let dexopt use cache dir. + oat_dir = nullptr; + } + const char* apk_path = apkPath.c_str(); const char* pkgname = getCStr(packageName, "*"); - const char* instruction_set = instructionSet.c_str(); - const char* oat_dir = getCStr(outputPath); const char* compiler_filter = compilerFilter.c_str(); const char* volume_uuid = getCStr(uuid); const char* class_loader_context = getCStr(classLoaderContext); diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS index 56739181bb..9a21104131 100644 --- a/cmds/installd/OWNERS +++ b/cmds/installd/OWNERS @@ -4,7 +4,9 @@ agampe@google.com calin@google.com jsharkey@android.com maco@google.com +mast@google.com mathieuc@google.com narayan@google.com ngeoffray@google.com +rpl@google.com toddke@google.com diff --git a/cmds/installd/art_helper/Android.bp b/cmds/installd/art_helper/Android.bp deleted file mode 100644 index c47dd722f9..0000000000 --- a/cmds/installd/art_helper/Android.bp +++ /dev/null @@ -1,12 +0,0 @@ -// Inherit image values. -art_global_defaults { - name: "libartimagevalues_defaults", -} - -cc_library_static { - name: "libartimagevalues", - defaults: ["libartimagevalues_defaults"], - srcs: ["art_image_values.cpp"], - export_include_dirs: ["."], - cflags: ["-Wconversion"], -} diff --git a/cmds/installd/art_helper/art_image_values.cpp b/cmds/installd/art_helper/art_image_values.cpp deleted file mode 100644 index a139049d9f..0000000000 --- a/cmds/installd/art_helper/art_image_values.cpp +++ /dev/null @@ -1,37 +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. - */ - -#include "art_image_values.h" - -namespace android { -namespace installd { -namespace art { - -uint32_t GetImageBaseAddress() { - return ART_BASE_ADDRESS; -} -int32_t GetImageMinBaseAddressDelta() { - return ART_BASE_ADDRESS_MIN_DELTA; -} -int32_t GetImageMaxBaseAddressDelta() { - return ART_BASE_ADDRESS_MAX_DELTA; -} - -static_assert(ART_BASE_ADDRESS_MIN_DELTA < ART_BASE_ADDRESS_MAX_DELTA, "Inconsistent setup"); - -} // namespace art -} // namespace installd -} // namespace android diff --git a/cmds/installd/art_helper/art_image_values.h b/cmds/installd/art_helper/art_image_values.h deleted file mode 100644 index 20c44c953f..0000000000 --- a/cmds/installd/art_helper/art_image_values.h +++ /dev/null @@ -1,34 +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 FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H -#define FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H - -#include <cstdint> - -namespace android { -namespace installd { -namespace art { - -uint32_t GetImageBaseAddress(); -int32_t GetImageMinBaseAddressDelta(); -int32_t GetImageMaxBaseAddressDelta(); - -} // namespace art -} // namespace installd -} // namespace android - -#endif // FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 26e9984f11..d99bcc8d13 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -127,4 +127,6 @@ interface IInstalld { const int FLAG_USE_QUOTA = 0x1000; const int FLAG_FORCE = 0x2000; + + const int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 0x20000; } diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index de7b2499b8..db36ce3c9e 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -445,9 +445,11 @@ private: } cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str())); - int32_t base_offset = ChooseRelocationOffsetDelta(art::GetImageMinBaseAddressDelta(), - art::GetImageMaxBaseAddressDelta()); - cmd.push_back(StringPrintf("--base=0x%x", art::GetImageBaseAddress() + base_offset)); + int32_t base_offset = ChooseRelocationOffsetDelta( + art::imagevalues::GetImageMinBaseAddressDelta(), + art::imagevalues::GetImageMaxBaseAddressDelta()); + cmd.push_back(StringPrintf("--base=0x%x", + art::imagevalues::GetImageBaseAddress() + base_offset)); cmd.push_back(StringPrintf("--instruction-set=%s", isa)); @@ -464,7 +466,7 @@ private: "--compiler-filter=", false, cmd); - cmd.push_back("--image-classes=/system/etc/preloaded-classes"); + cmd.push_back("--profile-file=/system/etc/boot-image.prof"); // TODO: Compiled-classes. const std::string* extra_opts = system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags"); diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index 2e2cc182ec..0c4badf489 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -64,16 +64,18 @@ static std::vector<apex::ApexFile> ActivateApexPackages() { // system/apex/apexd/apexd_main.cpp. // // Only scan the APEX directory under /system (within the chroot dir). - apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir); + // Cast call to void to suppress warn_unused_result. + static_cast<void>(apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir)); return apex::getActivePackages(); } static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) { for (const apex::ApexFile& apex_file : active_packages) { const std::string& package_path = apex_file.GetPath(); - apex::Status status = apex::deactivatePackage(package_path); - if (!status.Ok()) { - LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage(); + base::Result<void> status = apex::deactivatePackage(package_path); + if (!status) { + LOG(ERROR) << "Failed to deactivate " << package_path << ": " + << status.error(); } } } diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index 13fd0677e5..73780eccbf 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -241,18 +241,14 @@ protected: } ::testing::AssertionResult create_mock_app() { - // Create the oat dir. - app_oat_dir_ = app_apk_dir_ + "/oat"; // For debug mode, the directory might already exist. Avoid erroring out. if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0 && !kDebug) { return ::testing::AssertionFailure() << "Could not create app dir " << app_apk_dir_ << " : " << strerror(errno); } - binder::Status status = service_->createOatDir(app_oat_dir_, kRuntimeIsa); - if (!status.isOk()) { - return ::testing::AssertionFailure() << "Could not create oat dir: " - << status.toString8().c_str(); - } + + // Initialize the oat dir path. + app_oat_dir_ = app_apk_dir_ + "/oat"; // Copy the primary apk. apk_path_ = app_apk_dir_ + "/base.jar"; @@ -283,7 +279,7 @@ protected: } // Create the app user data. - status = service_->createAppData( + binder::Status status = service_->createAppData( volume_uuid_, package_name_, kTestUserId, @@ -647,6 +643,16 @@ TEST_F(DexoptTest, DexoptPrimaryPublic) { DEX2OAT_FROM_SCRATCH); } +TEST_F(DexoptTest, DexoptPrimaryPublicCreateOatDir) { + LOG(INFO) << "DexoptPrimaryPublic"; + ASSERT_BINDER_SUCCESS(service_->createOatDir(app_oat_dir_, kRuntimeIsa)); + CompilePrimaryDexOk("verify", + DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, + app_oat_dir_.c_str(), + kTestAppGid, + DEX2OAT_FROM_SCRATCH); +} + TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) { LOG(INFO) << "DexoptPrimaryFailedInvalidFilter"; binder::Status status; diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp index 93d878b607..f7dd8c82c3 100644 --- a/cmds/lshal/Android.bp +++ b/cmds/lshal/Android.bp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_library_shared { +cc_library_static { name: "liblshal", shared_libs: [ "libbase", @@ -47,13 +47,16 @@ cc_defaults { name: "lshal_defaults", shared_libs: [ "libbase", + "libcutils", + "libutils", "libhidlbase", - "libhidl-gen-utils", "libhidltransport", - "liblshal", - "libutils", + "libhidl-gen-hash", + "libhidl-gen-utils", + "libvintf", ], static_libs: [ + "liblshal", "libprocpartition", ], cflags: ["-Wall", "-Werror"], diff --git a/cmds/lshal/Command.h b/cmds/lshal/Command.h index e19e3f7fc2..84809d9a5d 100644 --- a/cmds/lshal/Command.h +++ b/cmds/lshal/Command.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_ +#pragma once #include "utils.h" @@ -48,5 +47,3 @@ protected: } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_ diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp index 0952db6e72..af22ac9b3d 100644 --- a/cmds/lshal/DebugCommand.cpp +++ b/cmds/lshal/DebugCommand.cpp @@ -79,7 +79,7 @@ void DebugCommand::usage() const { " lshal debug [-E] <interface> [options [options [...]]] \n" " Print debug information of a specified interface.\n" " -E: excludes debug output if HAL is actually a subclass.\n" - " <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n" + " <interface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n" " If instance name is missing `default` is used.\n" " options: space separated options to IBase::debug.\n"; @@ -88,4 +88,3 @@ void DebugCommand::usage() const { } // namespace lshal } // namespace android - diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h index 3c3f56fde5..cd57e31bfc 100644 --- a/cmds/lshal/DebugCommand.h +++ b/cmds/lshal/DebugCommand.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_ +#pragma once #include <string> @@ -53,5 +52,3 @@ private: } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_ diff --git a/cmds/lshal/HelpCommand.h b/cmds/lshal/HelpCommand.h index da0cba6f42..bfa850075d 100644 --- a/cmds/lshal/HelpCommand.h +++ b/cmds/lshal/HelpCommand.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_ +#pragma once #include <string> @@ -44,5 +43,3 @@ public: } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_ diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h index 85195fcc54..b3ed23d1fc 100644 --- a/cmds/lshal/ListCommand.h +++ b/cmds/lshal/ListCommand.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_ +#pragma once #include <getopt.h> #include <stdint.h> @@ -206,5 +205,3 @@ private: } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_ diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h index 9457f1e563..2679650611 100644 --- a/cmds/lshal/Lshal.h +++ b/cmds/lshal/Lshal.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_ +#pragma once #include <iostream> #include <string> @@ -76,5 +75,3 @@ private: } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_ diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h index 737d3a2963..7cffcf8193 100644 --- a/cmds/lshal/NullableOStream.h +++ b/cmds/lshal/NullableOStream.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ +#pragma once #include <iostream> @@ -69,5 +68,3 @@ private: } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h index 8dc3093742..8350160419 100644 --- a/cmds/lshal/PipeRelay.h +++ b/cmds/lshal/PipeRelay.h @@ -14,9 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_ - -#define FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_ +#pragma once #include <android-base/macros.h> #include <ostream> @@ -53,6 +51,3 @@ private: } // namespace lshal } // namespace android - -#endif // FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_ - diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h index 601b7e25f9..0ff0c96d38 100644 --- a/cmds/lshal/TableEntry.h +++ b/cmds/lshal/TableEntry.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_ +#pragma once #include <stdint.h> @@ -157,5 +156,3 @@ private: } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_ diff --git a/cmds/lshal/TextTable.h b/cmds/lshal/TextTable.h index 301b4bd969..be41a08251 100644 --- a/cmds/lshal/TextTable.h +++ b/cmds/lshal/TextTable.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_ +#pragma once #include <iostream> #include <string> @@ -80,5 +79,3 @@ private: } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_ diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h index 46d817759d..e8d22d9b58 100644 --- a/cmds/lshal/Timeout.h +++ b/cmds/lshal/Timeout.h @@ -14,6 +14,8 @@ * limitations under the License. */ +#pragma once + #include <condition_variable> #include <chrono> #include <functional> diff --git a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h index 7e864327af..ca1e690694 100644 --- a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h +++ b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_ +#pragma once #include <sys/types.h> @@ -44,5 +43,3 @@ Partition getPartition(pid_t pid); } // namespace procpartition } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_ diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h index 240155e4d0..04f52726e3 100644 --- a/cmds/lshal/utils.h +++ b/cmds/lshal/utils.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_ -#define FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_ +#pragma once #include <iomanip> #include <iostream> @@ -88,5 +87,3 @@ void replaceAll(std::string *s, char from, char to); } // namespace lshal } // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_ diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp new file mode 100644 index 0000000000..f4005c4dee --- /dev/null +++ b/cmds/servicemanager/Access.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 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 "Access.h" + +#include <android-base/logging.h> +#include <binder/IPCThreadState.h> +#include <log/log_safetynet.h> +#include <selinux/android.h> +#include <selinux/avc.h> + +namespace android { + +#ifdef VENDORSERVICEMANAGER +constexpr bool kIsVendor = true; +#else +constexpr bool kIsVendor = false; +#endif + +static std::string getPidcon(pid_t pid) { + android_errorWriteLog(0x534e4554, "121035042"); + + char* lookup = nullptr; + if (getpidcon(pid, &lookup) < 0) { + LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context"; + return ""; + } + std::string result = lookup; + freecon(lookup); + return result; +} + +static struct selabel_handle* getSehandle() { + static struct selabel_handle* gSehandle = nullptr; + + if (gSehandle != nullptr && selinux_status_updated()) { + selabel_close(gSehandle); + gSehandle = nullptr; + } + + if (gSehandle == nullptr) { + gSehandle = kIsVendor + ? selinux_android_vendor_service_context_handle() + : selinux_android_service_context_handle(); + } + + CHECK(gSehandle != nullptr); + return gSehandle; +} + +static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) { + const Access::CallingContext* ad = reinterpret_cast<Access::CallingContext*>(data); + + if (!ad) { + LOG(ERROR) << "No service manager audit data"; + return 0; + } + + snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name.c_str(), ad->debugPid, ad->uid); + return 0; +} + +Access::Access() { + union selinux_callback cb; + + cb.func_audit = auditCallback; + selinux_set_callback(SELINUX_CB_AUDIT, cb); + + cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); + + CHECK(selinux_status_open(true /*fallback*/) >= 0); + + CHECK(getcon(&mThisProcessContext) == 0); +} + +Access::~Access() { + freecon(mThisProcessContext); +} + +Access::CallingContext Access::getCallingContext(const std::string& name) { + IPCThreadState* ipc = IPCThreadState::self(); + + const char* callingSid = ipc->getCallingSid(); + pid_t callingPid = ipc->getCallingPid(); + + return CallingContext { + .debugPid = callingPid, + .uid = ipc->getCallingUid(), + .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid), + .name = name, + }; +} + +bool Access::canFind(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "find"); +} + +bool Access::canAdd(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "add"); +} + +bool Access::canList(const CallingContext& ctx) { + CHECK(ctx.name == ""); + + return actionAllowed(ctx, mThisProcessContext, "list"); +} + +bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) { + const char* tclass = "service_manager"; + + return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(const_cast<CallingContext*>((&sctx)))); +} + +bool Access::actionAllowedFromLookup(const CallingContext& sctx, const char *perm) { + char *tctx = nullptr; + if (selabel_lookup(getSehandle(), &tctx, sctx.name.c_str(), 0) != 0) { + LOG(ERROR) << "SELinux: No match for " << sctx.name << " in service_contexts.\n"; + return false; + } + + bool allowed = actionAllowed(sctx, tctx, perm); + freecon(tctx); + return allowed; +} + +} // android diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h new file mode 100644 index 0000000000..b2c78cc34d --- /dev/null +++ b/cmds/servicemanager/Access.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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 <string> +#include <sys/types.h> + +namespace android { + +// singleton +class Access { +public: + Access(); + virtual ~Access(); + + Access(const Access&) = delete; + Access& operator=(const Access&) = delete; + Access(Access&&) = delete; + Access& operator=(Access&&) = delete; + + struct CallingContext { + pid_t debugPid; + uid_t uid; + std::string sid; + + // name of the service + // + // empty if call is unrelated to service (e.g. list) + std::string name; + }; + + virtual CallingContext getCallingContext(const std::string& name); + + virtual bool canFind(const CallingContext& ctx); + virtual bool canAdd(const CallingContext& ctx); + virtual bool canList(const CallingContext& ctx); + +private: + bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm); + bool actionAllowedFromLookup(const CallingContext& sctx, const char *perm); + + char* mThisProcessContext = nullptr; +}; + +}; diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 428561bc8a..9cf3c5c134 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -1,51 +1,51 @@ cc_defaults { - name: "servicemanager_flags", + name: "servicemanager_defaults", cflags: [ "-Wall", "-Wextra", "-Werror", ], - product_variables: { - binder32bit: { - cflags: ["-DBINDER_IPC_32BIT=1"], - }, - }, - shared_libs: ["liblog"], -} - -cc_binary { - name: "bctest", - defaults: ["servicemanager_flags"], srcs: [ - "bctest.c", - "binder.c", + "Access.cpp", + "ServiceManager.cpp", + ], + + shared_libs: [ + "libbase", + "libbinder", // also contains servicemanager_interface + "libcutils", + "liblog", + "libutils", + "libselinux", ], } cc_binary { name: "servicemanager", - defaults: ["servicemanager_flags"], - srcs: [ - "service_manager.c", - "binder.c", - ], - shared_libs: ["libcutils", "libselinux"], + defaults: ["servicemanager_defaults"], init_rc: ["servicemanager.rc"], + srcs: ["main.cpp"], } cc_binary { name: "vndservicemanager", - defaults: ["servicemanager_flags"], + defaults: ["servicemanager_defaults"], + init_rc: ["vndservicemanager.rc"], vendor: true, - srcs: [ - "service_manager.c", - "binder.c", - ], cflags: [ "-DVENDORSERVICEMANAGER=1", ], - shared_libs: ["libcutils", "libselinux"], - init_rc: ["vndservicemanager.rc"], + srcs: ["main.cpp"], +} + +cc_test { + name: "servicemanager_test", + test_suites: ["device-tests"], + defaults: ["servicemanager_defaults"], + srcs: [ + "test_sm.cpp", + ], + static_libs: ["libgmock"], } diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp new file mode 100644 index 0000000000..b88b67d138 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2019 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 "ServiceManager.h" + +#include <android-base/logging.h> +#include <cutils/android_filesystem_config.h> +#include <cutils/multiuser.h> + +using ::android::binder::Status; + +namespace android { + +ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {} + +Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) { + // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons. + return checkService(name, outBinder); +} + +Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) { + auto ctx = mAccess->getCallingContext(name); + + auto it = mNameToService.find(name); + if (it == mNameToService.end()) { + *outBinder = nullptr; + return Status::ok(); + } + + const Service& service = it->second; + + if (!service.allowIsolated) { + uid_t appid = multiuser_get_app_id(ctx.uid); + bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; + + if (isIsolated) { + *outBinder = nullptr; + return Status::ok(); + } + } + + // TODO(b/136023468): move this check to be first + if (!mAccess->canFind(ctx)) { + // returns ok and null for legacy reasons + *outBinder = nullptr; + return Status::ok(); + } + + *outBinder = service.binder; + return Status::ok(); +} + +Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) { + auto ctx = mAccess->getCallingContext(name); + + // apps cannot add services + if (multiuser_get_app_id(ctx.uid) >= AID_APP) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (!mAccess->canAdd(ctx)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (binder == nullptr) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + // match legacy rules + if (name.size() == 0 || name.size() > 127) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + if (OK != binder->linkToDeath(this)) { + LOG(ERROR) << "Could not linkToDeath when adding " << name; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + auto it = mNameToService.find(name); + if (it != mNameToService.end()) { + if (OK != it->second.binder->unlinkToDeath(this)) { + LOG(WARNING) << "Could not unlinkToDeath when adding " << name; + } + } + + mNameToService[name] = Service { + .binder = binder, + .allowIsolated = allowIsolated, + .dumpPriority = dumpPriority, + }; + + return Status::ok(); +} + +Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) { + if (!mAccess->canList(mAccess->getCallingContext(""))) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + size_t toReserve = 0; + for (auto const& [name, service] : mNameToService) { + (void) name; + + if (service.dumpPriority & dumpPriority) ++toReserve; + } + + CHECK(outList->empty()); + + outList->reserve(toReserve); + for (auto const& [name, service] : mNameToService) { + (void) service; + + if (service.dumpPriority & dumpPriority) { + outList->push_back(name); + } + } + + return Status::ok(); +} + +void ServiceManager::binderDied(const wp<IBinder>& who) { + for (auto it = mNameToService.begin(); it != mNameToService.end();) { + if (who == it->second.binder) { + it = mNameToService.erase(it); + } else { + ++it; + } + } +} + +} // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h new file mode 100644 index 0000000000..78e48052b8 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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 <android/os/BnServiceManager.h> + +#include "Access.h" + +namespace android { + +class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { +public: + ServiceManager(std::unique_ptr<Access>&& access); + + binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override; + binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override; + binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override; + binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override; + + void binderDied(const wp<IBinder>& who) override; + +private: + struct Service { + sp<IBinder> binder; + bool allowIsolated; + int32_t dumpPriority; + }; + + std::map<std::string, Service> mNameToService; + std::unique_ptr<Access> mAccess; +}; + +} // namespace android diff --git a/cmds/servicemanager/TEST_MAPPING b/cmds/servicemanager/TEST_MAPPING new file mode 100644 index 0000000000..3e47269fe0 --- /dev/null +++ b/cmds/servicemanager/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "servicemanager_test" + } + ] +} diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c deleted file mode 100644 index 354df670e5..0000000000 --- a/cmds/servicemanager/bctest.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "binder.h" - -uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) -{ - uint32_t handle; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) - return 0; - - handle = bio_get_ref(&reply); - - if (handle) - binder_acquire(bs, handle); - - binder_done(bs, &msg, &reply); - - return handle; -} - -int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) -{ - int status; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - bio_put_obj(&msg, ptr); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) - return -1; - - status = bio_get_uint32(&reply); - - binder_done(bs, &msg, &reply); - - return status; -} - -unsigned token; - -int main(int argc, char **argv) -{ - struct binder_state *bs; - uint32_t svcmgr = BINDER_SERVICE_MANAGER; - uint32_t handle; - - bs = binder_open("/dev/binder", 128*1024); - if (!bs) { - fprintf(stderr, "failed to open binder driver\n"); - return -1; - } - - argc--; - argv++; - while (argc > 0) { - if (!strcmp(argv[0],"alt")) { - handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); - if (!handle) { - fprintf(stderr,"cannot find alt_svc_mgr\n"); - return -1; - } - svcmgr = handle; - fprintf(stderr,"svcmgr is via %x\n", handle); - } else if (!strcmp(argv[0],"lookup")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - handle = svcmgr_lookup(bs, svcmgr, argv[1]); - fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle); - argc--; - argv++; - } else if (!strcmp(argv[0],"publish")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - svcmgr_publish(bs, svcmgr, argv[1], &token); - argc--; - argv++; - } else { - fprintf(stderr,"unknown command %s\n", argv[0]); - return -1; - } - argc--; - argv++; - } - return 0; -} diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c deleted file mode 100644 index cf3b1728b6..0000000000 --- a/cmds/servicemanager/binder.c +++ /dev/null @@ -1,682 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#define LOG_TAG "Binder" - -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mman.h> -#include <unistd.h> - -#include <log/log.h> - -#include "binder.h" - -#define MAX_BIO_SIZE (1 << 30) - -#define TRACE 0 - -void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn); - -#if TRACE -void hexdump(void *_data, size_t len) -{ - unsigned char *data = _data; - size_t count; - - for (count = 0; count < len; count++) { - if ((count & 15) == 0) - fprintf(stderr,"%04zu:", count); - fprintf(stderr," %02x %c", *data, - (*data < 32) || (*data > 126) ? '.' : *data); - data++; - if ((count & 15) == 15) - fprintf(stderr,"\n"); - } - if ((count & 15) != 0) - fprintf(stderr,"\n"); -} - -void binder_dump_txn(struct binder_transaction_data *txn) -{ - struct flat_binder_object *obj; - binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets; - size_t count = txn->offsets_size / sizeof(binder_size_t); - - fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n", - (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags); - fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n", - txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size); - hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size); - while (count--) { - obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++); - fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n", - obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie); - } -} - -#define NAME(n) case n: return #n -const char *cmd_name(uint32_t cmd) -{ - switch(cmd) { - NAME(BR_NOOP); - NAME(BR_TRANSACTION_COMPLETE); - NAME(BR_INCREFS); - NAME(BR_ACQUIRE); - NAME(BR_RELEASE); - NAME(BR_DECREFS); - NAME(BR_TRANSACTION); - NAME(BR_REPLY); - NAME(BR_FAILED_REPLY); - NAME(BR_DEAD_REPLY); - NAME(BR_DEAD_BINDER); - default: return "???"; - } -} -#else -#define hexdump(a,b) do{} while (0) -#define binder_dump_txn(txn) do{} while (0) -#endif - -#define BIO_F_SHARED 0x01 /* needs to be buffer freed */ -#define BIO_F_OVERFLOW 0x02 /* ran out of space */ -#define BIO_F_IOERROR 0x04 -#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ - -struct binder_state -{ - int fd; - void *mapped; - size_t mapsize; -}; - -struct binder_state *binder_open(const char* driver, size_t mapsize) -{ - struct binder_state *bs; - struct binder_version vers; - - bs = malloc(sizeof(*bs)); - if (!bs) { - errno = ENOMEM; - return NULL; - } - - bs->fd = open(driver, O_RDWR | O_CLOEXEC); - if (bs->fd < 0) { - fprintf(stderr,"binder: cannot open %s (%s)\n", - driver, strerror(errno)); - goto fail_open; - } - - if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || - (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { - fprintf(stderr, - "binder: kernel driver version (%d) differs from user space version (%d)\n", - vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); - goto fail_open; - } - - bs->mapsize = mapsize; - bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); - if (bs->mapped == MAP_FAILED) { - fprintf(stderr,"binder: cannot map device (%s)\n", - strerror(errno)); - goto fail_map; - } - - return bs; - -fail_map: - close(bs->fd); -fail_open: - free(bs); - return NULL; -} - -void binder_close(struct binder_state *bs) -{ - munmap(bs->mapped, bs->mapsize); - close(bs->fd); - free(bs); -} - -int binder_become_context_manager(struct binder_state *bs) -{ - struct flat_binder_object obj; - memset(&obj, 0, sizeof(obj)); - obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX; - - int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj); - - // fallback to original method - if (result != 0) { - android_errorWriteLog(0x534e4554, "121035042"); - - result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); - } - return result; -} - -int binder_write(struct binder_state *bs, void *data, size_t len) -{ - struct binder_write_read bwr; - int res; - - bwr.write_size = len; - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) data; - bwr.read_size = 0; - bwr.read_consumed = 0; - bwr.read_buffer = 0; - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - if (res < 0) { - fprintf(stderr,"binder_write: ioctl failed (%s)\n", - strerror(errno)); - } - return res; -} - -void binder_free_buffer(struct binder_state *bs, - binder_uintptr_t buffer_to_free) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - } __attribute__((packed)) data; - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - binder_write(bs, &data, sizeof(data)); -} - -void binder_send_reply(struct binder_state *bs, - struct binder_io *reply, - binder_uintptr_t buffer_to_free, - int status) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - uint32_t cmd_reply; - struct binder_transaction_data txn; - } __attribute__((packed)) data; - - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - data.cmd_reply = BC_REPLY; - data.txn.target.ptr = 0; - data.txn.cookie = 0; - data.txn.code = 0; - if (status) { - data.txn.flags = TF_STATUS_CODE; - data.txn.data_size = sizeof(int); - data.txn.offsets_size = 0; - data.txn.data.ptr.buffer = (uintptr_t)&status; - data.txn.data.ptr.offsets = 0; - } else { - data.txn.flags = 0; - data.txn.data_size = reply->data - reply->data0; - data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0); - data.txn.data.ptr.buffer = (uintptr_t)reply->data0; - data.txn.data.ptr.offsets = (uintptr_t)reply->offs0; - } - binder_write(bs, &data, sizeof(data)); -} - -int binder_parse(struct binder_state *bs, struct binder_io *bio, - uintptr_t ptr, size_t size, binder_handler func) -{ - int r = 1; - uintptr_t end = ptr + (uintptr_t) size; - - while (ptr < end) { - uint32_t cmd = *(uint32_t *) ptr; - ptr += sizeof(uint32_t); -#if TRACE - fprintf(stderr,"%s:\n", cmd_name(cmd)); -#endif - switch(cmd) { - case BR_NOOP: - break; - case BR_TRANSACTION_COMPLETE: - break; - case BR_INCREFS: - case BR_ACQUIRE: - case BR_RELEASE: - case BR_DECREFS: -#if TRACE - fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *))); -#endif - ptr += sizeof(struct binder_ptr_cookie); - break; - case BR_TRANSACTION_SEC_CTX: - case BR_TRANSACTION: { - struct binder_transaction_data_secctx txn; - if (cmd == BR_TRANSACTION_SEC_CTX) { - if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) { - ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n"); - return -1; - } - memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx)); - ptr += sizeof(struct binder_transaction_data_secctx); - } else /* BR_TRANSACTION */ { - if ((end - ptr) < sizeof(struct binder_transaction_data)) { - ALOGE("parse: txn too small (binder_transaction_data)!\n"); - return -1; - } - memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data)); - ptr += sizeof(struct binder_transaction_data); - - txn.secctx = 0; - } - - binder_dump_txn(&txn.transaction_data); - if (func) { - unsigned rdata[256/4]; - struct binder_io msg; - struct binder_io reply; - int res; - - bio_init(&reply, rdata, sizeof(rdata), 4); - bio_init_from_txn(&msg, &txn.transaction_data); - res = func(bs, &txn, &msg, &reply); - if (txn.transaction_data.flags & TF_ONE_WAY) { - binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer); - } else { - binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res); - } - } - break; - } - case BR_REPLY: { - struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr; - if ((end - ptr) < sizeof(*txn)) { - ALOGE("parse: reply too small!\n"); - return -1; - } - binder_dump_txn(txn); - if (bio) { - bio_init_from_txn(bio, txn); - bio = 0; - } else { - /* todo FREE BUFFER */ - } - ptr += sizeof(*txn); - r = 0; - break; - } - case BR_DEAD_BINDER: { - struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr; - ptr += sizeof(binder_uintptr_t); - death->func(bs, death->ptr); - break; - } - case BR_FAILED_REPLY: - r = -1; - break; - case BR_DEAD_REPLY: - r = -1; - break; - default: - ALOGE("parse: OOPS %d\n", cmd); - return -1; - } - } - - return r; -} - -void binder_acquire(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_ACQUIRE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_release(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_RELEASE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death) -{ - struct { - uint32_t cmd; - struct binder_handle_cookie payload; - } __attribute__((packed)) data; - - data.cmd = BC_REQUEST_DEATH_NOTIFICATION; - data.payload.handle = target; - data.payload.cookie = (uintptr_t) death; - binder_write(bs, &data, sizeof(data)); -} - -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code) -{ - int res; - struct binder_write_read bwr; - struct { - uint32_t cmd; - struct binder_transaction_data txn; - } __attribute__((packed)) writebuf; - unsigned readbuf[32]; - - if (msg->flags & BIO_F_OVERFLOW) { - fprintf(stderr,"binder: txn buffer overflow\n"); - goto fail; - } - - writebuf.cmd = BC_TRANSACTION; - writebuf.txn.target.handle = target; - writebuf.txn.code = code; - writebuf.txn.flags = 0; - writebuf.txn.data_size = msg->data - msg->data0; - writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0); - writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0; - writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0; - - bwr.write_size = sizeof(writebuf); - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) &writebuf; - - hexdump(msg->data0, msg->data - msg->data0); - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); - goto fail; - } - - res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); - if (res == 0) return 0; - if (res < 0) goto fail; - } - -fail: - memset(reply, 0, sizeof(*reply)); - reply->flags |= BIO_F_IOERROR; - return -1; -} - -void binder_loop(struct binder_state *bs, binder_handler func) -{ - int res; - struct binder_write_read bwr; - uint32_t readbuf[32]; - - bwr.write_size = 0; - bwr.write_consumed = 0; - bwr.write_buffer = 0; - - readbuf[0] = BC_ENTER_LOOPER; - binder_write(bs, readbuf, sizeof(uint32_t)); - - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); - break; - } - - res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); - if (res == 0) { - ALOGE("binder_loop: unexpected reply?!\n"); - break; - } - if (res < 0) { - ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); - break; - } - } -} - -void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn) -{ - bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer; - bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets; - bio->data_avail = txn->data_size; - bio->offs_avail = txn->offsets_size / sizeof(size_t); - bio->flags = BIO_F_SHARED; -} - -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxoffs) -{ - size_t n = maxoffs * sizeof(size_t); - - if (n > maxdata) { - bio->flags = BIO_F_OVERFLOW; - bio->data_avail = 0; - bio->offs_avail = 0; - return; - } - - bio->data = bio->data0 = (char *) data + n; - bio->offs = bio->offs0 = data; - bio->data_avail = maxdata - n; - bio->offs_avail = maxoffs; - bio->flags = 0; -} - -static void *bio_alloc(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - if (size > bio->data_avail) { - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -void binder_done(struct binder_state *bs, - __unused struct binder_io *msg, - struct binder_io *reply) -{ - struct { - uint32_t cmd; - uintptr_t buffer; - } __attribute__((packed)) data; - - if (reply->flags & BIO_F_SHARED) { - data.cmd = BC_FREE_BUFFER; - data.buffer = (uintptr_t) reply->data0; - binder_write(bs, &data, sizeof(data)); - reply->flags = 0; - } -} - -static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = bio_alloc(bio, sizeof(*obj)); - - if (obj && bio->offs_avail) { - bio->offs_avail--; - *bio->offs++ = ((char*) obj) - ((char*) bio->data0); - return obj; - } - - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -void bio_put_uint32(struct binder_io *bio, uint32_t n) -{ - uint32_t *ptr = bio_alloc(bio, sizeof(n)); - if (ptr) - *ptr = n; -} - -void bio_put_obj(struct binder_io *bio, void *ptr) -{ - struct flat_binder_object *obj; - - obj = bio_alloc_obj(bio); - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_BINDER; - obj->binder = (uintptr_t)ptr; - obj->cookie = 0; -} - -void bio_put_ref(struct binder_io *bio, uint32_t handle) -{ - struct flat_binder_object *obj; - - if (handle) - obj = bio_alloc_obj(bio); - else - obj = bio_alloc(bio, sizeof(*obj)); - - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_HANDLE; - obj->handle = handle; - obj->cookie = 0; -} - -void bio_put_string16(struct binder_io *bio, const uint16_t *str) -{ - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = 0; - while (str[len]) len++; - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, (uint32_t) len); - len = (len + 1) * sizeof(uint16_t); - ptr = bio_alloc(bio, len); - if (ptr) - memcpy(ptr, str, len); -} - -void bio_put_string16_x(struct binder_io *bio, const char *_str) -{ - unsigned char *str = (unsigned char*) _str; - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = strlen(_str); - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, len); - ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); - if (!ptr) - return; - - while (*str) - *ptr++ = *str++; - *ptr++ = 0; -} - -static void *bio_get(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - - if (bio->data_avail < size){ - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -uint32_t bio_get_uint32(struct binder_io *bio) -{ - uint32_t *ptr = bio_get(bio, sizeof(*ptr)); - return ptr ? *ptr : 0; -} - -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz) -{ - size_t len; - - /* Note: The payload will carry 32bit size instead of size_t */ - len = (size_t) bio_get_uint32(bio); - if (sz) - *sz = len; - return bio_get(bio, (len + 1) * sizeof(uint16_t)); -} - -static struct flat_binder_object *_bio_get_obj(struct binder_io *bio) -{ - size_t n; - size_t off = bio->data - bio->data0; - - /* TODO: be smarter about this? */ - for (n = 0; n < bio->offs_avail; n++) { - if (bio->offs[n] == off) - return bio_get(bio, sizeof(struct flat_binder_object)); - } - - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -uint32_t bio_get_ref(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = _bio_get_obj(bio); - if (!obj) - return 0; - - if (obj->hdr.type == BINDER_TYPE_HANDLE) - return obj->handle; - - return 0; -} diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h deleted file mode 100644 index a9ccc74130..0000000000 --- a/cmds/servicemanager/binder.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#ifndef _BINDER_H_ -#define _BINDER_H_ - -#include <linux/android/binder.h> -#include <sys/ioctl.h> - -struct binder_state; - -struct binder_io -{ - char *data; /* pointer to read/write from */ - binder_size_t *offs; /* array of offsets */ - size_t data_avail; /* bytes available in data buffer */ - size_t offs_avail; /* entries available in offsets array */ - - char *data0; /* start of data buffer */ - binder_size_t *offs0; /* start of offsets buffer */ - uint32_t flags; - uint32_t unused; -}; - -struct binder_death { - void (*func)(struct binder_state *bs, void *ptr); - void *ptr; -}; - -/* the one magic handle */ -#define BINDER_SERVICE_MANAGER 0U - -#define SVC_MGR_NAME "android.os.IServiceManager" - -enum { - /* Must match definitions in IBinder.h and IServiceManager.h */ - PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), - SVC_MGR_GET_SERVICE = 1, - SVC_MGR_CHECK_SERVICE, - SVC_MGR_ADD_SERVICE, - SVC_MGR_LIST_SERVICES, -}; - -typedef int (*binder_handler)(struct binder_state *bs, - struct binder_transaction_data_secctx *txn, - struct binder_io *msg, - struct binder_io *reply); - -struct binder_state *binder_open(const char* driver, size_t mapsize); -void binder_close(struct binder_state *bs); - -/* initiate a blocking binder call - * - returns zero on success - */ -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code); - -/* release any state associate with the binder_io - * - call once any necessary data has been extracted from the - * binder_io after binder_call() returns - * - can safely be called even if binder_call() fails - */ -void binder_done(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply); - -/* manipulate strong references */ -void binder_acquire(struct binder_state *bs, uint32_t target); -void binder_release(struct binder_state *bs, uint32_t target); - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); - -void binder_loop(struct binder_state *bs, binder_handler func); - -int binder_become_context_manager(struct binder_state *bs); - -/* allocate a binder_io, providing a stack-allocated working - * buffer, size of the working buffer, and how many object - * offset entries to reserve from the buffer - */ -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxobjects); - -void bio_put_obj(struct binder_io *bio, void *ptr); -void bio_put_ref(struct binder_io *bio, uint32_t handle); -void bio_put_uint32(struct binder_io *bio, uint32_t n); -void bio_put_string16(struct binder_io *bio, const uint16_t *str); -void bio_put_string16_x(struct binder_io *bio, const char *_str); - -uint32_t bio_get_uint32(struct binder_io *bio); -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); -uint32_t bio_get_ref(struct binder_io *bio); - -#endif diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp new file mode 100644 index 0000000000..c8ceb42ac8 --- /dev/null +++ b/cmds/servicemanager/main.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 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-base/logging.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/Status.h> +#include <utils/StrongPointer.h> + +#include "Access.h" +#include "ServiceManager.h" + +using ::android::sp; +using ::android::ProcessState; +using ::android::IPCThreadState; +using ::android::ServiceManager; +using ::android::Access; + +int main(int argc, char** argv) { + if (argc > 2) { + LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; + } + + const char* driver = argc == 2 ? argv[1] : "/dev/binder"; + + android::base::InitLogging(nullptr, &android::base::KernelLogger); + + ProcessState::self()->initWithDriver(driver); + ProcessState::self()->setThreadPoolMaxThreadCount(0); + ProcessState::self()->setCallRestriction( + ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); + + sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>()); + IPCThreadState::self()->setTheContextObject(manager); + ProcessState::self()->becomeContextManager(nullptr, nullptr); + + IPCThreadState::self()->joinThreadPool(); + + // should not be reached + return EXIT_FAILURE; +} diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c deleted file mode 100644 index ec3fac538d..0000000000 --- a/cmds/servicemanager/service_manager.c +++ /dev/null @@ -1,442 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <cutils/android_filesystem_config.h> -#include <cutils/multiuser.h> - -#include <selinux/android.h> -#include <selinux/avc.h> - -#include "binder.h" - -#ifdef VENDORSERVICEMANAGER -#define LOG_TAG "VendorServiceManager" -#else -#define LOG_TAG "ServiceManager" -#endif -#include <log/log.h> - -struct audit_data { - pid_t pid; - uid_t uid; - const char *name; -}; - -const char *str8(const uint16_t *x, size_t x_len) -{ - static char buf[128]; - size_t max = 127; - char *p = buf; - - if (x_len < max) { - max = x_len; - } - - if (x) { - while ((max > 0) && (*x != '\0')) { - *p++ = *x++; - max--; - } - } - *p++ = 0; - return buf; -} - -int str16eq(const uint16_t *a, const char *b) -{ - while (*a && *b) - if (*a++ != *b++) return 0; - if (*a || *b) - return 0; - return 1; -} - -static char *service_manager_context; -static struct selabel_handle* sehandle; - -static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name) -{ - char *lookup_sid = NULL; - const char *class = "service_manager"; - bool allowed; - struct audit_data ad; - - if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) { - ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); - return false; - } - - ad.pid = spid; - ad.uid = uid; - ad.name = name; - - if (sid == NULL) { - android_errorWriteLog(0x534e4554, "121035042"); - } - - int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad); - allowed = (result == 0); - - freecon(lookup_sid); - return allowed; -} - -static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm) -{ - return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL); -} - -static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name) -{ - bool allowed; - char *tctx = NULL; - - if (!sehandle) { - ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); - abort(); - } - - if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { - ALOGE("SELinux: No match for %s in service_contexts.\n", name); - return false; - } - - allowed = check_mac_perms(spid, sid, uid, tctx, perm, name); - freecon(tctx); - return allowed; -} - -static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "add"; - - if (multiuser_get_app_id(uid) >= AID_APP) { - return 0; /* Don't allow apps to register services */ - } - - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -static int svc_can_list(pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "list"; - return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0; -} - -static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "find"; - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -struct svcinfo -{ - struct svcinfo *next; - uint32_t handle; - struct binder_death death; - int allow_isolated; - uint32_t dumpsys_priority; - size_t len; - uint16_t name[0]; -}; - -struct svcinfo *svclist = NULL; - -struct svcinfo *find_svc(const uint16_t *s16, size_t len) -{ - struct svcinfo *si; - - for (si = svclist; si; si = si->next) { - if ((len == si->len) && - !memcmp(s16, si->name, len * sizeof(uint16_t))) { - return si; - } - } - return NULL; -} - -void svcinfo_death(struct binder_state *bs, void *ptr) -{ - struct svcinfo *si = (struct svcinfo* ) ptr; - - ALOGI("service '%s' died\n", str8(si->name, si->len)); - if (si->handle) { - binder_release(bs, si->handle); - si->handle = 0; - } -} - -uint16_t svcmgr_id[] = { - 'a','n','d','r','o','i','d','.','o','s','.', - 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' -}; - - -uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid) -{ - struct svcinfo *si = find_svc(s, len); - - if (!si || !si->handle) { - return 0; - } - - if (!si->allow_isolated) { - // If this service doesn't allow access from isolated processes, - // then check the uid to see if it is isolated. - uid_t appid = uid % AID_USER; - if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { - return 0; - } - } - - if (!svc_can_find(s, len, spid, sid, uid)) { - return 0; - } - - return si->handle; -} - -int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, - uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) { - struct svcinfo *si; - - //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, - // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); - - if (!handle || (len == 0) || (len > 127)) - return -1; - - if (!svc_can_register(s, len, spid, sid, uid)) { - ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", - str8(s, len), handle, uid); - return -1; - } - - si = find_svc(s, len); - if (si) { - if (si->handle) { - ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", - str8(s, len), handle, uid); - svcinfo_death(bs, si); - } - si->handle = handle; - } else { - si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); - if (!si) { - ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", - str8(s, len), handle, uid); - return -1; - } - si->handle = handle; - si->len = len; - memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); - si->name[len] = '\0'; - si->death.func = (void*) svcinfo_death; - si->death.ptr = si; - si->allow_isolated = allow_isolated; - si->dumpsys_priority = dumpsys_priority; - si->next = svclist; - svclist = si; - } - - binder_acquire(bs, handle); - binder_link_to_death(bs, handle, &si->death); - return 0; -} - -int svcmgr_handler(struct binder_state *bs, - struct binder_transaction_data_secctx *txn_secctx, - struct binder_io *msg, - struct binder_io *reply) -{ - struct svcinfo *si; - uint16_t *s; - size_t len; - uint32_t handle; - uint32_t strict_policy; - int allow_isolated; - uint32_t dumpsys_priority; - - struct binder_transaction_data *txn = &txn_secctx->transaction_data; - - //ALOGI("target=%p code=%d pid=%d uid=%d\n", - // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); - - if (txn->target.ptr != BINDER_SERVICE_MANAGER) - return -1; - - if (txn->code == PING_TRANSACTION) - return 0; - - // Equivalent to Parcel::enforceInterface(), reading the RPC - // header with the strict mode policy mask and the interface name. - // Note that we ignore the strict_policy and don't propagate it - // further (since we do no outbound RPCs anyway). - strict_policy = bio_get_uint32(msg); - bio_get_uint32(msg); // Ignore worksource header. - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - - if ((len != (sizeof(svcmgr_id) / 2)) || - memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { - fprintf(stderr,"invalid id %s\n", str8(s, len)); - return -1; - } - - if (sehandle && selinux_status_updated() > 0) { -#ifdef VENDORSERVICEMANAGER - struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle(); -#else - struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(); -#endif - if (tmp_sehandle) { - selabel_close(sehandle); - sehandle = tmp_sehandle; - } - } - - switch(txn->code) { - case SVC_MGR_GET_SERVICE: - case SVC_MGR_CHECK_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid, - (const char*) txn_secctx->secctx); - if (!handle) - break; - bio_put_ref(reply, handle); - return 0; - - case SVC_MGR_ADD_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = bio_get_ref(msg); - allow_isolated = bio_get_uint32(msg) ? 1 : 0; - dumpsys_priority = bio_get_uint32(msg); - if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, - txn->sender_pid, (const char*) txn_secctx->secctx)) - return -1; - break; - - case SVC_MGR_LIST_SERVICES: { - uint32_t n = bio_get_uint32(msg); - uint32_t req_dumpsys_priority = bio_get_uint32(msg); - - if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) { - ALOGE("list_service() uid=%d - PERMISSION DENIED\n", - txn->sender_euid); - return -1; - } - si = svclist; - // walk through the list of services n times skipping services that - // do not support the requested priority - while (si) { - if (si->dumpsys_priority & req_dumpsys_priority) { - if (n == 0) break; - n--; - } - si = si->next; - } - if (si) { - bio_put_string16(reply, si->name); - return 0; - } - return -1; - } - default: - ALOGE("unknown code %d\n", txn->code); - return -1; - } - - bio_put_uint32(reply, 0); - return 0; -} - - -static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len) -{ - struct audit_data *ad = (struct audit_data *)data; - - if (!ad || !ad->name) { - ALOGE("No service manager audit data"); - return 0; - } - - snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid); - return 0; -} - -int main(int argc, char** argv) -{ - struct binder_state *bs; - union selinux_callback cb; - char *driver; - - if (argc > 1) { - driver = argv[1]; - } else { - driver = "/dev/binder"; - } - - bs = binder_open(driver, 128*1024); - if (!bs) { -#ifdef VENDORSERVICEMANAGER - ALOGW("failed to open binder driver %s\n", driver); - while (true) { - sleep(UINT_MAX); - } -#else - ALOGE("failed to open binder driver %s\n", driver); -#endif - return -1; - } - - if (binder_become_context_manager(bs)) { - ALOGE("cannot become context manager (%s)\n", strerror(errno)); - return -1; - } - - cb.func_audit = audit_callback; - selinux_set_callback(SELINUX_CB_AUDIT, cb); -#ifdef VENDORSERVICEMANAGER - cb.func_log = selinux_vendor_log_callback; -#else - cb.func_log = selinux_log_callback; -#endif - selinux_set_callback(SELINUX_CB_LOG, cb); - -#ifdef VENDORSERVICEMANAGER - sehandle = selinux_android_vendor_service_context_handle(); -#else - sehandle = selinux_android_service_context_handle(); -#endif - selinux_status_open(true); - - if (sehandle == NULL) { - ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); - abort(); - } - - if (getcon(&service_manager_context) != 0) { - ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); - abort(); - } - - - binder_loop(bs, svcmgr_handler); - - return 0; -} diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp new file mode 100644 index 0000000000..812d5cacd5 --- /dev/null +++ b/cmds/servicemanager/test_sm.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2019 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/ProcessState.h> +#include <cutils/android_filesystem_config.h> +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include "Access.h" +#include "ServiceManager.h" + +using android::sp; +using android::Access; +using android::IBinder; +using android::ServiceManager; +using android::os::IServiceManager; +using testing::_; +using testing::ElementsAre; +using testing::NiceMock; +using testing::Return; + +static sp<IBinder> getBinder() { + // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work. + // The context manager (servicemanager) is easy to get and is in another process. + return android::ProcessState::self()->getContextObject(nullptr); +} + +class MockAccess : public Access { +public: + MOCK_METHOD1(getCallingContext, CallingContext(const std::string& name)); + MOCK_METHOD1(canAdd, bool(const CallingContext&)); + MOCK_METHOD1(canFind, bool(const CallingContext&)); + MOCK_METHOD1(canList, bool(const CallingContext&)); +}; + +static sp<ServiceManager> getPermissiveServiceManager() { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + ON_CALL(*access, getCallingContext(_)).WillByDefault(Return(Access::CallingContext{})); + ON_CALL(*access, canAdd(_)).WillByDefault(Return(true)); + ON_CALL(*access, canFind(_)).WillByDefault(Return(true)); + ON_CALL(*access, canList(_)).WillByDefault(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + return sm; +} + +TEST(AddService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, EmptyNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, JustShortEnoughServiceNameHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService(std::string(127, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, TooLongNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService(std::string(128, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddNullServiceDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("foo", nullptr, false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddDisallowedFromApp) { + for (uid_t uid : { AID_APP_START, AID_APP_START + 1, AID_APP_END }) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{ + .debugPid = 1337, + .uid = uid, + })); + EXPECT_CALL(*access, canAdd(_)).Times(0); + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + } + +} + +TEST(AddService, HappyOverExistingService) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, NoPermissions) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(GetService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out); +} + +TEST(GetService, NonExistant) { + auto sm = getPermissiveServiceManager(); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, NoPermissionsForGettingService) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillRepeatedly(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, AllowedFromIsolated) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out.get()); +} + +TEST(GetService, NotAllowedFromIsolated) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + + // TODO(b/136023468): when security check is first, this should be called first + // EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(ListServices, NoPermissions) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canList(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + std::vector<std::string> out; + EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + EXPECT_TRUE(out.empty()); +} + +TEST(ListServices, AllServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector<std::string> out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa", "sb", "sc", "sd")); +} + +TEST(ListServices, CriticalServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector<std::string> out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa")); +} diff --git a/include/android/font.h b/include/android/font.h index 435a573f51..8001ee1938 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * { + * @{ */ /** diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index e286a4c812..0b8f892b9b 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * { + * @{ */ /** diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h index dde9055c7a..f0485a1871 100644 --- a/include/android/system_fonts.h +++ b/include/android/system_fonts.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * { + * @{ */ /** diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 905b25f397..760d55b751 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -94,7 +94,6 @@ cc_library_shared { "PermissionController.cpp", "ProcessInfoService.cpp", "IpPrefix.cpp", - ":libbinder_aidl", ], }, }, @@ -142,8 +141,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", + "aidl/android/os/IServiceManager.aidl", ], path: "aidl", } - -subdirs = ["tests"] diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index a2d10ab0ab..3424c28883 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1062,7 +1062,7 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, sp<BBinder> the_context_object; -void setTheContextObject(sp<BBinder> obj) +void IPCThreadState::setTheContextObject(sp<BBinder> obj) { the_context_object = obj; } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 0203d41992..07550fb571 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -18,6 +18,7 @@ #include <binder/IServiceManager.h> +#include <android/os/IServiceManager.h> #include <utils/Log.h> #include <binder/IPCThreadState.h> #ifndef __ANDROID_VNDK__ @@ -34,6 +35,9 @@ namespace android { +using AidlServiceManager = android::os::IServiceManager; +using android::binder::Status; + sp<IServiceManager> defaultServiceManager() { static Mutex gDefaultServiceManagerLock; @@ -142,11 +146,12 @@ class BpServiceManager : public BpInterface<IServiceManager> { public: explicit BpServiceManager(const sp<IBinder>& impl) - : BpInterface<IServiceManager>(impl) + : BpInterface<IServiceManager>(impl), + mTheRealServiceManager(interface_cast<AidlServiceManager>(impl)) { } - virtual sp<IBinder> getService(const String16& name) const + sp<IBinder> getService(const String16& name) const override { static bool gSystemBootCompleted = false; @@ -179,43 +184,36 @@ public: return nullptr; } - virtual sp<IBinder> checkService( const String16& name) const - { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); - return reply.readStrongBinder(); + sp<IBinder> checkService(const String16& name) const override { + sp<IBinder> ret; + if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { + return nullptr; + } + return ret; } - virtual status_t addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated, int dumpsysPriority) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - data.writeStrongBinder(service); - data.writeInt32(allowIsolated ? 1 : 0); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); - return err == NO_ERROR ? reply.readExceptionCode() : err; + status_t addService(const String16& name, const sp<IBinder>& service, + bool allowIsolated, int dumpsysPriority) override { + Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority); + return status.exceptionCode(); } virtual Vector<String16> listServices(int dumpsysPriority) { - Vector<String16> res; - int n = 0; + std::vector<std::string> ret; + if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) { + return {}; + } - for (;;) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeInt32(n++); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); - if (err != NO_ERROR) - break; - res.add(reply.readString16()); + Vector<String16> res; + res.setCapacity(ret.size()); + for (const std::string& name : ret) { + res.push(String16(name.c_str())); } return res; } + +private: + sp<AidlServiceManager> mTheRealServiceManager; }; IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl new file mode 100644 index 0000000000..50a72aa9e4 --- /dev/null +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2006 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; + +/** + * Basic interface for finding and publishing system services. + * + * You likely want to use android.os.ServiceManager in Java or + * android::IServiceManager in C++ in order to use this interface. + * + * @hide + */ +interface IServiceManager { + /* + * Must update values in IServiceManager.h + */ + /* Allows services to dump sections according to priorities. */ + const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0 + const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1 + const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2 + /** + * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the + * same priority as NORMAL priority but the services are not called with dump priority + * arguments. + */ + const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3 + + const int DUMP_FLAG_PRIORITY_ALL = 15; + // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH + // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; + + /* Allows services to dump sections in protobuf format. */ + const int DUMP_FLAG_PROTO = 16; // 1 << 4 + + /** + * Retrieve an existing service called @a name from the + * service manager. + * + * This is the same as checkService (returns immediately) but + * exists for legacy purposes. + * + * Returns null if the service does not exist. + */ + @UnsupportedAppUsage + IBinder getService(@utf8InCpp String name); + + /** + * Retrieve an existing service called @a name from the service + * manager. Non-blocking. Returns null if the service does not + * exist. + */ + @UnsupportedAppUsage + IBinder checkService(@utf8InCpp String name); + + /** + * Place a new @a service called @a name into the service + * manager. + */ + void addService(@utf8InCpp String name, IBinder service, + boolean allowIsolated, int dumpPriority); + + /** + * Return a list of all currently running services. + */ + @utf8InCpp String[] listServices(int dumpPriority); +} diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 614b0b33dd..b810f7e8ee 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -110,6 +110,8 @@ public: // the maximum number of binder threads threads allowed for this process. void blockUntilThreadAvailable(); + // Service manager registration + void setTheContextObject(sp<BBinder> obj); // Is this thread currently serving a binder call. This method // returns true if while traversing backwards from the function call diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 5fd4a95d7b..41cbde1c18 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -23,6 +23,7 @@ #include <inttypes.h> #include <mutex> +#include <optional> #include <set> #include <string> #include <unordered_map> @@ -62,19 +63,20 @@ static std::vector<std::vector<uint32_t>> gPolicyCpus; static std::set<uint32_t> gAllFreqs; static unique_fd gMapFd; -static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) { +static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) { std::string data; - if (!android::base::ReadFileToString(path, &data)) return false; + if (!android::base::ReadFileToString(path, &data)) return {}; auto strings = android::base::Split(data, " \n"); + std::vector<uint32_t> ret; for (const auto &s : strings) { if (s.empty()) continue; uint32_t n; - if (!android::base::ParseUint(s, &n)) return false; - out->emplace_back(n); + if (!android::base::ParseUint(s, &n)) return {}; + ret.emplace_back(n); } - return true; + return ret; } static int isPolicyFile(const struct dirent *d) { @@ -111,20 +113,22 @@ static bool initGlobals() { for (const auto &name : {"available", "boost"}) { std::string path = StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name); - if (!readNumbersFromFile(path, &freqs)) return false; + auto nums = readNumbersFromFile(path); + if (!nums) return false; + freqs.insert(freqs.end(), nums->begin(), nums->end()); } std::sort(freqs.begin(), freqs.end()); gPolicyFreqs.emplace_back(freqs); for (auto freq : freqs) gAllFreqs.insert(freq); - std::vector<uint32_t> cpus; std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus"); - if (!readNumbersFromFile(path, &cpus)) return false; - gPolicyCpus.emplace_back(cpus); + auto cpus = readNumbersFromFile(path); + if (!cpus) return false; + gPolicyCpus.emplace_back(*cpus); } - gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")}; + gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; if (gMapFd < 0) return false; gInitialized = true; @@ -151,17 +155,15 @@ bool startTrackingUidCpuFreqTimes() { } // Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes. -// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors -// using the format: +// Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], // [t1_0, t1_1, ...], ...] // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq. -bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) { - if (!gInitialized && !initGlobals()) return false; +std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) { + if (!gInitialized && !initGlobals()) return {}; time_key_t key = {.uid = uid, .freq = 0}; - freqTimes->clear(); - freqTimes->resize(gNPolicies); + std::vector<std::vector<uint64_t>> out(gNPolicies); std::vector<uint32_t> idxs(gNPolicies, 0); val_t value; @@ -172,32 +174,32 @@ bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTi if (errno == ENOENT) memset(&value.ar, 0, sizeof(value.ar)); else - return false; + return {}; } for (uint32_t i = 0; i < gNPolicies; ++i) { if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue; uint64_t time = 0; for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; idxs[i] += 1; - (*freqTimes)[i].emplace_back(time); + out[i].emplace_back(time); } } - return true; + return out; } // Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap. -// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to -// vectors of vectors using the format: +// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors +// using the format: // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...], // uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... } // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq. -bool getUidsCpuFreqTimes( - std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) { - if (!gInitialized && !initGlobals()) return false; +std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> +getUidsCpuFreqTimes() { + if (!gInitialized && !initGlobals()) return {}; - int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times"); - if (fd < 0) return false; + int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map"); + if (fd < 0) return {}; BpfMap<time_key_t, val_t> m(fd); std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs; @@ -206,25 +208,26 @@ bool getUidsCpuFreqTimes( for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j; policyFreqIdxs.emplace_back(freqIdxs); } - - auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val, + std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map; + auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val, const BpfMap<time_key_t, val_t> &) { - if (freqTimeMap->find(key.uid) == freqTimeMap->end()) { - (*freqTimeMap)[key.uid].resize(gNPolicies); + if (map.find(key.uid) == map.end()) { + map[key.uid].resize(gNPolicies); for (uint32_t i = 0; i < gNPolicies; ++i) { - (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0); + map[key.uid][i].resize(gPolicyFreqs[i].size(), 0); } } for (size_t policy = 0; policy < gNPolicies; ++policy) { for (const auto &cpu : gPolicyCpus[policy]) { auto freqIdx = policyFreqIdxs[policy][key.freq]; - (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu]; + map[key.uid][policy][freqIdx] += val.ar[cpu]; } } return android::netdutils::status::ok; }; - return isOk(m.iterateWithValue(fn)); + if (isOk(m.iterateWithValue(fn))) return map; + return {}; } // Clear all time in state data for a given uid. Returns false on error, true otherwise. diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h index 9f6103ed9b..d7b45870ac 100644 --- a/libs/cputimeinstate/cputimeinstate.h +++ b/libs/cputimeinstate/cputimeinstate.h @@ -23,8 +23,9 @@ namespace android { namespace bpf { bool startTrackingUidCpuFreqTimes(); -bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes); -bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap); +std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid); +std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> + getUidsCpuFreqTimes(); bool clearUidCpuFreqTimes(unsigned int uid); } // namespace bpf diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 9837865dfb..d4b87386e0 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -12,45 +12,46 @@ namespace bpf { using std::vector; TEST(TimeInStateTest, SingleUid) { - vector<vector<uint64_t>> times; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - EXPECT_FALSE(times.empty()); + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + EXPECT_FALSE(times->empty()); } TEST(TimeInStateTest, AllUid) { vector<size_t> sizes; - std::unordered_map<uint32_t, vector<vector<uint64_t>>> map; - ASSERT_TRUE(getUidsCpuFreqTimes(&map)); + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); - ASSERT_FALSE(map.empty()); + ASSERT_FALSE(map->empty()); - auto firstEntry = map.begin()->second; + auto firstEntry = map->begin()->second; for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); - for (const auto &vec : map) { + for (const auto &vec : *map) { ASSERT_EQ(vec.second.size(), sizes.size()); for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); } } TEST(TimeInStateTest, RemoveUid) { - vector<vector<uint64_t>> times, times2; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - ASSERT_FALSE(times.empty()); + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + ASSERT_FALSE(times->empty()); uint64_t sum = 0; - for (size_t i = 0; i < times.size(); ++i) { - for (auto x : times[i]) sum += x; + for (size_t i = 0; i < times->size(); ++i) { + for (auto x : (*times)[i]) sum += x; } ASSERT_GT(sum, (uint64_t)0); ASSERT_TRUE(clearUidCpuFreqTimes(0)); - ASSERT_TRUE(getUidCpuFreqTimes(0, ×2)); - ASSERT_EQ(times2.size(), times.size()); - for (size_t i = 0; i < times.size(); ++i) { - ASSERT_EQ(times2[i].size(), times[i].size()); - for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]); + auto times2 = getUidCpuFreqTimes(0); + ASSERT_TRUE(times2.has_value()); + ASSERT_EQ(times2->size(), times->size()); + for (size_t i = 0; i < times->size(); ++i) { + ASSERT_EQ((*times2)[i].size(), (*times)[i].size()); + for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]); } } diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 40f6b43802..8e762f193f 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -46,6 +46,7 @@ static const char* native_processes_to_dump[] = { static const char* hal_interfaces_to_dump[] { "android.hardware.audio@2.0::IDevicesFactory", "android.hardware.audio@4.0::IDevicesFactory", + "android.hardware.biometrics.face@1.0::IBiometricsFace", "android.hardware.bluetooth@1.0::IBluetoothHci", "android.hardware.camera.provider@2.4::ICameraProvider", "android.hardware.drm@1.0::IDrmFactory", diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 1c5fa52855..24b6c2d6de 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -37,6 +37,7 @@ #include <memory> #include <string> +#include <thread> // TODO(b/37049319) Get this from a header once one exists extern "C" { @@ -163,17 +164,20 @@ void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path, void GraphicsEnv::hintActivityLaunch() { ATRACE_CALL(); - // If there's already graphics driver preloaded in the process, just send - // the stats info to GpuStats directly through async binder. - std::lock_guard<std::mutex> lock(mStatsLock); - if (mGpuStats.glDriverToSend) { - mGpuStats.glDriverToSend = false; - sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime); - } - if (mGpuStats.vkDriverToSend) { - mGpuStats.vkDriverToSend = false; - sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); - } + std::thread trySendGpuStatsThread([this]() { + // If there's already graphics driver preloaded in the process, just send + // the stats info to GpuStats directly through async binder. + std::lock_guard<std::mutex> lock(mStatsLock); + if (mGpuStats.glDriverToSend) { + mGpuStats.glDriverToSend = false; + sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime); + } + if (mGpuStats.vkDriverToSend) { + mGpuStats.vkDriverToSend = false; + sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); + } + }); + trySendGpuStatsThread.detach(); } void GraphicsEnv::setGpuStats(const std::string& driverPackageName, diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index e0e3431ca5..b429d387ad 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -97,7 +97,9 @@ BufferQueueCore::BufferQueueCore() : mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, HAL_DATASPACE_UNKNOWN), mLastQueuedSlot(INVALID_BUFFER_SLOT), - mUniqueId(getUniqueId()) + mUniqueId(getUniqueId()), + mAutoPrerotation(false), + mTransformHintInUse(0) { int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { @@ -123,10 +125,12 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const mQueueBufferCanDrop, mLegacyBufferDrop); outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); - outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint, - mFrameCounter); + outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(), + mTransformHint, mFrameCounter); + outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(), + mTransformHintInUse, mAutoPrerotation); - outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { double timestamp = current->mTimestamp / 1e9; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..da091cc61f 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -408,6 +408,10 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou if (useDefaultSize) { width = mCore->mDefaultWidth; height = mCore->mDefaultHeight; + if (mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(width, height); + } } int found = BufferItem::INVALID_BUFFER_SLOT; @@ -951,7 +955,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; @@ -1132,9 +1136,6 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: value = static_cast<int32_t>(mCore->mConsumerIsProtected); break; - case NATIVE_WINDOW_MAX_BUFFER_COUNT: - value = static_cast<int32_t>(mCore->mMaxBufferCount); - break; default: return BAD_VALUE; } @@ -1194,11 +1195,12 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; + output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect @@ -1298,6 +1300,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); mCore->mDequeueCondition.notify_all(); + mCore->mAutoPrerotation = false; listener = mCore->mConsumerListener; } else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("disconnect: not connected (req=%d)", api); @@ -1341,6 +1344,8 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage) { ATRACE_CALL(); + + const bool useDefaultSize = !width && !height; while (true) { size_t newBufferCount = 0; uint32_t allocWidth = 0; @@ -1367,6 +1372,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocWidth = width > 0 ? width : mCore->mDefaultWidth; allocHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(allocWidth, allocHeight); + } + allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); @@ -1397,6 +1407,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, std::unique_lock<std::mutex> lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(checkWidth, checkHeight); + } + PixelFormat checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; uint64_t checkUsage = usage | mCore->mConsumerUsageBits; @@ -1599,4 +1614,14 @@ status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const { return NO_ERROR; } +status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + BQ_LOGV("setAutoPrerotation: %d", autoPrerotation); + + std::lock_guard<std::mutex> lock(mCore->mMutex); + + mCore->mAutoPrerotation = autoPrerotation; + return NO_ERROR; +} + } // namespace android diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index f5cf1c4d5a..b8faa2df4c 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -32,10 +32,11 @@ namespace android { // --------------------------------------------------------------------------- -DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) { +DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource, + ISurfaceComposer::ConfigChanged configChanged) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); if (sf != nullptr) { - mEventConnection = sf->createDisplayEventConnection(vsyncSource); + mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged); if (mEventConnection != nullptr) { mDataChannel = std::make_unique<gui::BitTube>(); mEventConnection->stealReceiveChannel(mDataChannel.get()); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 0e03b7d393..0009a57653 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -73,6 +73,7 @@ enum { GET_UNIQUE_ID, GET_CONSUMER_USAGE, SET_LEGACY_BUFFER_DROP, + SET_AUTO_PREROTATION, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -547,6 +548,17 @@ public: } return actualResult; } + + virtual status_t setAutoPrerotation(bool autoPrerotation) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeBool(autoPrerotation); + status_t result = remote()->transact(SET_AUTO_PREROTATION, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -675,6 +687,10 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const override { return mBase->getConsumerUsage(outUsage); } + + status_t setAutoPrerotation(bool autoPrerotation) override { + return mBase->setAutoPrerotation(autoPrerotation); + } }; IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, @@ -688,6 +704,12 @@ status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) { return INVALID_OPERATION; } +status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { + // No-op for IGBP other than BufferQueue. + (void)autoPrerotation; + return INVALID_OPERATION; +} + status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1050,6 +1072,13 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case SET_AUTO_PREROTATION: { + CHECK_INTERFACE(IGraphicBuffer, data, reply); + bool autoPrerotation = data.readBool(); + status_t result = setAutoPrerotation(autoPrerotation); + reply->writeInt32(result); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -1141,12 +1170,8 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( // ---------------------------------------------------------------------------- constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { - return sizeof(width) + - sizeof(height) + - sizeof(transformHint) + - sizeof(numPendingBuffers) + - sizeof(nextFrameNumber) + - sizeof(bufferReplaced); + return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) + + sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount); } size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { @@ -1170,6 +1195,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::flatten( FlattenableUtils::write(buffer, size, numPendingBuffers); FlattenableUtils::write(buffer, size, nextFrameNumber); FlattenableUtils::write(buffer, size, bufferReplaced); + FlattenableUtils::write(buffer, size, maxBufferCount); return frameTimestamps.flatten(buffer, size, fds, count); } @@ -1187,6 +1213,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( FlattenableUtils::read(buffer, size, numPendingBuffers); FlattenableUtils::read(buffer, size, nextFrameNumber); FlattenableUtils::read(buffer, size, bufferReplaced); + FlattenableUtils::read(buffer, size, maxBufferCount); return frameTimestamps.unflatten(buffer, size, fds, count); } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 6c9d81ab57..e487792c87 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -278,8 +278,8 @@ public: return NO_ERROR; } - virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource) - { + virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource, + ConfigChanged configChanged) { Parcel data, reply; sp<IDisplayEventConnection> result; int err = data.writeInterfaceToken( @@ -288,6 +288,7 @@ public: return result; } data.writeInt32(static_cast<int32_t>(vsyncSource)); + data.writeInt32(static_cast<int32_t>(configChanged)); err = remote()->transact( BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION, data, &reply); @@ -1155,8 +1156,11 @@ status_t BnSurfaceComposer::onTransact( } case CREATE_DISPLAY_EVENT_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IDisplayEventConnection> connection(createDisplayEventConnection( - static_cast<ISurfaceComposer::VsyncSource>(data.readInt32()))); + auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32()); + auto configChanged = static_cast<ISurfaceComposer::ConfigChanged>(data.readInt32()); + + sp<IDisplayEventConnection> connection( + createDisplayEventConnection(vsyncSource, configChanged)); reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..4e6a4e7b4c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -96,6 +96,7 @@ Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; + mMaxBufferCount = 0; } Surface::~Surface() { @@ -961,6 +962,10 @@ int Surface::query(int what, int* value) const { *value = static_cast<int>(mDataSpace); return NO_ERROR; } + case NATIVE_WINDOW_MAX_BUFFER_COUNT: { + *value = mMaxBufferCount; + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -1072,6 +1077,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_CONSUMER_USAGE64: res = dispatchGetConsumerUsage64(args); break; + case NATIVE_WINDOW_SET_AUTO_PREROTATION: + res = dispatchSetAutoPrerotation(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1272,6 +1280,11 @@ int Surface::dispatchGetConsumerUsage64(va_list args) { return getConsumerUsage(usage); } +int Surface::dispatchSetAutoPrerotation(va_list args) { + bool autoPrerotation = va_arg(args, int); + return setAutoPrerotation(autoPrerotation); +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -1298,6 +1311,7 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; + mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers @@ -1339,6 +1353,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; + mAutoPrerotation = false; if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; @@ -1920,7 +1935,8 @@ status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) return OK; } -status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) { +status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp<GraphicBuffer> buffer, + Dataspace dataspace) { if (buffer == nullptr) { return BAD_VALUE; } @@ -1929,6 +1945,11 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffe if (err != OK) { return err; } + ui::Dataspace tmpDataspace = surface->getBuffersDataSpace(); + err = surface->setBuffersDataSpace(dataspace); + if (err != OK) { + return err; + } err = surface->attachBuffer(buffer->getNativeBuffer()); if (err != OK) { return err; @@ -1937,8 +1958,30 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffe if (err != OK) { return err; } + err = surface->setBuffersDataSpace(tmpDataspace); + if (err != OK) { + return err; + } err = surface->disconnect(NATIVE_WINDOW_API_CPU); return err; } +int Surface::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + ALOGV("Surface::setAutoPrerotation (%d)", autoPrerotation); + Mutex::Autolock lock(mMutex); + + if (mAutoPrerotation == autoPrerotation) { + return OK; + } + + status_t err = mGraphicBufferProducer->setAutoPrerotation(autoPrerotation); + if (err == NO_ERROR) { + mAutoPrerotation = autoPrerotation; + } + ALOGE_IF(err, "IGraphicBufferProducer::setAutoPrerotation(%d) returned %s", autoPrerotation, + strerror(-err)); + return err; +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index cc9e468e16..c59fddfb9d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -322,10 +322,99 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mEarlyWakeup(other.mEarlyWakeup), + mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; + mListenerCallbacks = other.mListenerCallbacks; +} + +std::unique_ptr<SurfaceComposerClient::Transaction> +SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { + auto transaction = std::make_unique<Transaction>(); + if (transaction->readFromParcel(parcel) == NO_ERROR) { + return transaction; + } + return nullptr; +} + +status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { + const uint32_t forceSynchronous = parcel->readUint32(); + const uint32_t transactionNestCount = parcel->readUint32(); + const bool animation = parcel->readBool(); + const bool earlyWakeup = parcel->readBool(); + const bool containsBuffer = parcel->readBool(); + const int64_t desiredPresentTime = parcel->readInt64(); + + size_t count = static_cast<size_t>(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + SortedVector<DisplayState> displayStates; + displayStates.setCapacity(count); + for (size_t i = 0; i < count; i++) { + DisplayState displayState; + if (displayState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + displayStates.add(displayState); + } + + count = static_cast<size_t>(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> composerStates; + composerStates.reserve(count); + for (size_t i = 0; i < count; i++) { + sp<SurfaceControl> surfaceControl = SurfaceControl::readFromParcel(parcel); + + ComposerState composerState; + if (composerState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + composerStates[surfaceControl] = composerState; + } + + InputWindowCommands inputWindowCommands; + inputWindowCommands.read(*parcel); + + // Parsing was successful. Update the object. + mForceSynchronous = forceSynchronous; + mTransactionNestCount = transactionNestCount; + mAnimation = animation; + mEarlyWakeup = earlyWakeup; + mContainsBuffer = containsBuffer; + mDesiredPresentTime = desiredPresentTime; + mDisplayStates = displayStates; + mComposerStates = composerStates; + mInputWindowCommands = inputWindowCommands; + // listener callbacks contain function pointer addresses and may not be safe to parcel. + mListenerCallbacks.clear(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const { + parcel->writeUint32(mForceSynchronous); + parcel->writeUint32(mTransactionNestCount); + parcel->writeBool(mAnimation); + parcel->writeBool(mEarlyWakeup); + parcel->writeBool(mContainsBuffer); + parcel->writeInt64(mDesiredPresentTime); + parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); + for (auto const& displayState : mDisplayStates) { + displayState.write(*parcel); + } + + parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size())); + for (auto const& [surfaceControl, composerState] : mComposerStates) { + surfaceControl->writeToParcel(parcel); + composerState.write(*parcel); + } + + mInputWindowCommands.write(*parcel); + return NO_ERROR; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { @@ -336,7 +425,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mComposerStates[kv.first].state.merge(kv.second.state); } } - other.mComposerStates.clear(); for (auto const& state : other.mDisplayStates) { ssize_t index = mDisplayStates.indexOf(state); @@ -346,7 +434,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state); } } - other.mDisplayStates.clear(); for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; @@ -357,17 +444,27 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()), std::make_move_iterator(surfaceControls.end())); } - other.mListenerCallbacks.clear(); mInputWindowCommands.merge(other.mInputWindowCommands); - other.mInputWindowCommands.clear(); mContainsBuffer = other.mContainsBuffer; - other.mContainsBuffer = false; - + other.clear(); return *this; } +void SurfaceComposerClient::Transaction::clear() { + mComposerStates.clear(); + mDisplayStates.clear(); + mListenerCallbacks.clear(); + mInputWindowCommands.clear(); + mContainsBuffer = false; + mForceSynchronous = 0; + mTransactionNestCount = 0; + mAnimation = false; + mEarlyWakeup = false; + mDesiredPresentTime = -1; +} + void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle, const sp<ISurfaceComposerClient>& client) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 55488dad0b..b9defdd120 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -71,14 +71,6 @@ SurfaceControl::~SurfaceControl() release(); } -void SurfaceControl::destroy() -{ - if (isValid()) { - SurfaceComposerClient::Transaction().reparent(this, nullptr).apply(); - } - release(); -} - void SurfaceControl::release() { // Trigger an IPC now, to make sure things @@ -186,8 +178,7 @@ void SurfaceControl::writeToParcel(Parcel* parcel) parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); } -sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel) -{ +sp<SurfaceControl> SurfaceControl::readFromParcel(const Parcel* parcel) { sp<IBinder> client = parcel->readStrongBinder(); sp<IBinder> handle = parcel->readStrongBinder(); if (client == nullptr || handle == nullptr) diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 690a85f395..205e79c879 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -348,6 +348,14 @@ private: const uint64_t mUniqueId; + // When buffer size is driven by the consumer and mTransformHint specifies + // a 90 or 270 degree rotation, this indicates whether the width and height + // used by dequeueBuffer will be additionally swapped. + bool mAutoPrerotation; + + // mTransformHintInUse is to cache the mTransformHint used by the producer. + uint32_t mTransformHintInUse; + }; // class BufferQueueCore } // namespace android diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index d2a47a6aa8..9ad92a6e78 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -190,6 +190,9 @@ public: // See IGraphicBufferProducer::getConsumerUsage virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + // See IGraphicBufferProducer::setAutoPrerotation + virtual status_t setAutoPrerotation(bool autoPrerotation); + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp<IBinder>& who); diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 22de751498..a558cf9e18 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -88,10 +88,13 @@ public: * DisplayEventReceiver creates and registers an event connection with * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate * or requestNextVsync to receive them. + * To receive Config Changed events specify this in the constructor. * Other events start being delivered immediately. */ explicit DisplayEventReceiver( - ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp); + ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, + ISurfaceComposer::ConfigChanged configChanged = + ISurfaceComposer::eConfigChangedSuppress); /* * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..abe1e3f6e6 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -412,6 +412,7 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; + int maxBufferCount{0}; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, @@ -629,6 +630,14 @@ public: // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; + // Enable/disable the auto prerotation at buffer allocation when the buffer + // size is driven by the consumer. + // + // When buffer size is driven by the consumer and the transform hint + // specifies a 90 or 270 degree rotation, if auto prerotation is enabled, + // the width and height used for dequeueBuffer will be additionally swapped. + virtual status_t setAutoPrerotation(bool autoPrerotation); + // Static method exports any IGraphicBufferProducer object to a parcel. It // handles null producer as well. static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e2f77365b3..c84910b6ec 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -90,6 +90,8 @@ public: eVsyncSourceSurfaceFlinger = 1 }; + enum ConfigChanged { eConfigChangedSuppress = 0, eConfigChangedDispatch = 1 }; + /* * Create a connection with SurfaceFlinger. */ @@ -97,7 +99,8 @@ public: /* return an IDisplayEventConnection */ virtual sp<IDisplayEventConnection> createDisplayEventConnection( - VsyncSource vsyncSource = eVsyncSourceApp) = 0; + VsyncSource vsyncSource = eVsyncSourceApp, + ConfigChanged configChanged = eConfigChangedSuppress) = 0; /* create a virtual display * requires ACCESS_SURFACE_FLINGER permission. diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..fe528b3711 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -230,6 +230,7 @@ private: int dispatchGetWideColorSupport(va_list args); int dispatchGetHdrSupport(va_list args); int dispatchGetConsumerUsage64(va_list args); + int dispatchSetAutoPrerotation(va_list args); bool transformToDisplayInverse(); protected: @@ -265,6 +266,7 @@ public: virtual int setAsyncMode(bool async); virtual int setSharedBufferMode(bool sharedBufferMode); virtual int setAutoRefresh(bool autoRefresh); + virtual int setAutoPrerotation(bool autoPrerotation); virtual int setBuffersDimensions(uint32_t width, uint32_t height); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); @@ -292,7 +294,8 @@ public: ui::Dataspace getBuffersDataSpace(); - static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer); + static status_t attachAndQueueBufferWithDataspace(Surface* surface, sp<GraphicBuffer> buffer, + ui::Dataspace dataspace); protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; @@ -433,6 +436,7 @@ protected: // Caches the values that have been passed to the producer. bool mSharedBufferMode; bool mAutoRefresh; + bool mAutoPrerotation; // If in shared buffer mode and auto refresh is enabled, store the shared // buffer slot and return it for all calls to queue/dequeue without going @@ -465,6 +469,7 @@ protected: bool mReportRemovedBuffers = false; std::vector<sp<GraphicBuffer>> mRemovedBuffers; + int mMaxBufferCount; }; } // namespace android diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0e17c7b015..4dda97f5e1 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -285,7 +285,7 @@ public: std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls; }; - class Transaction { + class Transaction : Parcelable { std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates; SortedVector<DisplayState > mDisplayStates; std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> @@ -325,6 +325,15 @@ public: virtual ~Transaction() = default; Transaction(Transaction const& other); + // Factory method that creates a new Transaction instance from the parcel. + static std::unique_ptr<Transaction> createFromParcel(const Parcel* parcel); + + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + + // Clears the contents of the transaction without applying it. + void clear(); + status_t apply(bool synchronous = false); // Merge another transaction in to this one, clearing other // as if it had been applied. diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 23bfc0256b..ae4a14690f 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -44,7 +44,7 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: - static sp<SurfaceControl> readFromParcel(Parcel* parcel); + static sp<SurfaceControl> readFromParcel(const Parcel* parcel); void writeToParcel(Parcel* parcel); static bool isValid(const sp<SurfaceControl>& surface) { @@ -81,7 +81,7 @@ public: status_t getLayerFrameStats(FrameStats* outStats) const; sp<SurfaceComposerClient> getClient() const; - + explicit SurfaceControl(const sp<SurfaceControl>& other); SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 119e888edb..98dc1e6337 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -169,6 +169,18 @@ TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) { ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } +TEST_F(BufferQueueTest, GetMaxBufferCountInQueueBufferOutput_Succeeds) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + mConsumer->consumerConnect(dc, false); + int bufferCount = 50; + mConsumer->setMaxBufferCount(bufferCount); + + IGraphicBufferProducer::QueueBufferOutput output; + mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output); + ASSERT_EQ(output.maxBufferCount, bufferCount); +} + TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { createBufferQueue(); sp<DummyConsumer> dc(new DummyConsumer); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 960cf1846e..7718bc1b8e 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -548,8 +548,8 @@ public: } sp<ISurfaceComposerClient> createConnection() override { return nullptr; } - sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource) - override { + sp<IDisplayEventConnection> createDisplayEventConnection( + ISurfaceComposer::VsyncSource, ISurfaceComposer::ConfigChanged) override { return nullptr; } sp<IBinder> createDisplay(const String8& /*displayName*/, @@ -1746,4 +1746,74 @@ TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) { EXPECT_EQ(-1, outDisplayPresentTime); } +TEST_F(SurfaceTest, DequeueWithConsumerDrivenSize) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setDefaultBufferSize(10, 10); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_set_buffers_dimensions(window.get(), 0, 0); + + int fence; + ANativeWindowBuffer* buffer; + + // Buffer size is driven by the consumer + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Buffer size is driven by the consumer + consumer->setDefaultBufferSize(10, 20); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Transform hint isn't synced to producer before queueBuffer or connect + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence)); + + // Transform hint is synced to producer but no auto prerotation + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Prerotation is driven by the consumer with the transform hint used by producer + native_window_set_auto_prerotation(window.get(), true); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(20, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Turn off auto prerotaton + native_window_set_auto_prerotation(window.get(), false); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Test auto prerotation bit is disabled after disconnect + native_window_set_auto_prerotation(window.get(), true); + native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + native_window_set_buffers_dimensions(window.get(), 0, 0); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); +} + } // namespace android diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index 0c22bfefed..56900c129e 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -38,29 +38,29 @@ KeyMap::KeyMap() { KeyMap::~KeyMap() { } -status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, +status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { - status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str()); + status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", - deviceIdenfifier.name.c_str(), keyLayoutName.string()); + deviceIdentifier.name.c_str(), keyLayoutName.string()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { - status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str()); + status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", - deviceIdenfifier.name.c_str(), keyLayoutName.string()); + deviceIdentifier.name.c_str(), keyCharacterMapName.string()); } } @@ -70,25 +70,25 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, } // Try searching by device identifier. - if (probeKeyMap(deviceIdenfifier, "")) { + if (probeKeyMap(deviceIdentifier, "")) { return OK; } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. - if (probeKeyMap(deviceIdenfifier, "Generic")) { + if (probeKeyMap(deviceIdentifier, "Generic")) { return OK; } // Try the Virtual key map as a last resort. - if (probeKeyMap(deviceIdenfifier, "Virtual")) { + if (probeKeyMap(deviceIdentifier, "Virtual")) { return OK; } // Give up! ALOGE("Could not determine key map for device '%s' and no default key maps were found!", - deviceIdenfifier.name.c_str()); + deviceIdentifier.name.c_str()); return NAME_NOT_FOUND; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 8435dac636..1751443419 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -262,3 +262,7 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) { return native_window_set_auto_refresh(window, autoRefresh); } + +int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation) { + return native_window_set_auto_prerotation(window, autoPrerotation); +} diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 61590e0196..8cbf0a4244 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -203,41 +203,42 @@ enum { */ enum { // clang-format off - NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */ - NATIVE_WINDOW_CONNECT = 1, /* deprecated */ - NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ - NATIVE_WINDOW_SET_CROP = 3, /* private */ - NATIVE_WINDOW_SET_BUFFER_COUNT = 4, - NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ - NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, - NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, - NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, - NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, - NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ - NATIVE_WINDOW_LOCK = 11, /* private */ - NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ - NATIVE_WINDOW_API_CONNECT = 13, /* private */ - NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ - NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ - NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */ - NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */ - NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, - NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, - NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ - NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, - NATIVE_WINDOW_SET_AUTO_REFRESH = 22, - NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, - NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, - NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, - NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, - NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, - NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, - NATIVE_WINDOW_GET_HDR_SUPPORT = 29, - NATIVE_WINDOW_SET_USAGE64 = 30, - NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, - NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, - NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, + NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */ + NATIVE_WINDOW_CONNECT = 1, /* deprecated */ + NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ + NATIVE_WINDOW_SET_CROP = 3, /* private */ + NATIVE_WINDOW_SET_BUFFER_COUNT = 4, + NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ + NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, + NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, + NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, + NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, + NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ + NATIVE_WINDOW_LOCK = 11, /* private */ + NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ + NATIVE_WINDOW_API_CONNECT = 13, /* private */ + NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ + NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ + NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */ + NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */ + NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, + NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, + NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ + NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, + NATIVE_WINDOW_SET_AUTO_REFRESH = 22, + NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, + NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, + NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, + NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, + NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, + NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, + NATIVE_WINDOW_GET_HDR_SUPPORT = 29, + NATIVE_WINDOW_SET_USAGE64 = 30, + NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, + NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, + NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, + NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, // clang-format on }; @@ -985,4 +986,18 @@ static inline int native_window_get_consumer_usage(struct ANativeWindow* window, return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage); } +/* + * native_window_set_auto_prerotation(..., autoPrerotation) + * Enable/disable the auto prerotation at buffer allocation when the buffer size + * is driven by the consumer. + * + * When buffer size is driven by the consumer and the transform hint specifies + * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and + * height used for dequeueBuffer will be additionally swapped. + */ +static inline int native_window_set_auto_prerotation(struct ANativeWindow* window, + bool autoPrerotation) { + return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation); +} + __END_DECLS diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h index 995ba44d20..500052c936 100644 --- a/libs/nativewindow/include/vndk/window.h +++ b/libs/nativewindow/include/vndk/window.h @@ -316,6 +316,15 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo */ int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh); +/* + * Enable/disable the auto prerotation at buffer allocation when the buffer size + * is driven by the consumer. + * + * When buffer size is driven by the consumer and the transform hint specifies + * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and + * height used for dequeueBuffer will be additionally swapped. + */ +int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation); /*****************************************************************************/ diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index bad8b11540..119a07dad7 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -28,6 +28,7 @@ LIBNATIVEWINDOW { ANativeWindow_queryf; # vndk ANativeWindow_queueBuffer; # vndk ANativeWindow_release; + ANativeWindow_setAutoPrerotation; # vndk ANativeWindow_setAutoRefresh; # vndk ANativeWindow_setBufferCount; # vndk ANativeWindow_setBuffersDataSpace; # introduced=28 diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 46a8e9eecf..6e7ec336e9 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -456,10 +456,6 @@ void GLESRenderEngine::primeCache() const { mFeatureFlags & USE_COLOR_MANAGEMENT); } -bool GLESRenderEngine::isCurrent() const { - return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext(); -} - base::unique_fd GLESRenderEngine::flush() { ATRACE_CALL(); if (!GLExtensions::getInstance().hasNativeFenceSync()) { @@ -795,7 +791,6 @@ status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0); uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", glStatus); @@ -1013,33 +1008,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return NO_ERROR; } -void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) { - setViewportAndProjection(Rect(vpw, vph), sourceCrop); - - if (rotation == ui::Transform::ROT_0) { - return; - } - - // Apply custom rotation to the projection. - float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f; - mat4 m = mState.projectionMatrix; - switch (rotation) { - case ui::Transform::ROT_90: - m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m; - break; - case ui::Transform::ROT_180: - m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m; - break; - case ui::Transform::ROT_270: - m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m; - break; - default: - break; - } - mState.projectionMatrix = m; -} - void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { ATRACE_CALL(); mVpWidth = viewport.getWidth(); @@ -1103,14 +1071,6 @@ void GLESRenderEngine::setupLayerTexturing(const Texture& texture) { mState.textureEnabled = true; } -void GLESRenderEngine::setupLayerBlackedOut() { - glBindTexture(GL_TEXTURE_2D, mProtectedTexName); - Texture texture(Texture::TEXTURE_2D, mProtectedTexName); - texture.setDimensions(1, 1); // FIXME: we should get that from somewhere - mState.texture = texture; - mState.textureEnabled = true; -} - void GLESRenderEngine::setColorTransform(const mat4& colorTransform) { mState.colorMatrix = colorTransform; } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index de793c2142..70b704abce 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -50,7 +50,6 @@ class GLESRenderEngine : public impl::RenderEngine { public: static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags, uint32_t imageCacheSize); - static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy, @@ -58,17 +57,7 @@ public: uint32_t imageCacheSize); ~GLESRenderEngine() override EXCLUDES(mRenderingMutex); - std::unique_ptr<Framebuffer> createFramebuffer() override; - std::unique_ptr<Image> createImage() override; - void primeCache() const override; - bool isCurrent() const override; - base::unique_fd flush() override; - bool finish() override; - bool waitFence(base::unique_fd fenceFd) override; - void clearWithColor(float red, float green, float blue, float alpha) override; - void fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; void bindExternalTextureImage(uint32_t texName, const Image& image) override; @@ -78,7 +67,6 @@ public: void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); status_t bindFrameBuffer(Framebuffer* framebuffer) override; void unbindFrameBuffer(Framebuffer* framebuffer) override; - void checkErrors() const override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; @@ -88,9 +76,7 @@ public: base::unique_fd&& bufferFence, base::unique_fd* drawFence) EXCLUDES(mRenderingMutex) override; - // internal to RenderEngine EGLDisplay getEGLDisplay() const { return mEGLDisplay; } - EGLConfig getEGLConfig() const { return mEGLConfig; } // Creates an output image for rendering to EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, bool useFramebufferCache); @@ -104,27 +90,6 @@ public: protected: Framebuffer* getFramebufferForDrawing() override; void dump(std::string& result) override; - void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) override; - void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) override; - void setupLayerTexturing(const Texture& texture) override; - void setupLayerBlackedOut() override; - void setupFillWithColor(float r, float g, float b, float a) override; - void setColorTransform(const mat4& colorTransform) override; - void disableTexturing() override; - void disableBlending() override; - void setupCornerRadiusCropSize(float width, float height) override; - - // HDR and color management related functions and state - void setSourceY410BT2020(bool enable) override; - void setSourceDataSpace(ui::Dataspace source) override; - void setOutputDataSpace(ui::Dataspace dataspace) override; - void setDisplayMaxLuminance(const float maxLuminance) override; - - // drawing - void drawMesh(const Mesh& mesh) override; - size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -136,12 +101,16 @@ private: GLES_VERSION_3_0 = 0x30000, }; + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); static GlesVersion parseGlesVersion(const char* str); static EGLContext createEglContext(EGLDisplay display, EGLConfig config, EGLContext shareContext, bool useContextPriority, Protection protection); static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection); + std::unique_ptr<Framebuffer> createFramebuffer(); + std::unique_ptr<Image> createImage(); + void checkErrors() const; void setScissor(const Rect& region); void disableScissor(); bool waitSync(EGLSyncKHR sync, EGLint flags); @@ -165,6 +134,28 @@ private: // blending is an expensive operation, we want to turn off blending when it's not necessary. void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer, const Mesh& mesh); + base::unique_fd flush(); + bool finish(); + bool waitFence(base::unique_fd fenceFd); + void clearWithColor(float red, float green, float blue, float alpha); + void fillRegionWithColor(const Region& region, float red, float green, float blue, float alpha); + void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, + const half4& color, float cornerRadius); + void setupLayerTexturing(const Texture& texture); + void setupFillWithColor(float r, float g, float b, float a); + void setColorTransform(const mat4& colorTransform); + void disableTexturing(); + void disableBlending(); + void setupCornerRadiusCropSize(float width, float height); + + // HDR and color management related functions and state + void setSourceY410BT2020(bool enable); + void setSourceDataSpace(ui::Dataspace source); + void setOutputDataSpace(ui::Dataspace dataspace); + void setDisplayMaxLuminance(const float maxLuminance); + + // drawing + void drawMesh(const Mesh& mesh); EGLDisplay mEGLDisplay; EGLConfig mEGLConfig; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index e7070041f2..8a798eefd1 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -77,10 +77,6 @@ public: // This interface, while still in use until a suitable replacement is built, // should be considered deprecated, minus some methods which still may be // used to support legacy behavior. - - virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0; - virtual std::unique_ptr<Image> createImage() = 0; - virtual void primeCache() const = 0; // dump the extension strings. always call the base class. @@ -88,24 +84,6 @@ public: virtual bool useNativeFenceSync() const = 0; virtual bool useWaitSync() const = 0; - - virtual bool isCurrent() const = 0; - - // helpers - // flush submits RenderEngine command stream for execution and returns a - // native fence fd that is signaled when the execution has completed. It - // returns -1 on errors. - virtual base::unique_fd flush() = 0; - // finish waits until RenderEngine command stream has been executed. It - // returns false on errors. - virtual bool finish() = 0; - // waitFence inserts a wait on an external fence fd to RenderEngine - // command stream. It returns false on errors. - virtual bool waitFence(base::unique_fd fenceFd) = 0; - - virtual void clearWithColor(float red, float green, float blue, float alpha) = 0; - virtual void fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) = 0; virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0; @@ -126,40 +104,6 @@ public: virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0; virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0; - // set-up - virtual void checkErrors() const = 0; - virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) = 0; - virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) = 0; - virtual void setupLayerTexturing(const Texture& texture) = 0; - virtual void setupLayerBlackedOut() = 0; - virtual void setupFillWithColor(float r, float g, float b, float a) = 0; - // Sets up the crop size for corner radius clipping. - // - // Having corner radius will force GPU composition on the layer and its children, drawing it - // with a special shader. The shader will receive the radius and the crop rectangle as input, - // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1. - // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop - // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be - // in local layer coordinate space, so we have to take the layer transform into account when - // walking up the tree. - virtual void setupCornerRadiusCropSize(float width, float height) = 0; - - // Set a color transform matrix that is applied in linear space right before OETF. - virtual void setColorTransform(const mat4& /* colorTransform */) = 0; - virtual void disableTexturing() = 0; - virtual void disableBlending() = 0; - - // HDR and color management support - virtual void setSourceY410BT2020(bool enable) = 0; - virtual void setSourceDataSpace(ui::Dataspace source) = 0; - virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0; - virtual void setDisplayMaxLuminance(const float maxLuminance) = 0; - - // drawing - virtual void drawMesh(const Mesh& mesh) = 0; - // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index e33bcfd994..f099cd2455 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -34,20 +34,12 @@ public: RenderEngine(); ~RenderEngine() override; - MOCK_METHOD0(createFramebuffer, std::unique_ptr<renderengine::Framebuffer>()); - MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>()); MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*()); MOCK_CONST_METHOD0(primeCache, void()); MOCK_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(useNativeFenceSync, bool()); MOCK_CONST_METHOD0(useWaitSync, bool()); MOCK_CONST_METHOD0(isCurrent, bool()); - MOCK_METHOD0(flush, base::unique_fd()); - MOCK_METHOD0(finish, bool()); - MOCK_METHOD1(waitFence, bool(base::unique_fd*)); - bool waitFence(base::unique_fd fd) override { return waitFence(&fd); }; - MOCK_METHOD4(clearWithColor, void(float, float, float, float)); - MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float)); MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&)); @@ -55,22 +47,6 @@ public: MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&)); MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); - MOCK_CONST_METHOD0(checkErrors, void()); - MOCK_METHOD4(setViewportAndProjection, - void(size_t, size_t, Rect, ui::Transform::orientation_flags)); - MOCK_METHOD5(setupLayerBlending, void(bool, bool, bool, const half4&, float)); - MOCK_METHOD1(setupLayerTexturing, void(const Texture&)); - MOCK_METHOD0(setupLayerBlackedOut, void()); - MOCK_METHOD4(setupFillWithColor, void(float, float, float, float)); - MOCK_METHOD2(setupCornerRadiusCropSize, void(float, float)); - MOCK_METHOD1(setColorTransform, void(const mat4&)); - MOCK_METHOD1(setSaturationMatrix, void(const mat4&)); - MOCK_METHOD0(disableTexturing, void()); - MOCK_METHOD0(disableBlending, void()); - MOCK_METHOD1(setSourceY410BT2020, void(bool)); - MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace)); - MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace)); - MOCK_METHOD1(setDisplayMaxLuminance, void(const float)); MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*)); MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*)); MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 5840d51079..96d5eb9d1f 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -94,7 +94,7 @@ SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) SensorManager::SensorManager(const String16& opPackageName) : mSensorList(nullptr), mOpPackageName(opPackageName), mDirectConnectionHandle(1) { - // okay we're not locked here, but it's not needed during construction + Mutex::Autolock _l(mLock); assertStateLocked(); } diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp index da91a979fe..1dfc1e9e88 100644 --- a/libs/ui/BufferHubBuffer.cpp +++ b/libs/ui/BufferHubBuffer.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define LOG_TAG "BufferHubBuffer" #include <poll.h> #include <android-base/unique_fd.h> diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 3fc6a2d34a..579e68e917 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -626,7 +626,7 @@ status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& si bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage, bufferHubBuffer->desc().stride); mBufferId = bufferHubBuffer->id(); - mBufferHubBuffer.reset(std::move(bufferHubBuffer.get())); + mBufferHubBuffer = std::move(bufferHubBuffer); return NO_ERROR; } diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 373fa4f221..c5170d091c 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -46,6 +46,24 @@ cc_test { cflags: ["-Wall", "-Werror"], } +// This test has a main method, and requires a separate binary to be built. +cc_test { + name: "GraphicBufferOverBinder_test", + srcs: ["GraphicBufferOverBinder_test.cpp"], + cflags: ["-Wall", "-Werror"], + header_libs: [ + "libdvr_headers", + ], + shared_libs: [ + "android.frameworks.bufferhub@1.0", + "libbinder", + "libgui", + "liblog", + "libui", + "libutils", + ], +} + cc_test { name: "BufferHub_test", header_libs: [ diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp new file mode 100644 index 0000000000..7c0a44a64f --- /dev/null +++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2019 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 "GraphicBufferOverBinder_test" + +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> +#include <gtest/gtest.h> +#include <gui/BufferQueue.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <ui/BufferHubBuffer.h> +#include <ui/GraphicBuffer.h> +#include <utils/Log.h> + +namespace android { + +constexpr uint32_t kTestWidth = 1024; +constexpr uint32_t kTestHeight = 1; +constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB; +constexpr uint32_t kTestLayerCount = 1; +constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; +static const String16 kTestServiceName = String16("GraphicBufferOverBinderTestService"); +enum GraphicBufferOverBinderTestServiceCode { + GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, + GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER, +}; + +class GraphicBufferOverBinderTestService : public BBinder { +public: + GraphicBufferOverBinderTestService() { + // GraphicBuffer + mGraphicBuffer = new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, + kTestUsage); + ALOGI("mGraphicBuffer id %" PRIi32, mGraphicBuffer->getBufferId()); + + // BufferHub-backed GraphicBuffer + std::unique_ptr<BufferHubBuffer> bufferHubBuffer = + BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, + kTestUsage, /*userMetadataSize=*/0); + mBufferhubBackedGraphicBuffer = new GraphicBuffer(std::move(bufferHubBuffer)); + if (!mBufferhubBackedGraphicBuffer->isBufferHubBuffer()) { + ALOGE("Failed to back GraphicBuffer with BufferHub."); + } + if (bufferHubBuffer != nullptr) { + ALOGE("Failed to move BufferHubBuffer to GraphicBuffer"); + } + ALOGI("mBufferhubBackedGraphicBuffer id %" PRIi32, + mBufferhubBackedGraphicBuffer->getBufferId()); + } + + ~GraphicBufferOverBinderTestService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply, + uint32_t /*flags*/ = 0) { + switch (code) { + case GRAPHIC_BUFFER: { + return reply->write(*mGraphicBuffer); + } + case GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER: { + return reply->write(*mBufferhubBackedGraphicBuffer); + } + default: + return UNKNOWN_TRANSACTION; + }; + } + +protected: + sp<GraphicBuffer> mGraphicBuffer; + sp<GraphicBuffer> mBufferhubBackedGraphicBuffer; +}; + +static int runBinderServer() { + ProcessState::self()->startThreadPool(); + + sp<IServiceManager> sm = defaultServiceManager(); + sp<GraphicBufferOverBinderTestService> service = new GraphicBufferOverBinderTestService; + sm->addService(kTestServiceName, service, false); + + ALOGI("Binder server running..."); + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + ALOGI("Binder server exiting..."); + return 0; +} + +class GraphicBufferOverBinderTest : public ::testing::TestWithParam<uint32_t> { +protected: + virtual void SetUp() { + mService = defaultServiceManager()->getService(kTestServiceName); + if (mService == nullptr) { + ALOGE("Failed to connect to the test service."); + return; + } + + ALOGI("Binder service is ready for client."); + } + + status_t GetGraphicBuffer(sp<GraphicBuffer>* outBuf, uint32_t opCode) { + Parcel data; + Parcel reply; + status_t error = mService->transact(opCode, data, &reply); + if (error != NO_ERROR) { + ALOGE("Failed to get graphic buffer over binder, error=%d.", error); + return error; + } + + *outBuf = new GraphicBuffer(); + return reply.read(**outBuf); + } + +private: + sp<IBinder> mService; +}; + +TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferOverBinder) { + sp<GraphicBuffer> gb; + EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER), OK); + EXPECT_NE(gb, nullptr); + EXPECT_FALSE(gb->isBufferHubBuffer()); + void* vaddr; + EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); + EXPECT_EQ(gb->unlock(), OK); +} + +TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferFromBufferHubBufferOverBinder) { + sp<GraphicBuffer> gb; + EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER), NO_ERROR); + EXPECT_NE(gb, nullptr); + EXPECT_TRUE(gb->isBufferHubBuffer()); + void* vaddr; + EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); + EXPECT_EQ(gb->unlock(), OK); +} + +} // namespace android + +int main(int argc, char** argv) { + pid_t pid = fork(); + if (pid == 0) { + android::ProcessState::self()->startThreadPool(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + + } else { + ALOGI("Test process pid: %d.", pid); + return android::runBinderServer(); + } +} diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp index a4b81feffc..cd03bc2be7 100644 --- a/services/bufferhub/Android.bp +++ b/services/bufferhub/Android.bp @@ -63,6 +63,7 @@ cc_binary { "libbufferhubservice", "libcrypto", "libcutils", + "libhidlbase", "libhidltransport", "libhwbinder", "liblog", diff --git a/services/gpuservice/OWNERS b/services/gpuservice/OWNERS new file mode 100644 index 0000000000..5d028393f6 --- /dev/null +++ b/services/gpuservice/OWNERS @@ -0,0 +1,3 @@ +chrisforbes@google.com +lpy@google.com +zzyiwei@google.com diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 6a7f2797f4..7c061c5857 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -276,7 +276,7 @@ void MotionClassifier::enqueueEvent(ClassifierEvent&& event) { bool eventAdded = mEvents.push(std::move(event)); if (!eventAdded) { // If the queue is full, suspect the HAL is slow in processing the events. - ALOGE("Dropped event with eventTime %" PRId64, event.args->eventTime); + ALOGE("Could not add the event to the queue. Resetting"); reset(); } } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 9aa4e85e2f..6e953f4af6 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -149,13 +149,14 @@ filegroup { "Scheduler/DispSyncSource.cpp", "Scheduler/EventControlThread.cpp", "Scheduler/EventThread.cpp", - "Scheduler/IdleTimer.cpp", + "Scheduler/OneShotTimer.cpp", "Scheduler/LayerHistory.cpp", "Scheduler/LayerInfo.cpp", "Scheduler/MessageQueue.cpp", + "Scheduler/PhaseOffsets.cpp", "Scheduler/Scheduler.cpp", "Scheduler/SchedulerUtils.cpp", - "Scheduler/PhaseOffsets.cpp", + "Scheduler/VSyncModulator.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceInterceptor.cpp", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 9d723998c4..f51fbb45f6 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -19,9 +19,7 @@ #define LOG_TAG "BufferLayer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <cmath> -#include <cstdlib> -#include <mutex> +#include "BufferLayer.h" #include <compositionengine/CompositionEngine.h> #include <compositionengine/Display.h> @@ -45,11 +43,14 @@ #include <utils/StopWatch.h> #include <utils/Trace.h> -#include "BufferLayer.h" +#include <cmath> +#include <cstdlib> +#include <mutex> +#include <sstream> + #include "Colorizer.h" #include "DisplayDevice.h" #include "LayerRejecter.h" - #include "TimeStats/TimeStats.h" namespace android { @@ -525,6 +526,9 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) } if ((*point)->getFrameNumber() <= mCurrentFrameNumber) { + std::stringstream ss; + ss << "Dropping sync point " << (*point)->getFrameNumber(); + ATRACE_NAME(ss.str().c_str()); point = mLocalSyncPoints.erase(point); } else { ++point; diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 6709fb4b48..096cd1a9cc 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -419,30 +419,6 @@ std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const { return mCurrentFenceTime; } -status_t BufferLayerConsumer::doFenceWaitLocked() const { - if (mCurrentFence->isValid()) { - if (mRE.useWaitSync()) { - base::unique_fd fenceFd(mCurrentFence->dup()); - if (fenceFd == -1) { - BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno); - return -errno; - } - if (!mRE.waitFence(std::move(fenceFd))) { - BLC_LOGE("doFenceWait: failed to wait on fence fd"); - return UNKNOWN_ERROR; - } - } else { - status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked"); - if (err != NO_ERROR) { - BLC_LOGE("doFenceWait: error waiting for fence: %d", err); - return err; - } - } - } - - return NO_ERROR; -} - void BufferLayerConsumer::freeBufferLocked(int slotIndex) { BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); std::lock_guard<std::mutex> lock(mImagesMutex); diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index e3f6100c35..144686c83d 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -252,11 +252,6 @@ private: // mCurrentTextureImage must not be nullptr. void computeCurrentTransformMatrixLocked(); - // doFenceWaitLocked inserts a wait command into the RenderEngine command - // stream to ensure that it is safe for future RenderEngine commands to - // access the current texture buffer. - status_t doFenceWaitLocked() const; - // getCurrentCropLocked returns the cropping rectangle of the current buffer. Rect getCurrentCropLocked() const; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 57f1008e85..d6853661a5 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -201,7 +201,7 @@ uint64_t BufferQueueLayer::getFrameNumber() const { uint64_t frameNumber = mQueueItems[0].mFrameNumber; // The head of the queue will be dropped if there are signaled and timely frames behind it - nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime(); + nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime(); if (isRemovedFromCurrentState()) { expectedPresentTime = 0; @@ -279,7 +279,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode, getTransformToDisplayInverse(), mFreezeGeometryUpdates); - nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime(); + nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime(); if (isRemovedFromCurrentState()) { expectedPresentTime = 0; diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 482c723a15..6bfd302b5c 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -87,11 +87,18 @@ status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32 LayerMetadata metadata, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) { if (mFlinger->authenticateSurfaceTexture(parent) == false) { + ALOGE("failed to authenticate surface texture"); + // The extra parent layer check below before returning is to help with debugging + // b/134888387. Once the bug is fixed the check can be deleted. + if ((static_cast<MonitoredProducer*>(parent.get()))->getLayer() == nullptr) { + ALOGE("failed to find parent layer"); + } return BAD_VALUE; } const auto& layer = (static_cast<MonitoredProducer*>(parent.get()))->getLayer(); if (layer == nullptr) { + ALOGE("failed to find parent layer"); return BAD_VALUE; } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index e21128ca81..9bff73e950 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -83,10 +83,6 @@ public: // Called after the HWC calls are made to present the display virtual void onPresentDisplayCompleted() = 0; - // Called to set the viewport and projection state for rendering into this - // surface - virtual void setViewportAndProjection() = 0; - // Called after the surface has been rendering to signal the surface should // be made ready for displaying virtual void flip() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index 0f57315eb6..e4c9c80429 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -56,7 +56,6 @@ public: sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd&& readyFence) override; void onPresentDisplayCompleted() override; - void setViewportAndProjection() override; void flip() override; // Debugging diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index ca2299aa26..146a2eae64 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -41,7 +41,6 @@ public: MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd&&)); MOCK_METHOD0(onPresentDisplayCompleted, void()); - MOCK_METHOD0(setViewportAndProjection, void()); MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 3fcd9d155d..8a91316e65 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -215,13 +215,6 @@ void RenderSurface::onPresentDisplayCompleted() { mDisplaySurface->onFrameCommitted(); } -void RenderSurface::setViewportAndProjection() { - auto& renderEngine = mCompositionEngine.getRenderEngine(); - Rect sourceCrop = Rect(mSize); - renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop, - ui::Transform::ROT_0); -} - void RenderSurface::flip() { mPageFlipCount++; } diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index f75a4dcb85..87419ea6a8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -364,20 +364,6 @@ TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) { } /* ------------------------------------------------------------------------ - * RenderSurface::setViewportAndProjection() - */ - -TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) { - mSurface.setSizeForTest(ui::Size(100, 200)); - - EXPECT_CALL(mRenderEngine, - setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0)) - .Times(1); - - mSurface.setViewportAndProjection(); -} - -/* ------------------------------------------------------------------------ * RenderSurface::flip() */ diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index cc5a5b5729..7f47a2ecd4 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -24,6 +24,7 @@ #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <gui/BufferQueue.h> +#include <hidl/HidlTransportSupport.h> #include <hidl/HidlTransportUtils.h> namespace android { @@ -229,6 +230,7 @@ std::string Composer::dumpDebugInfo() void Composer::registerCallback(const sp<IComposerCallback>& callback) { + android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2); auto ret = mClient->registerCallback(callback); if (!ret.isOk()) { ALOGE("failed to register IComposerCallback"); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index cae1b46c57..83ab5cfce2 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -19,12 +19,7 @@ #define LOG_TAG "Layer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <math.h> -#include <stdint.h> -#include <stdlib.h> -#include <sys/types.h> -#include <algorithm> -#include <mutex> +#include "Layer.h" #include <android-base/stringprintf.h> #include <compositionengine/Display.h> @@ -39,7 +34,11 @@ #include <gui/BufferItem.h> #include <gui/LayerDebugInfo.h> #include <gui/Surface.h> +#include <math.h> #include <renderengine/RenderEngine.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> #include <ui/DebugUtils.h> #include <ui/GraphicBuffer.h> #include <ui/PixelFormat.h> @@ -49,12 +48,15 @@ #include <utils/StopWatch.h> #include <utils/Trace.h> +#include <algorithm> +#include <mutex> +#include <sstream> + #include "BufferLayer.h" #include "ColorLayer.h" #include "Colorizer.h" #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" -#include "Layer.h" #include "LayerProtoHelper.h" #include "LayerRejecter.h" #include "MonitoredProducer.h" @@ -617,32 +619,6 @@ bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) { // local state // ---------------------------------------------------------------------------- -void Layer::computeGeometry(const RenderArea& renderArea, - renderengine::Mesh& mesh, - bool useIdentityTransform) const { - const ui::Transform renderAreaTransform(renderArea.getTransform()); - FloatRect win = getBounds(); - - vec2 lt = vec2(win.left, win.top); - vec2 lb = vec2(win.left, win.bottom); - vec2 rb = vec2(win.right, win.bottom); - vec2 rt = vec2(win.right, win.top); - - ui::Transform layerTransform = getTransform(); - if (!useIdentityTransform) { - lt = layerTransform.transform(lt); - lb = layerTransform.transform(lb); - rb = layerTransform.transform(rb); - rt = layerTransform.transform(rt); - } - - renderengine::Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - position[0] = renderAreaTransform.transform(lt); - position[1] = renderAreaTransform.transform(lb); - position[2] = renderAreaTransform.transform(rb); - position[3] = renderAreaTransform.transform(rt); -} - bool Layer::isSecure() const { const State& s(mDrawingState); return (s.flags & layer_state_t::eLayerSecure); @@ -677,6 +653,7 @@ void Layer::pushPendingState() { if (!mCurrentState.modified) { return; } + ATRACE_CALL(); // If this transaction is waiting on the receipt of a frame, generate a sync // point and send it to the remote layer. @@ -693,6 +670,9 @@ void Layer::pushPendingState() { } else { auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy, this); if (barrierLayer->addSyncPoint(syncPoint)) { + std::stringstream ss; + ss << "Adding sync point " << mCurrentState.frameNumber_legacy; + ATRACE_NAME(ss.str().c_str()); mRemoteSyncPoints.push_back(std::move(syncPoint)); } else { // We already missed the frame we're supposed to synchronize @@ -710,6 +690,7 @@ void Layer::pushPendingState() { } void Layer::popPendingState(State* stateToCommit) { + ATRACE_CALL(); *stateToCommit = mPendingStates[0]; mPendingStates.removeAt(0); @@ -741,6 +722,7 @@ bool Layer::applyPendingStates(State* stateToCommit) { } if (mRemoteSyncPoints.front()->frameIsAvailable()) { + ATRACE_NAME("frameIsAvailable"); // Apply the state update popPendingState(stateToCommit); stateUpdateAvailable = true; @@ -749,6 +731,7 @@ bool Layer::applyPendingStates(State* stateToCommit) { mRemoteSyncPoints.front()->setTransactionApplied(); mRemoteSyncPoints.pop_front(); } else { + ATRACE_NAME("!frameIsAvailable"); break; } } else { @@ -1195,6 +1178,7 @@ uint32_t Layer::getLayerStack() const { } void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) { + ATRACE_CALL(); mCurrentState.barrierLayer_legacy = barrierLayer; mCurrentState.frameNumber_legacy = frameNumber; // We don't set eTransactionNeeded, because just receiving a deferral diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 6db6beb4f6..8a4d87f889 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -357,8 +357,6 @@ public: return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay); } - void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh, - bool useIdentityTransform) const; FloatRect getBounds(const Region& activeTransparentRegion) const; FloatRect getBounds() const; diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index c60421b538..7a959f7b19 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -154,6 +154,10 @@ status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const { return mProducer->getConsumerUsage(outUsage); } +status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) { + return mProducer->setAutoPrerotation(autoPrerotation); +} + IBinder* MonitoredProducer::onAsBinder() { return this; } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index d346f821d3..788919b3da 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -70,6 +70,7 @@ public: virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override; virtual status_t getUniqueId(uint64_t* outId) const override; virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + virtual status_t setAutoPrerotation(bool autoPrerotation) override; // The Layer which created this producer, and on which queued Buffer's will be displayed. sp<Layer> getLayer() const; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 66906e950c..72bbf5dc26 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -258,7 +258,7 @@ void RegionSamplingThread::binderDied(const wp<IBinder>& who) { namespace { // Using Rec. 709 primaries -float getLuma(float r, float g, float b) { +inline float getLuma(float r, float g, float b) { constexpr auto rec709_red_primary = 0.2126f; constexpr auto rec709_green_primary = 0.7152f; constexpr auto rec709_blue_primary = 0.0722f; @@ -293,10 +293,10 @@ float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t st const uint32_t* rowBase = data + row * stride; for (int32_t column = area.left; column < area.right; ++column) { uint32_t pixel = rowBase[column]; - const float r = (pixel & 0xFF) / 255.0f; - const float g = ((pixel >> 8) & 0xFF) / 255.0f; - const float b = ((pixel >> 16) & 0xFF) / 255.0f; - const uint8_t luma = std::round(getLuma(r, g, b) * 255.0f); + const float r = pixel & 0xFF; + const float g = (pixel >> 8) & 0xFF; + const float b = (pixel >> 16) & 0xFF; + const uint8_t luma = std::round(getLuma(r, g, b)); ++brightnessBuckets[luma]; if (brightnessBuckets[luma] > majoritySampleNum) return luma / 255.0f; } @@ -342,9 +342,19 @@ void RegionSamplingThread::captureSample() { } const auto device = mFlinger.getDefaultDisplayDevice(); - const auto display = device->getCompositionDisplay(); - const auto state = display->getState(); - const auto orientation = static_cast<ui::Transform::orientation_flags>(state.orientation); + const auto orientation = [](uint32_t orientation) { + switch (orientation) { + default: + case DisplayState::eOrientationDefault: + return ui::Transform::ROT_0; + case DisplayState::eOrientation90: + return ui::Transform::ROT_90; + case DisplayState::eOrientation180: + return ui::Transform::ROT_180; + case DisplayState::eOrientation270: + return ui::Transform::ROT_270; + } + }(device->getOrientation()); std::vector<RegionSamplingThread::Descriptor> descriptors; Region sampleRegion; diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 3c6fcf3872..ac7339c42a 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -27,7 +27,7 @@ #include <ui/GraphicBuffer.h> #include <ui/Rect.h> #include <utils/StrongPointer.h> -#include "Scheduler/IdleTimer.h" +#include "Scheduler/OneShotTimer.h" namespace android { @@ -107,7 +107,7 @@ private: SurfaceFlinger& mFlinger; Scheduler& mScheduler; const TimingTunables mTunables; - scheduler::IdleTimer mIdleTimer; + scheduler::OneShotTimer mIdleTimer; std::unique_ptr<SamplingOffsetCallback> const mPhaseCallback; diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index 95ff9d0c73..83fd42b43f 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -92,9 +92,12 @@ public: mPeriod = period; if (!mModelLocked && referenceTimeChanged) { for (auto& eventListener : mEventListeners) { - eventListener.mHasFired = false; - eventListener.mLastEventTime = - mReferenceTime - mPeriod + mPhase + eventListener.mPhase; + eventListener.mLastEventTime = mReferenceTime + mPhase + eventListener.mPhase; + // If mLastEventTime is after mReferenceTime (can happen when positive phase offsets + // are used) we treat it as like it happened in previous period. + if (eventListener.mLastEventTime > mReferenceTime) { + eventListener.mLastEventTime -= mPeriod; + } } } if (mTraceDetailedInfo) { @@ -123,13 +126,6 @@ public: void unlockModel() { Mutex::Autolock lock(mMutex); - if (mModelLocked) { - for (auto& eventListener : mEventListeners) { - if (eventListener.mLastEventTime > mReferenceTime) { - eventListener.mHasFired = true; - } - } - } mModelLocked = false; ATRACE_INT("DispSync:ModelLocked", mModelLocked); } @@ -259,10 +255,6 @@ public: listener.mLastCallbackTime = lastCallbackTime; } - if (!mModelLocked && listener.mLastEventTime > mReferenceTime) { - listener.mHasFired = true; - } - mEventListeners.push_back(listener); mCond.signal(); @@ -300,12 +292,8 @@ public: // new offset to allow for a seamless offset change without double-firing or // skipping. nsecs_t diff = oldPhase - phase; - if (diff > mPeriod / 2) { - diff -= mPeriod; - } else if (diff < -mPeriod / 2) { - diff += mPeriod; - } eventListener.mLastEventTime -= diff; + eventListener.mLastCallbackTime -= diff; mCond.signal(); return NO_ERROR; } @@ -320,7 +308,6 @@ private: nsecs_t mLastEventTime; nsecs_t mLastCallbackTime; DispSync::Callback* mCallback; - bool mHasFired = false; }; struct CallbackInvocation { @@ -368,12 +355,7 @@ private: eventListener.mName); continue; } - if (eventListener.mHasFired && !mModelLocked) { - eventListener.mLastEventTime = t; - ALOGV("[%s] [%s] Skipping event due to already firing", mName, - eventListener.mName); - continue; - } + CallbackInvocation ci; ci.mCallback = eventListener.mCallback; ci.mEventTime = t; @@ -382,7 +364,6 @@ private: callbackInvocations.push_back(ci); eventListener.mLastEventTime = t; eventListener.mLastCallbackTime = now; - eventListener.mHasFired = true; } } diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 00948aedb4..026b55707c 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -27,18 +27,23 @@ namespace android { -DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, +DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, + nsecs_t offsetThresholdForNextVsync, bool traceVsync, const char* name) : mName(name), mTraceVsync(traceVsync), mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)), mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)), + mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)), + mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)), mDispSync(dispSync), - mPhaseOffset(phaseOffset) {} + mPhaseOffset(phaseOffset), + mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {} void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); if (enable) { + tracePhaseOffset(); status_t err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast<DispSync::Callback*>(this), mLastCallbackTime); @@ -64,16 +69,17 @@ void DispSyncSource::setCallback(VSyncSource::Callback* callback) { void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { std::lock_guard lock(mVsyncMutex); - - // Normalize phaseOffset to [0, period) - auto period = mDispSync->getPeriod(); - phaseOffset %= period; - if (phaseOffset < 0) { - // If we're here, then phaseOffset is in (-period, 0). After this - // operation, it will be in (0, period) - phaseOffset += period; + const nsecs_t period = mDispSync->getPeriod(); + // Check if offset should be handled as negative + if (phaseOffset >= mOffsetThresholdForNextVsync) { + phaseOffset -= period; } + + // Normalize phaseOffset to [-period, period) + const int numPeriods = phaseOffset / period; + phaseOffset -= numPeriods * period; mPhaseOffset = phaseOffset; + tracePhaseOffset(); // If we're not enabled, we don't need to mess with the listeners if (!mEnabled) { @@ -92,11 +98,11 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { { std::lock_guard lock(mCallbackMutex); callback = mCallback; + } - if (mTraceVsync) { - mValue = (mValue + 1) % 2; - ATRACE_INT(mVsyncEventLabel.c_str(), mValue); - } + if (mTraceVsync) { + mValue = (mValue + 1) % 2; + ATRACE_INT(mVsyncEventLabel.c_str(), mValue); } if (callback != nullptr) { @@ -104,4 +110,14 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { } } -} // namespace android
\ No newline at end of file +void DispSyncSource::tracePhaseOffset() { + if (mPhaseOffset > 0) { + ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset); + ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0); + } else { + ATRACE_INT(mVsyncOffsetLabel.c_str(), 0); + ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset); + } +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 4759699c5e..50560a5a2b 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -25,7 +25,8 @@ namespace android { class DispSyncSource final : public VSyncSource, private DispSync::Callback { public: - DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name); + DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync, + bool traceVsync, const char* name); ~DispSyncSource() override = default; @@ -38,12 +39,16 @@ private: // The following method is the implementation of the DispSync::Callback. virtual void onDispSyncEvent(nsecs_t when); + void tracePhaseOffset() REQUIRES(mVsyncMutex); + const char* const mName; int mValue = 0; const bool mTraceVsync; const std::string mVsyncOnLabel; const std::string mVsyncEventLabel; + const std::string mVsyncOffsetLabel; + const std::string mVsyncNegativeOffsetLabel; nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0; DispSync* mDispSync; @@ -53,7 +58,8 @@ private: std::mutex mVsyncMutex; nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex); + const nsecs_t mOffsetThresholdForNextVsync; bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 05bad4ddd8..9d1f777859 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -76,6 +76,10 @@ std::string toString(const DisplayEventReceiver::Event& event) { return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u}", event.header.displayId, event.vsync.count); + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + return StringPrintf("ConfigChanged{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT + ", configId=%u}", + event.header.displayId, event.config.configId); default: return "Event{}"; } @@ -107,8 +111,10 @@ DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32 } // namespace EventThreadConnection::EventThreadConnection(EventThread* eventThread, - ResyncCallback resyncCallback) + ResyncCallback resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) : resyncCallback(std::move(resyncCallback)), + configChanged(configChanged), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {} @@ -203,8 +209,10 @@ void EventThread::setPhaseOffset(nsecs_t phaseOffset) { mVSyncSource->setPhaseOffset(phaseOffset); } -sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const { - return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback)); +sp<EventThreadConnection> EventThread::createEventConnection( + ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const { + return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback), + configChanged); } status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) { @@ -398,9 +406,11 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, const sp<EventThreadConnection>& connection) const { switch (event.header.type) { case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: - case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: return true; + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch; + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: switch (connection->vsyncRequest) { case VSyncRequest::None: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 61530c62e5..dd23b88726 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -69,7 +69,8 @@ public: class EventThreadConnection : public BnDisplayEventConnection { public: - EventThreadConnection(EventThread*, ResyncCallback); + EventThreadConnection(EventThread*, ResyncCallback, + ISurfaceComposer::ConfigChanged configChanged); virtual ~EventThreadConnection(); virtual status_t postEvent(const DisplayEventReceiver::Event& event); @@ -82,6 +83,7 @@ public: const ResyncCallback resyncCallback; VSyncRequest vsyncRequest = VSyncRequest::None; + const ISurfaceComposer::ConfigChanged configChanged; private: virtual void onFirstRef(); @@ -93,7 +95,8 @@ class EventThread { public: virtual ~EventThread(); - virtual sp<EventThreadConnection> createEventConnection(ResyncCallback) const = 0; + virtual sp<EventThreadConnection> createEventConnection( + ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const = 0; // called before the screen is turned off from main thread virtual void onScreenReleased() = 0; @@ -128,7 +131,8 @@ public: EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName); ~EventThread(); - sp<EventThreadConnection> createEventConnection(ResyncCallback) const override; + sp<EventThreadConnection> createEventConnection( + ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const override; status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override; void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 1db43a32cd..f80c2336f7 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -46,11 +46,13 @@ LayerHistory::LayerHistory() { LayerHistory::~LayerHistory() = default; std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name, + float minRefreshRate, float maxRefreshRate) { const int64_t id = sNextId++; std::lock_guard lock(mLock); - mInactiveLayerInfos.emplace(id, std::make_shared<LayerInfo>(name, maxRefreshRate)); + mInactiveLayerInfos.emplace(id, + std::make_shared<LayerInfo>(name, minRefreshRate, maxRefreshRate)); return std::make_unique<LayerHistory::LayerHandle>(*this, id); } @@ -173,5 +175,18 @@ void LayerHistory::removeIrrelevantLayers() { } } +void LayerHistory::clearHistory() { + std::lock_guard lock(mLock); + + auto it = mActiveLayerInfos.begin(); + while (it != mActiveLayerInfos.end()) { + auto id = it->first; + auto layerInfo = it->second; + layerInfo->clearHistory(); + mInactiveLayerInfos.insert({id, layerInfo}); + it = mActiveLayerInfos.erase(it); + } +} + } // namespace scheduler } // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index adc5ce5f64..5598cc1cf5 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -53,7 +53,8 @@ public: ~LayerHistory(); // When the layer is first created, register it. - std::unique_ptr<LayerHandle> createLayer(const std::string name, float maxRefreshRate); + std::unique_ptr<LayerHandle> createLayer(const std::string name, float minRefreshRate, + float maxRefreshRate); // Method for inserting layers and their requested present time into the unordered map. void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime, bool isHdr); @@ -64,6 +65,9 @@ public: // layers. See go/content-fps-detection-in-scheduler for more information. std::pair<float, bool> getDesiredRefreshRateAndHDR(); + // Clears all layer history. + void clearHistory(); + // Removes the handle and the object from the map. void destroyLayer(const int64_t id); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 95d7d31564..beddb9be61 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -24,9 +24,10 @@ namespace android { namespace scheduler { -LayerInfo::LayerInfo(const std::string name, float maxRefreshRate) +LayerInfo::LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate) : mName(name), mMinRefreshDuration(1e9f / maxRefreshRate), + mLowActivityRefreshDuration(1e9f / minRefreshRate), mRefreshRateHistory(mMinRefreshDuration) {} LayerInfo::~LayerInfo() = default; @@ -38,10 +39,16 @@ void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) { mLastUpdatedTime = std::max(lastPresentTime, systemTime()); mPresentTimeHistory.insertPresentTime(mLastUpdatedTime); + if (mLastPresentTime == 0) { + // First frame + mLastPresentTime = lastPresentTime; + return; + } + const nsecs_t timeDiff = lastPresentTime - mLastPresentTime; mLastPresentTime = lastPresentTime; // Ignore time diff that are too high - those are stale values - if (timeDiff > TIME_EPSILON_NS.count()) return; + if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return; const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration; mRefreshRateHistory.insertRefreshRate(refreshDuration); } diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 02b6aefa2b..2c50053ebd 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -55,7 +55,7 @@ class LayerInfo { float getRefreshRateAvg() const { nsecs_t refreshDuration = mMinRefreshDuration; - if (mElements.size() == HISTORY_SIZE) { + if (mElements.size() > 0) { refreshDuration = scheduler::calculate_mean(mElements); } @@ -86,13 +86,42 @@ class LayerInfo { // Checks whether the present time that was inserted HISTORY_SIZE ago is within a // certain threshold: TIME_EPSILON_NS. bool isRelevant() const { - const int64_t obsoleteEpsilon = systemTime() - scheduler::TIME_EPSILON_NS.count(); - // The layer had to publish at least HISTORY_SIZE of updates, and the first - // update should not be older than TIME_EPSILON_NS nanoseconds. - if (mElements.size() == HISTORY_SIZE && - mElements.at(HISTORY_SIZE - 1) > obsoleteEpsilon) { + if (mElements.size() < 2) { + return false; + } + + // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates + if (mElements.size() != HISTORY_SIZE && + mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) { + return false; + } + + // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds. + const int64_t obsoleteEpsilon = + systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count(); + if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) { + return false; + } + + return true; + } + + bool isLowActivityLayer() const { + // We want to make sure that we received more than two frames from the layer + // in order to check low activity. + if (mElements.size() < 2) { + return false; + } + + const int64_t obsoleteEpsilon = + systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count(); + // Check the frame before last to determine whether there is low activity. + // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending + // infrequent updates. + if (mElements.at(mElements.size() - 2) < obsoleteEpsilon) { return true; } + return false; } @@ -101,10 +130,11 @@ class LayerInfo { private: std::deque<nsecs_t> mElements; static constexpr size_t HISTORY_SIZE = 10; + static constexpr std::chrono::nanoseconds HISTORY_TIME = 500ms; }; public: - LayerInfo(const std::string name, float maxRefreshRate); + LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate); ~LayerInfo(); LayerInfo(const LayerInfo&) = delete; @@ -134,6 +164,10 @@ public: // Calculate the average refresh rate. float getDesiredRefreshRate() const { std::lock_guard lock(mLock); + + if (mPresentTimeHistory.isLowActivityLayer()) { + return 1e9f / mLowActivityRefreshDuration; + } return mRefreshRateHistory.getRefreshRateAvg(); } @@ -165,6 +199,7 @@ public: private: const std::string mName; const nsecs_t mMinRefreshDuration; + const nsecs_t mLowActivityRefreshDuration; mutable std::mutex mLock; nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0; nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index baf900df52..fcb307f213 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -96,7 +96,8 @@ void MessageQueue::setEventThread(android::EventThread* eventThread, } mEventThread = eventThread; - mEvents = eventThread->createEventConnection(std::move(resyncCallback)); + mEvents = eventThread->createEventConnection(std::move(resyncCallback), + ISurfaceComposer::eConfigChangedSuppress); mEvents->stealReceiveChannel(&mEventTube); mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver, this); diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp index 37fdfc7c62..4870a3bbdd 100644 --- a/services/surfaceflinger/Scheduler/IdleTimer.cpp +++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "IdleTimer.h" +#include "OneShotTimer.h" #include <chrono> #include <thread> @@ -22,23 +22,23 @@ namespace android { namespace scheduler { -IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback) +OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + const TimeoutCallback& timeoutCallback) : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {} -IdleTimer::~IdleTimer() { +OneShotTimer::~OneShotTimer() { stop(); } -void IdleTimer::start() { +void OneShotTimer::start() { { std::lock_guard<std::mutex> lock(mMutex); mState = TimerState::RESET; } - mThread = std::thread(&IdleTimer::loop, this); + mThread = std::thread(&OneShotTimer::loop, this); } -void IdleTimer::stop() { +void OneShotTimer::stop() { { std::lock_guard<std::mutex> lock(mMutex); mState = TimerState::STOPPED; @@ -49,7 +49,7 @@ void IdleTimer::stop() { } } -void IdleTimer::loop() { +void OneShotTimer::loop() { while (true) { bool triggerReset = false; bool triggerTimeout = false; @@ -100,7 +100,7 @@ void IdleTimer::loop() { } } // namespace scheduler -void IdleTimer::reset() { +void OneShotTimer::reset() { { std::lock_guard<std::mutex> lock(mMutex); mState = TimerState::RESET; diff --git a/services/surfaceflinger/Scheduler/IdleTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h index 2646688860..fd1aa02226 100644 --- a/services/surfaceflinger/Scheduler/IdleTimer.h +++ b/services/surfaceflinger/Scheduler/OneShotTimer.h @@ -29,15 +29,15 @@ namespace scheduler { * Class that sets off a timer for a given interval, and fires a callback when the * interval expires. */ -class IdleTimer { +class OneShotTimer { public: using Interval = std::chrono::milliseconds; using ResetCallback = std::function<void()>; using TimeoutCallback = std::function<void()>; - IdleTimer(const Interval& interval, const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback); - ~IdleTimer(); + OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + const TimeoutCallback& timeoutCallback); + ~OneShotTimer(); // Initializes and turns on the idle timer. void start(); diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 276bce1f89..8a2604f4a3 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -25,6 +25,7 @@ using namespace android::sysprop; namespace scheduler { +using RefreshRateType = RefreshRateConfigs::RefreshRateType; PhaseOffsets::~PhaseOffsets() = default; namespace impl { @@ -72,25 +73,32 @@ PhaseOffsets::PhaseOffsets() { property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1"); const int phaseOffsetThresholdForNextVsyncNs = atoi(value); - mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs - : sfVsyncPhaseOffsetNs, - earlyAppOffsetNs != -1 ? earlyAppOffsetNs - : vsyncPhaseOffsetNs}; - mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs - : sfVsyncPhaseOffsetNs, - earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs - : vsyncPhaseOffsetNs}; - mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; - - mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs - : highFpsLateAppOffsetNs}; - mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs - : highFpsLateAppOffsetNs}; - mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; + Offsets defaultOffsets; + Offsets highFpsOffsets; + defaultOffsets.early = {RefreshRateType::DEFAULT, + earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, + earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs}; + defaultOffsets.earlyGl = {RefreshRateType::DEFAULT, + earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs, + earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs}; + defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; + + highFpsOffsets.early = {RefreshRateType::PERFORMANCE, + highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs + : highFpsLateSfOffsetNs, + highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs + : highFpsLateAppOffsetNs}; + highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE, + highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs + : highFpsLateSfOffsetNs, + highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs + : highFpsLateAppOffsetNs}; + highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, + highFpsLateAppOffsetNs}; + + mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); + mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); + mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 ? phaseOffsetThresholdForNextVsyncNs @@ -99,12 +107,7 @@ PhaseOffsets::PhaseOffsets() { PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const { - switch (refreshRateType) { - case RefreshRateConfigs::RefreshRateType::PERFORMANCE: - return mHighRefreshRateOffsets; - default: - return mDefaultRefreshRateOffsets; - } + return mOffsets.at(refreshRateType); } void PhaseOffsets::dump(std::string& result) const { diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index dc71e6eb60..2b5c2f10f1 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -17,6 +17,7 @@ #pragma once #include <cinttypes> +#include <unordered_map> #include "RefreshRateConfigs.h" #include "VSyncModulator.h" @@ -79,14 +80,10 @@ public: void dump(std::string& result) const override; private: - Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; } - Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; } - std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType = RefreshRateConfigs::RefreshRateType::DEFAULT; - Offsets mDefaultRefreshRateOffsets; - Offsets mHighRefreshRateOffsets; + std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets; nsecs_t mOffsetThresholdForNextVsync; }; } // namespace impl diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index e2a348e146..65f0e40ffe 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -38,9 +38,9 @@ #include "DispSyncSource.h" #include "EventControlThread.h" #include "EventThread.h" -#include "IdleTimer.h" #include "InjectVSyncSource.h" #include "LayerInfo.h" +#include "OneShotTimer.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" @@ -86,50 +86,47 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, if (mSetIdleTimerMs > 0) { if (mSupportKernelTimer) { - mIdleTimer = - std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds( - mSetIdleTimerMs), - [this] { resetKernelTimerCallback(); }, - [this] { - expiredKernelTimerCallback(); - }); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>( + std::chrono::milliseconds(mSetIdleTimerMs), + [this] { resetKernelTimerCallback(); }, + [this] { expiredKernelTimerCallback(); }); } else { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds( - mSetIdleTimerMs), - [this] { resetTimerCallback(); }, - [this] { expiredTimerCallback(); }); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>( + std::chrono::milliseconds(mSetIdleTimerMs), [this] { resetTimerCallback(); }, + [this] { expiredTimerCallback(); }); } mIdleTimer->start(); } if (mSetTouchTimerMs > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that - mTouchTimer = - std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetTouchTimerMs), - [this] { resetTouchTimerCallback(); }, - [this] { expiredTouchTimerCallback(); }); + mTouchTimer = std::make_unique<scheduler::OneShotTimer>( + std::chrono::milliseconds(mSetTouchTimerMs), [this] { resetTouchTimerCallback(); }, + [this] { expiredTouchTimerCallback(); }); mTouchTimer->start(); } } Scheduler::~Scheduler() { - // Ensure the IdleTimer thread is joined before we start destroying state. + // Ensure the OneShotTimer threads are joined before we start destroying state. mTouchTimer.reset(); mIdleTimer.reset(); } sp<Scheduler::ConnectionHandle> Scheduler::createConnection( - const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback, + const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, + ResyncCallback resyncCallback, impl::EventThread::InterceptVSyncsCallback interceptCallback) { const int64_t id = sNextId++; ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id); std::unique_ptr<EventThread> eventThread = makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, - std::move(interceptCallback)); + offsetThresholdForNextVsync, std::move(interceptCallback)); auto eventThreadConnection = - createConnectionInternal(eventThread.get(), std::move(resyncCallback)); + createConnectionInternal(eventThread.get(), std::move(resyncCallback), + ISurfaceComposer::eConfigChangedSuppress); mConnections.emplace(id, std::make_unique<Connection>(new ConnectionHandle(id), eventThreadConnection, @@ -138,24 +135,28 @@ sp<Scheduler::ConnectionHandle> Scheduler::createConnection( } std::unique_ptr<EventThread> Scheduler::makeEventThread( - const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs, + const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback interceptCallback) { std::unique_ptr<VSyncSource> eventThreadSource = - std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName); + std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync, + true, connectionName); return std::make_unique<impl::EventThread>(std::move(eventThreadSource), std::move(interceptCallback), connectionName); } -sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread, - ResyncCallback&& resyncCallback) { - return eventThread->createEventConnection(std::move(resyncCallback)); +sp<EventThreadConnection> Scheduler::createConnectionInternal( + EventThread* eventThread, ResyncCallback&& resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) { + return eventThread->createEventConnection(std::move(resyncCallback), configChanged); } sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection( - const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) { + const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) { RETURN_VALUE_IF_INVALID(nullptr); return createConnectionInternal(mConnections[handle->id]->thread.get(), - std::move(resyncCallback)); + std::move(resyncCallback), configChanged); } EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) { @@ -309,7 +310,7 @@ void Scheduler::setIgnorePresentFences(bool ignore) { mPrimaryDispSync->setIgnorePresentFences(ignore); } -nsecs_t Scheduler::expectedPresentTime() { +nsecs_t Scheduler::getDispSyncExpectedPresentTime() { return mPrimaryDispSync->expectedPresentTime(); } @@ -324,8 +325,11 @@ std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer( : RefreshRateType::PERFORMANCE; const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType); - const uint32_t fps = (refreshRate) ? refreshRate->fps : 0; - return mLayerHistory.createLayer(name, fps); + const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0; + + const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT); + const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0; + return mLayerHistory.createLayer(name, defaultFps, performanceFps); } void Scheduler::addLayerPresentTimeAndHDR( @@ -404,6 +408,10 @@ void Scheduler::notifyTouchEvent() { if (mSupportKernelTimer) { resetIdleTimer(); } + + // Touch event will boost the refresh rate to performance. + // Clear Layer History to get fresh FPS detection + mLayerHistory.clearHistory(); } void Scheduler::resetTimerCallback() { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index d311f62fdb..a30776059f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -26,9 +26,9 @@ #include "DispSync.h" #include "EventControlThread.h" #include "EventThread.h" -#include "IdleTimer.h" #include "InjectVSyncSource.h" #include "LayerHistory.h" +#include "OneShotTimer.h" #include "RefreshRateConfigs.h" #include "SchedulerUtils.h" @@ -96,12 +96,13 @@ public: virtual ~Scheduler(); /** Creates an EventThread connection. */ - sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs, - ResyncCallback, + sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, ResyncCallback, impl::EventThread::InterceptVSyncsCallback); - sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle, - ResyncCallback); + sp<IDisplayEventConnection> createDisplayEventConnection( + const sp<ConnectionHandle>& handle, ResyncCallback, + ISurfaceComposer::ConfigChanged configChanged); // Getter methods. EventThread* getEventThread(const sp<ConnectionHandle>& handle); @@ -149,7 +150,7 @@ public: void addResyncSample(const nsecs_t timestamp, bool* periodFlushed); void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime); void setIgnorePresentFences(bool ignore); - nsecs_t expectedPresentTime(); + nsecs_t getDispSyncExpectedPresentTime(); // Registers the layer in the scheduler, and returns the handle for future references. std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name, int windowType); @@ -184,7 +185,8 @@ public: protected: virtual std::unique_ptr<EventThread> makeEventThread( - const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs, + const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback interceptCallback); private: @@ -197,7 +199,8 @@ private: enum class TouchState { INACTIVE, ACTIVE }; // Creates a connection on the given EventThread and forwards the given callbacks. - sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&); + sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&, + ISurfaceComposer::ConfigChanged); nsecs_t calculateAverage() const; void updateFrameSkipping(const int64_t skipCount); @@ -270,14 +273,14 @@ private: // Timer that records time between requests for next vsync. If the time is higher than a given // interval, a callback is fired. Set this variable to >0 to use this feature. int64_t mSetIdleTimerMs = 0; - std::unique_ptr<scheduler::IdleTimer> mIdleTimer; + std::unique_ptr<scheduler::OneShotTimer> mIdleTimer; // Enables whether to use idle timer callbacks that support the kernel // timer. bool mSupportKernelTimer; // Timer used to monitor touch events. int64_t mSetTouchTimerMs = 0; - std::unique_ptr<scheduler::IdleTimer> mTouchTimer; + std::unique_ptr<scheduler::OneShotTimer> mTouchTimer; std::mutex mCallbackLock; ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h index 3bf3922edd..ced1899109 100644 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h @@ -36,13 +36,16 @@ static constexpr size_t ARRAY_SIZE = 30; static constexpr int SCREEN_OFF_CONFIG_ID = -1; static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff; -// This number is used when we try to determine how long does a given layer stay relevant. -// Currently it is set to 100ms, because that would indicate 10Hz rendering. -static constexpr std::chrono::nanoseconds TIME_EPSILON_NS = 100ms; - // This number is used when we try to determine how long do we keep layer information around -// before we remove it. Currently it is set to 100ms. -static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 100ms; +// before we remove it. It is also used to determine how long the layer stays relevant. +// This time period captures infrequent updates when playing YouTube video with static image, +// or waiting idle in messaging app, when cursor is blinking. +static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 1200ms; + +// Layer is considered low activity if the buffers come more than LOW_ACTIVITY_EPSILON_NS +// apart. This is helping SF to vote for lower refresh rates when there is not activity +// in screen. +static constexpr std::chrono::nanoseconds LOW_ACTIVITY_EPSILON_NS = 250ms; // Calculates the statistical mean (average) in the data structure (array, vector). The // function does not modify the contents of the array. diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp new file mode 100644 index 0000000000..d452c19b68 --- /dev/null +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -0,0 +1,177 @@ +/* + * Copyright 2019 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 ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "VSyncModulator.h" + +#include <cutils/properties.h> +#include <utils/Trace.h> + +#include <cinttypes> +#include <mutex> + +namespace android { + +using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; +VSyncModulator::VSyncModulator() { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.vsync_trace_detailed_info", value, "0"); + mTraceDetailedInfo = atoi(value); + // Populate the offset map with some default offsets. + const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0}; + setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0); +} + +void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, + nsecs_t thresholdForNextVsync) { + std::lock_guard<std::mutex> lock(mMutex); + mOffsetMap.insert_or_assign(OffsetType::Early, early); + mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl); + mOffsetMap.insert_or_assign(OffsetType::Late, late); + mThresholdForNextVsync = thresholdForNextVsync; + updateOffsetsLocked(); +} + +void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { + if (transactionStart == Scheduler::TransactionStart::EARLY) { + mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; + } + + // An early transaction stays an early transaction. + if (transactionStart == mTransactionStart || + mTransactionStart == Scheduler::TransactionStart::EARLY) { + return; + } + mTransactionStart = transactionStart; + updateOffsets(); +} + +void VSyncModulator::onTransactionHandled() { + if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; + mTransactionStart = Scheduler::TransactionStart::NORMAL; + updateOffsets(); +} + +void VSyncModulator::onRefreshRateChangeInitiated() { + if (mRefreshRateChangePending) { + return; + } + mRefreshRateChangePending = true; + updateOffsets(); +} + +void VSyncModulator::onRefreshRateChangeCompleted() { + if (!mRefreshRateChangePending) { + return; + } + mRefreshRateChangePending = false; + updateOffsets(); +} + +void VSyncModulator::onRefreshed(bool usedRenderEngine) { + bool updateOffsetsNeeded = false; + if (mRemainingEarlyFrameCount > 0) { + mRemainingEarlyFrameCount--; + updateOffsetsNeeded = true; + } + if (usedRenderEngine) { + mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION; + updateOffsetsNeeded = true; + } else if (mRemainingRenderEngineUsageCount > 0) { + mRemainingRenderEngineUsageCount--; + updateOffsetsNeeded = true; + } + if (updateOffsetsNeeded) { + updateOffsets(); + } +} + +VSyncModulator::Offsets VSyncModulator::getOffsets() { + std::lock_guard<std::mutex> lock(mMutex); + return mOffsets; +} + +VSyncModulator::Offsets VSyncModulator::getNextOffsets() { + return mOffsetMap.at(getNextOffsetType()); +} + +VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() { + // Early offsets are used if we're in the middle of a refresh rate + // change, or if we recently begin a transaction. + if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || + mRefreshRateChangePending) { + return OffsetType::Early; + } else if (mRemainingRenderEngineUsageCount > 0) { + return OffsetType::EarlyGl; + } else { + return OffsetType::Late; + } +} + +void VSyncModulator::updateOffsets() { + std::lock_guard<std::mutex> lock(mMutex); + updateOffsetsLocked(); +} + +void VSyncModulator::updateOffsetsLocked() { + const Offsets desired = getNextOffsets(); + const Offsets current = mOffsets; + + bool changed = false; + if (desired.sf != current.sf) { + if (mSfConnectionHandle != nullptr) { + mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); + } else if (mSfEventThread != nullptr) { + mSfEventThread->setPhaseOffset(desired.sf); + } + changed = true; + } + if (desired.app != current.app) { + if (mAppConnectionHandle != nullptr) { + mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); + } else if (mAppEventThread != nullptr) { + mAppEventThread->setPhaseOffset(desired.app); + } + changed = true; + } + + if (changed) { + flushOffsets(); + } +} + +void VSyncModulator::flushOffsets() { + OffsetType type = getNextOffsetType(); + mOffsets = mOffsetMap.at(type); + if (!mTraceDetailedInfo) { + return; + } + ATRACE_INT("Vsync-EarlyOffsetsOn", + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early); + ATRACE_INT("Vsync-EarlyGLOffsetsOn", + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl); + ATRACE_INT("Vsync-LateOffsetsOn", + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late); + ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early); + ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl); + ATRACE_INT("Vsync-HighFpsLateOffsetsOn", + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late); +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 41c3a3a605..10cf8e6cc9 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -16,8 +16,6 @@ #pragma once -#include <utils/Errors.h> - #include <cinttypes> #include <mutex> @@ -41,11 +39,22 @@ private: const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; public: + VSyncModulator(); + + // Wrapper for a collection of surfaceflinger/app offsets for a particular + // configuration . struct Offsets { + scheduler::RefreshRateConfigs::RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; + enum class OffsetType { + Early, + EarlyGl, + Late, + }; + // Sets the phase offsets // // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction @@ -56,31 +65,16 @@ public: // appEarly: Like sfEarly, but for the app-vsync // appEarlyGl: Like sfEarlyGl, but for the app-vsync. // appLate: The regular app vsync phase offset. - void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) { - mEarlyOffsets = early; - mEarlyGlOffsets = earlyGl; - mLateOffsets = late; - - if (mSfConnectionHandle && late.sf != mOffsets.load().sf) { - mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf); - } - - if (mAppConnectionHandle && late.app != mOffsets.load().app) { - mScheduler->setPhaseOffset(mAppConnectionHandle, late.app); - } - - mOffsets = late; - } - - Offsets getEarlyOffsets() const { return mEarlyOffsets; } - - Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; } + void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, + nsecs_t thresholdForNextVsync) EXCLUDES(mMutex); + // Sets handles to the SF and app event threads. void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) { mSfEventThread = sfEventThread; mAppEventThread = appEventThread; } + // Sets the scheduler and vsync connection handlers. void setSchedulerAndHandles(Scheduler* scheduler, Scheduler::ConnectionHandle* appConnectionHandle, Scheduler::ConnectionHandle* sfConnectionHandle) { @@ -89,109 +83,43 @@ public: mSfConnectionHandle = sfConnectionHandle; } - void setTransactionStart(Scheduler::TransactionStart transactionStart) { - if (transactionStart == Scheduler::TransactionStart::EARLY) { - mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; - } - - // An early transaction stays an early transaction. - if (transactionStart == mTransactionStart || - mTransactionStart == Scheduler::TransactionStart::EARLY) { - return; - } - mTransactionStart = transactionStart; - updateOffsets(); - } + // Signals that a transaction has started, and changes offsets accordingly. + void setTransactionStart(Scheduler::TransactionStart transactionStart); - void onTransactionHandled() { - if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; - mTransactionStart = Scheduler::TransactionStart::NORMAL; - updateOffsets(); - } + // Signals that a transaction has been completed, so that we can finish + // special handling for a transaction. + void onTransactionHandled(); // Called when we send a refresh rate change to hardware composer, so that // we can move into early offsets. - void onRefreshRateChangeInitiated() { - if (mRefreshRateChangePending) { - return; - } - mRefreshRateChangePending = true; - updateOffsets(); - } + void onRefreshRateChangeInitiated(); // Called when we detect from vsync signals that the refresh rate changed. // This way we can move out of early offsets if no longer necessary. - void onRefreshRateChangeCompleted() { - if (!mRefreshRateChangePending) { - return; - } - mRefreshRateChangePending = false; - updateOffsets(); - } + void onRefreshRateChangeCompleted(); - void onRefreshed(bool usedRenderEngine) { - bool updateOffsetsNeeded = false; - if (mRemainingEarlyFrameCount > 0) { - mRemainingEarlyFrameCount--; - updateOffsetsNeeded = true; - } - if (usedRenderEngine) { - mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION; - updateOffsetsNeeded = true; - } else if (mRemainingRenderEngineUsageCount > 0) { - mRemainingRenderEngineUsageCount--; - updateOffsetsNeeded = true; - } - - if (updateOffsetsNeeded) { - updateOffsets(); - } - } + // Called when the display is presenting a new frame. usedRenderEngine + // should be set to true if RenderEngine was involved with composing the new + // frame. + void onRefreshed(bool usedRenderEngine); - Offsets getOffsets() { - // Early offsets are used if we're in the middle of a refresh rate - // change, or if we recently begin a transaction. - if (mTransactionStart == Scheduler::TransactionStart::EARLY || - mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { - return mEarlyOffsets; - } else if (mRemainingRenderEngineUsageCount > 0) { - return mEarlyGlOffsets; - } else { - return mLateOffsets; - } - } + // Returns the offsets that we are currently using + Offsets getOffsets() EXCLUDES(mMutex); private: - void updateOffsets() { - const Offsets desired = getOffsets(); - const Offsets current = mOffsets; - - bool changed = false; - if (desired.sf != current.sf) { - if (mSfConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); - } else { - mSfEventThread->setPhaseOffset(desired.sf); - } - changed = true; - } - if (desired.app != current.app) { - if (mAppConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); - } else { - mAppEventThread->setPhaseOffset(desired.app); - } - changed = true; - } - - if (changed) { - mOffsets = desired; - } - } - - Offsets mLateOffsets; - Offsets mEarlyOffsets; - Offsets mEarlyGlOffsets; + // Returns the next offsets that we should be using + Offsets getNextOffsets() REQUIRES(mMutex); + // Returns the next offset type that we should use. + OffsetType getNextOffsetType(); + // Updates offsets and persists them into the scheduler framework. + void updateOffsets() EXCLUDES(mMutex); + void updateOffsetsLocked() REQUIRES(mMutex); + // Updates the internal offsets and offset type. + void flushOffsets() REQUIRES(mMutex); + + mutable std::mutex mMutex; + std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex); + nsecs_t mThresholdForNextVsync; EventThread* mSfEventThread = nullptr; EventThread* mAppEventThread = nullptr; @@ -200,13 +128,15 @@ private: Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; - std::atomic<Offsets> mOffsets; + Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0}; std::atomic<Scheduler::TransactionStart> mTransactionStart = Scheduler::TransactionStart::NORMAL; std::atomic<bool> mRefreshRateChangePending = false; std::atomic<int> mRemainingEarlyFrameCount = 0; std::atomic<int> mRemainingRenderEngineUsageCount = 0; + + bool mTraceDetailedInfo = false; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 982a33e48a..2cb2544448 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -302,8 +302,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mDefaultCompositionDataspace = static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB)); - mWideColorGamutCompositionDataspace = - static_cast<ui::Dataspace>(wcg_composition_dataspace(Dataspace::V0_SRGB)); + mWideColorGamutCompositionDataspace = static_cast<ui::Dataspace>(wcg_composition_dataspace( + hasWideColorDisplay ? Dataspace::DISPLAY_P3 : Dataspace::V0_SRGB)); defaultCompositionDataspace = mDefaultCompositionDataspace; wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace; defaultCompositionPixelFormat = static_cast<ui::PixelFormat>( @@ -377,7 +377,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mLumaSampling = atoi(value); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold @@ -616,13 +617,16 @@ void SurfaceFlinger::init() { mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); mAppConnectionHandle = - mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), + mScheduler->createConnection("app", mVsyncModulator.getOffsets().app, + mPhaseOffsets->getOffsetThresholdForNextVsync(), resyncCallback, impl::EventThread::InterceptVSyncsCallback()); - mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(), - resyncCallback, [this](nsecs_t timestamp) { - mInterceptor->saveVSyncEvent(timestamp); - }); + mSfConnectionHandle = + mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf, + mPhaseOffsets->getOffsetThresholdForNextVsync(), + resyncCallback, [this](nsecs_t timestamp) { + mInterceptor->saveVSyncEvent(timestamp); + }); mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), @@ -940,7 +944,8 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { mVsyncModulator.onRefreshRateChangeInitiated(); mPhaseOffsets->setRefreshRateType(info.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); } mDesiredActiveConfigChanged = true; ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); @@ -974,7 +979,8 @@ void SurfaceFlinger::setActiveConfigInternal() { mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { @@ -992,7 +998,8 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() { mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); } bool SurfaceFlinger::performSetActiveConfig() { @@ -1372,7 +1379,7 @@ status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource) { + ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) { auto resyncCallback = mScheduler->makeResyncCallback([this] { Mutex::Autolock lock(mStateLock); return getVsyncPeriod(); @@ -1381,7 +1388,8 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; - return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback)); + return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback), + configChanged); } // ---------------------------------------------------------------------------- @@ -1540,14 +1548,12 @@ void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) { void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) { ATRACE_CALL(); + mHWCVsyncPendingState = enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable; + if (const auto displayId = getInternalDisplayIdLocked()) { sp<DisplayDevice> display = getDefaultDisplayDeviceLocked(); if (display && display->isPoweredOn()) { - getHwComposer().setVsyncEnabled(*displayId, - enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); - } else { - // Cache the latest vsync state and apply it when screen is on again - mEnableHWVsyncScreenOn = enabled; + setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState); } } } @@ -1661,7 +1667,7 @@ bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS { DisplayStatInfo stats; mScheduler->getDisplayStatInfo(&stats); - const nsecs_t presentTime = mScheduler->expectedPresentTime(); + const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(); // Inflate the expected present time if we're targetting the next vsync. const nsecs_t correctedTime = mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() @@ -1795,6 +1801,12 @@ void SurfaceFlinger::handleMessageRefresh() { mVsyncModulator.onRefreshed(mHadClientComposition); mLayersWithQueuedFrames.clear(); + if (mVisibleRegionsDirty) { + mVisibleRegionsDirty = false; + if (mTracingEnabled) { + mTracing.notify("visibleRegionsDirty"); + } + } } @@ -1804,9 +1816,6 @@ bool SurfaceFlinger::handleMessageInvalidate() { if (mVisibleRegionsDirty) { computeLayerBounds(); - if (mTracingEnabled) { - mTracing.notify("visibleRegionsDirty"); - } } for (auto& layer : mLayersPendingRefresh) { @@ -2166,7 +2175,14 @@ void SurfaceFlinger::postComposition() } mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]); - mTransactionCompletedThread.sendCallbacks(); + + // Lock the mStateLock in case SurfaceFlinger is in the middle of applying a transaction. + // If we do not lock here, a callback could be sent without all of its SurfaceControls and + // metrics. + { + Mutex::Autolock _l(mStateLock); + mTransactionCompletedThread.sendCallbacks(); + } if (mLumaSampling && mRegionSamplingThread) { mRegionSamplingThread->notifyNewContent(); @@ -2201,7 +2217,6 @@ void SurfaceFlinger::rebuildLayerStacks() { // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { ATRACE_NAME("rebuildLayerStacks VR Dirty"); - mVisibleRegionsDirty = false; invalidateHwcGeometry(); for (const auto& pair : mDisplays) { @@ -3519,11 +3534,6 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice, return true; } -void SurfaceFlinger::drawWormhole(const Region& region) const { - auto& engine(getRenderEngine()); - engine.fillRegionWithColor(region, 0, 0, 0, 0); -} - status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc, const sp<IBinder>& parentHandle, @@ -3668,7 +3678,7 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector<ComposerState>& states) { - nsecs_t expectedPresentTime = mScheduler->expectedPresentTime(); + nsecs_t expectedPresentTime = getExpectedPresentTime(); // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime && @@ -3918,6 +3928,11 @@ uint32_t SurfaceFlinger::setClientStateLocked( sp<Layer> layer(client->getLayerUser(s.surface)); if (layer == nullptr) { + for (auto& listenerCallback : listenerCallbacks) { + mTransactionCompletedThread.addUnpresentedCallbackHandle( + new CallbackHandle(listenerCallback.transactionCompletedListener, + listenerCallback.callbackIds, s.surface)); + } return 0; } @@ -4434,6 +4449,13 @@ void SurfaceFlinger::initializeDisplays() { new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); })); } +void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled) { + if (mHWCVsyncState != enabled) { + getHwComposer().setVsyncEnabled(displayId, enabled); + mHWCVsyncState = enabled; + } +} + void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) { if (display->isVirtual()) { ALOGE("%s: Invalid operation on virtual display", __FUNCTION__); @@ -4460,11 +4482,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int // Turn on the display getHwComposer().setPowerMode(*displayId, mode); if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) { - if (mEnableHWVsyncScreenOn) { - setPrimaryVsyncEnabledInternal(mEnableHWVsyncScreenOn); - mEnableHWVsyncScreenOn = false; - } - + setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); } @@ -4490,6 +4508,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mScheduler->onScreenReleased(mAppConnectionHandle); } + // Make sure HWVsync is disabled before turning off the display + setVsyncEnabledInHWC(*displayId, HWC2::Vsync::Disable); + getHwComposer().setPowerMode(*displayId, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display @@ -5646,6 +5667,11 @@ status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace* captureOrientation = fromSurfaceComposerRotation( static_cast<ISurfaceComposer::Rotation>(display->getOrientation())); + if (captureOrientation == ui::Transform::orientation_flags::ROT_90) { + captureOrientation = ui::Transform::orientation_flags::ROT_270; + } else if (captureOrientation == ui::Transform::orientation_flags::ROT_270) { + captureOrientation = ui::Transform::orientation_flags::ROT_90; + } *outDataspace = pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index df6cdf2993..1a9dcdd2ef 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -407,7 +407,9 @@ private: const sp<IGraphicBufferProducer>& bufferProducer) const override; status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override; sp<IDisplayEventConnection> createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override; + ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp, + ISurfaceComposer::ConfigChanged configChanged = + ISurfaceComposer::eConfigChangedSuppress) override; status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, @@ -788,7 +790,6 @@ private: void postFramebuffer(const sp<DisplayDevice>& display); void postFrame(); - void drawWormhole(const Region& region) const; /* ------------------------------------------------------------------------ * Display management @@ -843,6 +844,7 @@ private: } bool previousFrameMissed(); + void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled); /* * Debugging & dumpsys @@ -1177,8 +1179,9 @@ private: // be any issues with a raw pointer referencing an invalid object. std::unordered_set<Layer*> mOffscreenLayers; - // Flag to indicate whether to re-enable HWVsync when screen is on - bool mEnableHWVsyncScreenOn = false; + // Flags to capture the state of Vsync in HWC + HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable; + HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 4f352ff9db..2b33ba1746 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -177,15 +177,11 @@ SurfaceFlingerProperties::primary_display_orientation_values primary_display_ori bool use_color_management(bool defaultValue) { auto tmpuseColorManagement = SurfaceFlingerProperties::use_color_management(); - auto tmpHasHDRDisplay = SurfaceFlingerProperties::has_HDR_display(); - auto tmpHasWideColorDisplay = SurfaceFlingerProperties::has_wide_color_display(); + auto tmpHasHDRDisplayVal = has_HDR_display(defaultValue); + auto tmpHasWideColorDisplayVal = has_wide_color_display(defaultValue); auto tmpuseColorManagementVal = tmpuseColorManagement.has_value() ? *tmpuseColorManagement : defaultValue; - auto tmpHasHDRDisplayVal = tmpHasHDRDisplay.has_value() ? *tmpHasHDRDisplay : - defaultValue; - auto tmpHasWideColorDisplayVal = tmpHasWideColorDisplay.has_value() ? *tmpHasWideColorDisplay : - defaultValue; return tmpuseColorManagementVal || tmpHasHDRDisplayVal || tmpHasWideColorDisplayVal; } diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 4773307a65..18524f02d8 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -61,7 +61,7 @@ public: void setTraceFlags(uint32_t flags); private: - static constexpr auto kDefaultBufferCapInByte = 100_MB; + static constexpr auto kDefaultBufferCapInByte = 5_MB; static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb"; class LayersTraceBuffer { // ring buffer diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp index cb368b0886..d03cb7b22a 100644 --- a/services/surfaceflinger/layerproto/Android.bp +++ b/services/surfaceflinger/layerproto/Android.bp @@ -43,7 +43,7 @@ java_library_static { type: "nano", }, srcs: ["*.proto"], - no_framework_libs: true, + sdk_version: "core_platform", target: { android: { jarjar_rules: "jarjar-rules.txt", diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index decabd5e88..a8ec7649c6 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -36,7 +36,7 @@ owner: Platform prop { api_name: "vsync_event_phase_offset_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" } @@ -44,7 +44,7 @@ prop { prop { api_name: "vsync_sf_event_phase_offset_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" } @@ -53,7 +53,7 @@ prop { prop { api_name: "use_context_priority" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_context_priority" } @@ -62,7 +62,7 @@ prop { prop { api_name: "max_frame_buffer_acquired_buffers" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" } @@ -80,7 +80,7 @@ prop { prop { api_name: "has_wide_color_display" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.has_wide_color_display" } @@ -90,7 +90,7 @@ prop { prop { api_name: "running_without_sync_framework" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.running_without_sync_framework" } @@ -108,7 +108,7 @@ prop { prop { api_name: "has_HDR_display" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.has_HDR_display" } @@ -117,7 +117,7 @@ prop { prop { api_name: "present_time_offset_from_vsync_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" } @@ -129,7 +129,7 @@ prop { prop { api_name: "force_hwc_copy_for_virtual_displays" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" } @@ -139,7 +139,7 @@ prop { prop { api_name: "max_virtual_display_dimension" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.max_virtual_display_dimension" } @@ -151,7 +151,7 @@ prop { prop { api_name: "use_vr_flinger" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_vr_flinger" } @@ -161,7 +161,7 @@ prop { prop { api_name: "start_graphics_allocator_service" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.start_graphics_allocator_service" } @@ -171,7 +171,7 @@ prop { api_name: "primary_display_orientation" type: Enum enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.primary_display_orientation" } @@ -182,7 +182,7 @@ prop { prop { api_name: "use_color_management" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_color_management" } @@ -209,7 +209,7 @@ prop { prop { api_name: "default_composition_dataspace" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.default_composition_dataspace" } @@ -220,7 +220,7 @@ prop { prop { api_name: "default_composition_pixel_format" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.default_composition_pixel_format" } @@ -235,7 +235,7 @@ prop { prop { api_name: "wcg_composition_dataspace" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.wcg_composition_dataspace" } @@ -246,7 +246,7 @@ prop { prop { api_name: "wcg_composition_pixel_format" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.wcg_composition_pixel_format" } @@ -258,7 +258,7 @@ prop { prop { api_name: "display_primary_red" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_red" } @@ -266,7 +266,7 @@ prop { prop { api_name: "display_primary_green" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_green" } @@ -274,7 +274,7 @@ prop { prop { api_name: "display_primary_blue" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_blue" } @@ -282,7 +282,7 @@ prop { prop { api_name: "display_primary_white" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_white" } @@ -293,7 +293,7 @@ prop { prop { api_name: "set_idle_timer_ms" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.set_idle_timer_ms" } @@ -304,7 +304,7 @@ prop { prop { api_name: "set_touch_timer_ms" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.set_touch_timer_ms" } @@ -314,7 +314,7 @@ prop { prop { api_name: "use_smart_90_for_video" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_smart_90_for_video" } @@ -322,7 +322,7 @@ prop { prop { api_name: "enable_protected_contents" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.protected_contents" } @@ -332,7 +332,7 @@ prop { prop { api_name: "support_kernel_idle_timer" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.support_kernel_idle_timer" } diff --git a/services/surfaceflinger/test.png b/services/surfaceflinger/test.png Binary files differnew file mode 100644 index 0000000000..773dcc3e72 --- /dev/null +++ b/services/surfaceflinger/test.png diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index f842d61c7f..4917bc2a51 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -42,7 +42,7 @@ cc_test { "DisplayTransactionTest.cpp", "EventControlThreadTest.cpp", "EventThreadTest.cpp", - "IdleTimerTest.cpp", + "OneShotTimerTest.cpp", "LayerHistoryTest.cpp", "LayerMetadataTest.cpp", "SchedulerTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4f8ed1ae1c..e6211c488e 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -303,11 +303,6 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1); EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true)); - // TODO: remove once we verify that we can just grab the fence from the - // FramebufferSurface. - EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() { - return base::unique_fd(); - })); EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1); EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1); diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index 2e705dad6d..0aa8cf565d 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -51,6 +51,7 @@ protected: AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder; static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms; + static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms; static constexpr int mIterations = 100; }; @@ -78,7 +79,8 @@ void DispSyncSourceTest::createDispSync() { void DispSyncSourceTest::createDispSyncSource() { createDispSync(); - mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true, + mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), + mOffsetThresholdForNextVsync.count(), true, "DispSyncSourceTest"); mDispSyncSource->setCallback(this); } diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index ea908a9018..dbd9b84039 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -55,8 +55,9 @@ protected: class MockEventThreadConnection : public EventThreadConnection { public: MockEventThreadConnection(android::impl::EventThread* eventThread, - ResyncCallback&& resyncCallback) - : EventThreadConnection(eventThread, std::move(resyncCallback)) {} + ResyncCallback&& resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) + : EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {} MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event)); }; @@ -67,7 +68,8 @@ protected: ~EventThreadTest() override; void createThread(); - sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder); + sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder, + ISurfaceComposer::ConfigChanged configChanged); void expectVSyncSetEnabledCallReceived(bool expectedState); void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset); @@ -110,7 +112,8 @@ EventThreadTest::EventThreadTest() { .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable())); createThread(); - mConnection = createConnection(mConnectionEventCallRecorder); + mConnection = createConnection(mConnectionEventCallRecorder, + ISurfaceComposer::eConfigChangedDispatch); // A display must be connected for VSYNC events to be delivered. mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true); @@ -138,9 +141,10 @@ void EventThreadTest::createThread() { } sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection( - ConnectionEventRecorder& recorder) { + ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged) { sp<MockEventThreadConnection> connection = - new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable()); + new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(), + configChanged); EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable())); return connection; } @@ -267,7 +271,9 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; - sp<MockEventThreadConnection> firstConnection = createConnection(firstConnectionEventRecorder); + sp<MockEventThreadConnection> firstConnection = + createConnection(firstConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(0, firstConnection); // By itself, this should not enable vsync events @@ -277,7 +283,8 @@ TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // However if there is another connection which wants events at a nonzero rate..... ConnectionEventRecorder secondConnectionEventRecorder{0}; sp<MockEventThreadConnection> secondConnection = - createConnection(secondConnectionEventRecorder); + createConnection(secondConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, secondConnection); // EventThread should enable vsync callbacks. @@ -363,7 +370,9 @@ TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) { TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY}; - sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder); + sp<MockEventThreadConnection> errorConnection = + createConnection(errorConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, errorConnection); // EventThread should enable vsync callbacks. @@ -387,7 +396,9 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK}; - sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder); + sp<MockEventThreadConnection> errorConnection = + createConnection(errorConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, errorConnection); // EventThread should enable vsync callbacks. @@ -449,5 +460,18 @@ TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7); } +TEST_F(EventThreadTest, suppressConfigChanged) { + ConnectionEventRecorder suppressConnectionEventRecorder{0}; + sp<MockEventThreadConnection> suppressConnection = + createConnection(suppressConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); + + mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9); + expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9); + + auto args = suppressConnectionEventRecorder.waitForCall(); + ASSERT_FALSE(args.has_value()); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index 96121bb088..1d7501102e 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -23,6 +23,8 @@ namespace android { namespace scheduler { +using RefreshRateType = RefreshRateConfigs::RefreshRateType; + class FakePhaseOffsets : public android::scheduler::PhaseOffsets { nsecs_t FAKE_PHASE_OFFSET_NS = 0; @@ -34,20 +36,20 @@ public: nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; } PhaseOffsets::Offsets getOffsetsForRefreshRate( - RefreshRateConfigs::RefreshRateType /*refreshRateType*/) const override { + RefreshRateType /*refreshRateType*/) const override { return getCurrentOffsets(); } // Returns early, early GL, and late offsets for Apps and SF. PhaseOffsets::Offsets getCurrentOffsets() const override { - return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; + return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; } // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. - void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {} + void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {} nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; } @@ -56,4 +58,4 @@ public: }; } // namespace scheduler -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 2b1dfa8f38..7ec90660ce 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -25,6 +25,7 @@ public: protected: std::unique_ptr<LayerHistory> mLayerHistory; + static constexpr float MIN_REFRESH_RATE = 30.f; static constexpr float MAX_REFRESH_RATE = 90.f; }; @@ -36,7 +37,7 @@ LayerHistoryTest::~LayerHistoryTest() {} namespace { TEST_F(LayerHistoryTest, oneLayer) { std::unique_ptr<LayerHistory::LayerHandle> testLayer = - mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); mLayerHistory->insert(testLayer, 0, false /*isHDR*/); @@ -60,7 +61,7 @@ TEST_F(LayerHistoryTest, oneLayer) { TEST_F(LayerHistoryTest, oneHDRLayer) { std::unique_ptr<LayerHistory::LayerHandle> testLayer = - mLayerHistory->createLayer("TestHDRLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); mLayerHistory->insert(testLayer, 0, true /*isHDR*/); @@ -74,7 +75,7 @@ TEST_F(LayerHistoryTest, oneHDRLayer) { TEST_F(LayerHistoryTest, explicitTimestamp) { std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer = - mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(test30FpsLayer, true); nsecs_t startTime = systemTime(); @@ -87,13 +88,13 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { TEST_F(LayerHistoryTest, multipleLayers) { std::unique_ptr<LayerHistory::LayerHandle> testLayer = - mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer = - mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(test30FpsLayer, true); std::unique_ptr<LayerHistory::LayerHandle> testLayer2 = - mLayerHistory->createLayer("TestLayer2", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer2, true); nsecs_t startTime = systemTime(); @@ -119,8 +120,8 @@ TEST_F(LayerHistoryTest, multipleLayers) { mLayerHistory->insert(testLayer2, 0, false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); - // After 100 ms frames become obsolete. - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + // After 1200 ms frames become obsolete. + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); // Insert the 31st frame. mLayerHistory->insert(test30FpsLayer, startTime + (30 * 33333333), false /*isHDR*/); EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp index eff22b6640..0208728026 100644 --- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp +++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp @@ -21,17 +21,17 @@ #include <utils/Log.h> #include "AsyncCallRecorder.h" -#include "Scheduler/IdleTimer.h" +#include "Scheduler/OneShotTimer.h" using namespace std::chrono_literals; namespace android { namespace scheduler { -class IdleTimerTest : public testing::Test { +class OneShotTimerTest : public testing::Test { protected: - IdleTimerTest() = default; - ~IdleTimerTest() override = default; + OneShotTimerTest() = default; + ~OneShotTimerTest() override = default; // This timeout should be used when a 3ms callback is expected. // While the tests typically request a callback after 3ms, the scheduler @@ -46,7 +46,7 @@ protected: AsyncCallRecorder<void (*)()> mResetTimerCallback; AsyncCallRecorder<void (*)()> mExpiredTimerCallback; - std::unique_ptr<IdleTimer> mIdleTimer; + std::unique_ptr<OneShotTimer> mIdleTimer; void clearPendingCallbacks() { while (mExpiredTimerCallback.waitForCall(0us).has_value()) { @@ -55,13 +55,14 @@ protected: }; namespace { -TEST_F(IdleTimerTest, createAndDestroyTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {}, [] {}); +TEST_F(OneShotTimerTest, createAndDestroyTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>( + 3ms, [] {}, [] {}); } -TEST_F(IdleTimerTest, startStopTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, startStopTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); auto startTime = std::chrono::steady_clock::now(); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -70,7 +71,7 @@ TEST_F(IdleTimerTest, startStopTest) { bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value(); // Under ideal conditions there should be no event. But occasionally // it is possible that the wait just prior takes more than 30ms, and - // a callback is observed. We check the elapsed time since before the IdleTimer + // a callback is observed. We check the elapsed time since before the OneShotTimer // thread was started as a sanity check to not have a flakey test. EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms); @@ -79,9 +80,9 @@ TEST_F(IdleTimerTest, startStopTest) { mIdleTimer->stop(); } -TEST_F(IdleTimerTest, resetTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, resetTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); // Observe any event that happens in about 25ms. We don't care if one was @@ -104,9 +105,9 @@ TEST_F(IdleTimerTest, resetTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, resetBackToBackTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, resetBackToBackTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -135,9 +136,9 @@ TEST_F(IdleTimerTest, resetBackToBackTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, startNotCalledTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, startNotCalledTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); // The start hasn't happened, so the callback does not happen. EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); @@ -147,9 +148,9 @@ TEST_F(IdleTimerTest, startNotCalledTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, idleTimerIdlesTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, idleTimerIdlesTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -167,18 +168,18 @@ TEST_F(IdleTimerTest, idleTimerIdlesTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); mIdleTimer->stop(); } -TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); @@ -190,9 +191,9 @@ TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); } -TEST_F(IdleTimerTest, noCallbacksAfterStopTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 1f8b11180b..740115ea32 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -25,7 +25,8 @@ protected: class MockEventThreadConnection : public android::EventThreadConnection { public: explicit MockEventThreadConnection(EventThread* eventThread) - : EventThreadConnection(eventThread, ResyncCallback()) {} + : EventThreadConnection(eventThread, ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress) {} ~MockEventThreadConnection() = default; MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel)); @@ -47,7 +48,7 @@ protected: std::unique_ptr<EventThread> makeEventThread( const char* /* connectionName */, DispSync* /* dispSync */, - nsecs_t /* phaseOffsetNs */, + nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */, impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override { return std::move(mEventThread); } @@ -81,10 +82,10 @@ SchedulerTest::SchedulerTest() { // createConnection call to scheduler makes a createEventConnection call to EventThread. Make // sure that call gets executed and returns an EventThread::Connection object. - EXPECT_CALL(*mEventThread, createEventConnection(_)) + EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillRepeatedly(Return(mEventThreadConnection)); - mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(), + mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(), impl::EventThread::InterceptVSyncsCallback()); EXPECT_TRUE(mConnectionHandle != nullptr); } @@ -105,7 +106,10 @@ TEST_F(SchedulerTest, testNullPtr) { // exceptions, just gracefully continues. sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( - returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback())); + returnedValue = + mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr); EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr); @@ -126,7 +130,9 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback())); + mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr); EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr); @@ -155,7 +161,9 @@ TEST_F(SchedulerTest, validConnectionHandle) { sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback())); + mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue != nullptr); ASSERT_EQ(returnedValue, mEventThreadConnection); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index c3d2b8de4f..cb6980ed1a 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -17,6 +17,7 @@ #pragma once #include <gmock/gmock.h> +#include <gui/ISurfaceComposer.h> #include "Scheduler/EventThread.h" #include "Scheduler/RefreshRateConfigs.h" @@ -34,7 +35,8 @@ public: // Scheduler::Connection. This allows plugging in mock::EventThread. sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) { sp<EventThreadConnection> eventThreadConnection = - new EventThreadConnection(eventThread.get(), ResyncCallback()); + new EventThreadConnection(eventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress); const int64_t id = sNextId++; mConnections.emplace(id, std::make_unique<Scheduler::Connection>(new ConnectionHandle(id), diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 5b5f8e7fab..ed35ebf2b6 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -28,7 +28,8 @@ public: EventThread(); ~EventThread() override; - MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback)); + MOCK_CONST_METHOD2(createEventConnection, + sp<EventThreadConnection>(ResyncCallback, ISurfaceComposer::ConfigChanged)); MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index 021d8cbfca..1604775da5 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -110,6 +110,7 @@ cc_binary { "liblog", "libhardware", "libhwbinder", + "libhidlbase", "libui", "libutils", "libvr_hwc-hal", diff --git a/vulkan/api/templates/asciidoc.tmpl b/vulkan/api/templates/asciidoc.tmpl deleted file mode 100644 index 3009e19cad..0000000000 --- a/vulkan/api/templates/asciidoc.tmpl +++ /dev/null @@ -1,151 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{if not (Global "AsciiDocPath")}}{{Global "AsciiDocPath" "../../doc/specs/vulkan/"}}{{end}} -{{$ | Macro "AsciiDoc.Main"}} - - -{{/* -------------------------------------------------------------------------------- - AsciiDoc generation main entry point. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Main"}} - {{$docPath := Global "AsciiDocPath"}} - - {{/* Generate AsciiDoc files for API enums and bitfields (flags). */}} - {{range $e := $.Enums}} - {{if not $e.IsBitfield}} - {{$filename := print $docPath "enums/" (Macro "EnumName" $e) ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Enum" $e) "File" $filename}} - {{else}} - {{$filename := print $docPath "flags/" (Macro "EnumName" $e) ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Flag" $e) "File" $filename}} - {{end}} - {{end}} - - {{/* Generate AsciiDoc files for API commands (protos). */}} - {{range $f := (AllCommands $)}} - {{if not (GetAnnotation $f "pfn")}} - {{$filename := print $docPath "protos/" $f.Name ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Proto" $f) "File" $filename}} - {{end}} - {{end}} - - {{/* Generate AsciiDoc files for API structs. */}} - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{$filename := print $docPath "structs/" $c.Name ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Struct" $c) "File" $filename}} - {{end}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API enum. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Enum"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef enum { - {{range $i, $e := $.Entries}} - {{Macro "EnumEntry" $e}} = {{AsSigned $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - ¶ - {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}} - {{$first := Macro "EnumFirstEntry" $}} - {{$last := Macro "EnumLastEntry" $}} - {{$name}}_BEGIN_RANGE = {{$first}}, - {{$name}}_END_RANGE = {{$last}}, - {{$name}}_NUM = ({{$last}} - {{$first}} + 1), - {{$name}}_MAX_ENUM = 0x7FFFFFFF - } {{Macro "EnumName" $}}; -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Flag"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef VkFlags {{Macro "EnumName" $}}; - {{if $.Entries}} - typedef enum { - {{range $e := $.Entries}} - {{Macro "BitfieldEntryName" $e}} = {{printf "%#.8x" $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - } {{Macro "EnumName" $ | TrimRight "s"}}Bits; - {{end}} -{{end}} - - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API class. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Struct"}} - {{AssertType $ "Class"}} - - {{Macro "Docs" $.Docs}} - typedef {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} { - {{range $f := $.Fields}} - {{Node "Type" $f}} {{$f.Name}}{{Macro "ArrayPostfix" (TypeOf $f)}}; {{Macro "Docs" $f.Docs}} - {{end}} - } {{Macro "StructName" $}}; -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API function. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Proto"}} - {{AssertType $ "Function"}} - - {{Macro "Docs" $.Docs}} - {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}}); -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Wraps the specified Code in AsciiDoc source tags then writes to the specified File. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Write"}} - {{AssertType $.Code "string"}} - {{AssertType $.File "string"}} - - {{$code := $.Code | Format (Global "clang-format")}} - {{JoinWith "\n" (Macro "AsciiDoc.Header") $code (Macro "AsciiDoc.Footer") ""| Write $.File}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits an AsciiDoc source header. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Header"}} -[source,{basebackend@docbook:c++:cpp}] ------------------------------------------------------------------------------- -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits an AsciiDoc source footer. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Footer"}} ------------------------------------------------------------------------------- -{{end}} diff --git a/vulkan/api/templates/vk_xml.tmpl b/vulkan/api/templates/vk_xml.tmpl deleted file mode 100644 index 893bde7833..0000000000 --- a/vulkan/api/templates/vk_xml.tmpl +++ /dev/null @@ -1,435 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{Macro "DefineGlobals" $}} -{{$ | Macro "vk.xml" | Reflow 4 | Write "vk.xml"}} - - -{{/* -------------------------------------------------------------------------------- - Entry point -------------------------------------------------------------------------------- -*/}} -{{define "vk.xml"}} -<?xml version="1.0" encoding="UTF-8"?> -<registry> - »<comment>« -Copyright (c) 2015 The Khronos Group Inc. -¶ -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and/or associated documentation files (the -"Materials"), to deal in the Materials without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Materials, and to -permit persons to whom the Materials are furnished to do so, subject to -the following conditions: -¶ -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Materials. -¶ -THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -¶ ------------------------------------------------------------------------- -¶ -This file, vk.xml, is the Vulkan API Registry.» - </comment> -¶ - <!-- SECTION: Vulkan type definitions --> - <types>» - <type name="vk_platform" category="include">#include "vk_platform.h"</type> -¶ - <type category="define">#define <name>VK_MAKE_VERSION</name>(major, minor, patch) \ - «((major << 22) | (minor << 12) | patch)</type>» -¶ - <type category="define">// Vulkan API version supported by this file«« -#define <name>VK_API_VERSION</name> <type>VK_MAKE_VERSION</type>({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}})</type> -¶ - »»<type category="define">«« -#if (_MSC_VER >= 1800 || __cplusplus >= 201103L) -#define <name>VK_NONDISP_HANDLE_OPERATOR_BOOL</name>() explicit operator bool() const { return handle != 0; } -#else -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() -«#endif - »»»</type> -¶ - <type category="define">««« -#define <name>VK_DEFINE_HANDLE</name>(obj) typedef struct obj##_T* obj;</type> - »»»<type category="define">««« -#if defined(__cplusplus) - »»#if (_MSC_VER >= 1800 || __cplusplus >= 201103L) - »// The bool operator only works if there are no implicit conversions from an obj to - // a bool-compatible type, which can then be used to unintentionally violate type safety. - // C++11 and above supports the "explicit" keyword on conversion operators to stop this - // from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating - // the object handle as a bool in expressions like: - // if (obj) vkDestroy(obj); - #define VK_NONDISP_HANDLE_OPERATOR_BOOL() explicit operator bool() const { return handle != 0; } - #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - explicit obj(uint64_t x) : handle(x) { } \ - obj(decltype(nullptr)) : handle(0) { } - «#else» - #define VK_NONDISP_HANDLE_OPERATOR_BOOL() - #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj(uint64_t x) : handle(x) { } - «#endif - #define <name>VK_DEFINE_NONDISP_HANDLE</name>(obj) \» - struct obj { \ - obj() { } \ - VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj& operator =(uint64_t x) { handle = x; return *this; } \ - bool operator==(const obj& other) const { return handle == other.handle; } \ - bool operator!=(const obj& other) const { return handle != other.handle; } \ - bool operator!() const { return !handle; } \ - VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - uint64_t handle; \ - }; -««#else - »#define VK_DEFINE_NONDISP_HANDLE(obj) typedef struct obj##_T { uint64_t handle; } obj;« -#endif - »»</type> -¶ - <type category="define"> -#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800) || __cplusplus >= 201103L) - »#define <name>VK_NULL_HANDLE</name> nullptr -«#else - »#define VK_NULL_HANDLE 0 -«#endif - »»</type> -¶ - <type requires="vk_platform" name="VkDeviceSize"/> - <type requires="vk_platform" name="VkSampleMask"/> - <type requires="vk_platform" name="VkFlags"/> - <!-- Basic C types, pulled in via vk_platform.h --> - <type requires="vk_platform" name="char"/> - <type requires="vk_platform" name="float"/> - <type requires="vk_platform" name="VkBool32"/> - <type requires="vk_platform" name="uint8_t"/> - <type requires="vk_platform" name="uint32_t"/> - <type requires="vk_platform" name="uint64_t"/> - <type requires="vk_platform" name="int32_t"/> - <type requires="vk_platform" name="size_t"/> - <!-- Bitfield types --> - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{$bits := print (Macro "EnumName" $e | TrimRight "s") "Bits"}} - <type{{if $e.Entries}} requires="{{$bits}}"{{end}} category="bitmask">typedef <type>VkFlags</type> <name>{{$e.Name}}</name>;</type>§ - {{if $e.Entries}}{{Macro "XML.Docs" $e.Docs}} - {{else}}{{Macro "XML.Docs" (Strings $e.Docs "(no bits yet)")}} - {{end}} - {{end}} - {{end}} -¶ - <!-- Types which can be void pointers or class pointers, selected at compile time --> - {{range $i, $p := $.Pseudonyms}} - {{ if (GetAnnotation $p "dispatchHandle")}} - {{if Global "VK_DEFINE_HANDLE_TYPE_DEFINED"}} - <type category="handle">VK_DEFINE_HANDLE(<name>{{$p.Name}}</name>)</type> - {{else}} - {{Global "VK_DEFINE_HANDLE_TYPE_DEFINED" "YES"}} - <type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>{{$p.Name}}</name>)</type> - {{end}} - {{else if (GetAnnotation $p "nonDispatchHandle")}} - {{if Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED"}} - <type category="handle">VK_DEFINE_NONDISP_HANDLE(<name>{{$p.Name}}</name>)</type> - {{else}} - {{Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED" "YES"}} - <type category="handle"><type>VK_DEFINE_NONDISP_HANDLE</type>(<name>{{$p.Name}}</name>)</type> - {{end}} - {{end}} - {{end}} -¶ - <!-- Types generated from corresponding <enums> tags below --> - {{range $e := SortBy $.Enums "EnumName"}} - {{if and $e.Entries (not (GetAnnotation $e "internal"))}} - {{if $e.IsBitfield}} - <type name="{{Macro "EnumName" $e | TrimRight "s"}}Bits" category="enum"/> - {{else}} - <type name="{{$e.Name}}" category="enum"/> - {{end}} - {{end}} - {{end}} -¶ - <!-- The PFN_vk*Function types are used by VkAllocCallbacks below --> - <type>typedef void* (VKAPI *<name>PFN_vkAllocFunction</name>)(« - void* pUserData, - size_t size, - size_t alignment, - <type>VkSystemAllocType</type> allocType);</type>» - <type>typedef void (VKAPI *<name>PFN_vkFreeFunction</name>)(« - void* pUserData, - void* pMem);</type>» -¶ - <!-- The PFN_vkVoidFunction type are used by VkGet*ProcAddr below --> - <type>typedef void (VKAPI *<name>PFN_vkVoidFunction</name>)(void);</type> -¶ - <!-- Struct types --> - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{Macro "Struct" $c}} - {{end}} - {{end}} - «</types> -¶ - <!-- SECTION: Vulkan enumerant (token) definitions. --> -¶ - <enums namespace="VK" comment="Misc. hardcoded constants - not an enumerated type">» - <!-- This is part of the header boilerplate --> - {{range $d := $.Definitions}} - {{if HasPrefix $d.Name "VK_"}} - <enum value="{{$d.Expression}}" name="{{$d.Name}}"/>{{Macro "XML.Docs" $d.Docs}} - {{end}} - {{end}} - <enum value="1000.0f" name="VK_LOD_CLAMP_NONE"/> - <enum value="(-0U)" name="VK_REMAINING_MIP_LEVELS"/> - <enum value="(~0U)" name="VK_REMAINING_ARRAY_LAYERS"/> - <enum value="(_0ULL)" name="VK_WHOLE_SIZE"/> - <enum value="(~0U)" name="VK_ATTACHMENT_UNUSED"/> - <enum value="(~0U)" name="VK_QUEUE_FAMILY_IGNORED"/> - <enum value="(~0U)" name="VK_SUBPASS_EXTERNAL"/> - «</enums> -¶ - <!-- Unlike OpenGL, most tokens in Vulkan are actual typed enumerants in» - their own numeric namespaces. The "name" attribute is the C enum - type name, and is pulled in from a <type> definition above - (slightly clunky, but retains the type / enum distinction). "type" - attributes of "enum" or "bitmask" indicate that these values should - be generated inside an appropriate definition. -->« -¶ - {{range $e := $.Enums}} - {{if not (or $e.IsBitfield (GetAnnotation $e "internal"))}} - {{Macro "XML.Enum" $e}} - {{end}} - {{end}} -¶ - <!-- Flags --> - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{Macro "XML.Bitfield" $e}} - {{end}} - {{end}} -¶ - <!-- SECTION: Vulkan command definitions --> - <commands namespace="vk">» - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "XML.Function" $f}} - {{end}} - {{end}} - «</commands> -¶ - <!-- SECTION: Vulkan API interface definitions --> - <feature api="vulkan" name="VK_VERSION_1_0" number="1.0">» - <require comment="Header boilerplate">» - <type name="vk_platform"/> - «</require> - <require comment="API version">» - <type name="VK_API_VERSION"/> - «</require> - <require comment="API constants">» - <enum name="VK_LOD_CLAMP_NONE"/> - <enum name="VK_REMAINING_MIP_LEVELS"/> - <enum name="VK_REMAINING_ARRAY_LAYERS"/> - <enum name="VK_WHOLE_SIZE"/> - <enum name="VK_ATTACHMENT_UNUSED"/> - <enum name="VK_TRUE"/> - <enum name="VK_FALSE"/> - «</require> - <require comment="All functions (TODO: split by type)">» - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - <command name="{{$f.Name}}"/> - {{end}} - {{end}} - </require> - «<require comment="Types not directly used by the API">» - <!-- Include <type name="typename"/> here for e.g. structs that» - are not parameter types of commands, but still need to be - defined in the API. - «--> - <type name="VkBufferMemoryBarrier"/> - <type name="VkDispatchIndirectCmd"/> - <type name="VkDrawIndexedIndirectCmd"/> - <type name="VkDrawIndirectCmd"/> - <type name="VkImageMemoryBarrier"/> - <type name="VkMemoryBarrier"/> - «</require> - «</feature> -¶ - <!-- SECTION: Vulkan extension interface definitions (none yet) --> -«</registry> -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Bitfield"}} - {{AssertType $ "Enum"}} - - {{if $.Entries}} - <enums namespace="VK" name="{{Macro "EnumName" $ | TrimRight "s"}}Bits" type="bitmask">» - {{range $e := $.Entries}} - {{$pos := Bitpos $e.Value}} - <enum § - {{if gt $pos -1}} bitpos="{{$pos}}" § - {{else}}value="{{if $e.Value}}{{printf "0x%.8X" $e.Value}}{{else}}0{{end}}" § - {{end}}name="{{Macro "BitfieldEntryName" $e}}" § - {{if $d := $e.Docs}} comment="{{$d | JoinWith " "}}"{{end}}/> - {{end}} - «</enums> - {{end}} - -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified enum. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Enum"}} - {{AssertType $ "Enum"}} - - <enums namespace="VK" name="{{Macro "EnumName" $}}" type="enum" § - expand="{{Macro "EnumName" $ | SplitPascalCase | Upper | JoinWith "_"}}"{{if $.Docs}} comment="{{$.Docs | JoinWith " "}}"{{end}}>» - {{range $i, $e := $.Entries}} - <enum value="{{AsSigned $e.Value}}" name="{{Macro "BitfieldEntryName" $e}}"{{if $e.Docs}} comment="{{$e.Docs | JoinWith " "}}"{{end}}/> - {{end}} - {{if $lu := GetAnnotation $ "lastUnused"}} - <unused start="{{index $lu.Arguments 0}}"/> - {{end}} - «</enums> -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "Struct"}} - {{AssertType $ "Class"}} - - <type category="{{Macro "StructType" $}}" name="{{Macro "StructName" $}}"{{if $.Docs}} comment="{{$.Docs | JoinWith " "}}"{{end}}>» - {{range $f := $.Fields}} - <member>{{Node "XML.Type" $f}} <name>{{$f.Name}}</name>{{Macro "XML.ArrayPostfix" $f}}</member>{{Macro "XML.Docs" $f.Docs}} - {{end}} - «</type> -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits either 'struct' or 'union' for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "StructType"}} - {{AssertType $ "Class"}} - - {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function pointer typedef declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Function"}} - {{AssertType $ "Function"}} - - {{$ts := GetAnnotation $ "threadSafety"}} - <command{{if $ts}} threadsafe="{{index $ts.Arguments 0}}"{{end}}>» - <proto>{{Node "XML.Type" $.Return}} <name>{{$.Name}}</name></proto> - {{range $p := $.CallParameters}} - <param>{{Node "XML.Type" $p}} <name>{{$p.Name}}{{Macro "ArrayPostfix" $p}}</name></param> - {{end}} - «</command> -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the XML translation for the specified documentation block (string array). -------------------------------------------------------------------------------- -*/}} -{{define "XML.Docs"}} - {{if $}} <!-- {{JoinWith " " $ | Replace "<" "" | Replace ">" ""}} -->{{end}} -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C translation for the specified type. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Type.Class" }}<type>{{Macro "StructName" $.Type}}</type>{{end}} -{{define "XML.Type.Pseudonym" }}<type>{{$.Type.Name}}</type>{{end}} -{{define "XML.Type.Enum" }}<type>{{$.Type.Name}}</type>{{end}} -{{define "XML.Type.StaticArray"}}{{Node "XML.Type" $.Type.ValueType}}{{end}} -{{define "XML.Type.Pointer" }}{{if $.Type.Const}}{{Node "XML.ConstType" $.Type.To}}{{else}}{{Node "XML.Type" $.Type.To}}{{end}}*{{end}} -{{define "XML.Type.Slice" }}<type>{{Node "XML.Type" $.Type.To}}</type>*{{end}} -{{define "XML.Type#s8" }}<type>int8_t</type>{{end}} -{{define "XML.Type#u8" }}<type>uint8_t</type>{{end}} -{{define "XML.Type#s16" }}<type>int16_t</type>{{end}} -{{define "XML.Type#u16" }}<type>uint16_t</type>{{end}} -{{define "XML.Type#s32" }}<type>int32_t</type>{{end}} -{{define "XML.Type#u32" }}<type>uint32_t</type>{{end}} -{{define "XML.Type#f32" }}<type>float</type>{{end}} -{{define "XML.Type#s64" }}<type>int64_t</type>{{end}} -{{define "XML.Type#u64" }}<type>uint64_t</type>{{end}} -{{define "XML.Type#f64" }}<type>double</type>{{end}} -{{define "XML.Type#char" }}<type>char</type>{{end}} -{{define "XML.Type#void" }}void{{end}} - -{{define "XML.ConstType_Default"}}const {{Node "XML.Type" $.Type}}{{end}} -{{define "XML.ConstType.Pointer"}}{{Node "XML.Type" $.Type}} const{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a C type and name for the given parameter -------------------------------------------------------------------------------- -*/}} -{{define "XML.Parameter"}} - {{AssertType $ "Parameter"}} - - <type>{{Macro "ParameterType" $}}</type> <name>{{$.Name}}{{Macro "ArrayPostfix" $}}</name> -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits a comma-separated list of C type-name paired parameters for the given - command. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Parameters"}} - {{AssertType $ "Function"}} - - {{ForEach $.CallParameters "XML.Parameter" | JoinWith ", "}} - {{if not $.CallParameters}}<type>void</type>{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the fixed-size-array postfix for pseudonym types annotated with @array -------------------------------------------------------------------------------- -*/}} -{{define "XML.ArrayPostfix"}}{{Node "XML.ArrayPostfix" $}}{{end}} -{{define "XML.ArrayPostfix.StaticArray"}}[{{Node "XML.NamedValue" $.Type.SizeExpr}}]{{end}} -{{define "XML.ArrayPostfix_Default"}}{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the value of the given constant, or the <enum> tagged name if existant. -------------------------------------------------------------------------------- -*/}} -{{define "XML.NamedValue.Definition"}}<enum>{{$.Node.Name}}</enum>{{end}} -{{define "XML.NamedValue.EnumEntry"}}<enum>{{$.Node.Name}}</enum>{{end}} -{{define "XML.NamedValue_Default"}}{{$.Node}}{{end}} diff --git a/vulkan/api/templates/vulkan_h.tmpl b/vulkan/api/templates/vulkan_h.tmpl deleted file mode 100644 index 83a5e40804..0000000000 --- a/vulkan/api/templates/vulkan_h.tmpl +++ /dev/null @@ -1,295 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{Macro "DefineGlobals" $}} -{{$ | Macro "vulkan.h" | Format (Global "clang-format") | Write "../include/vulkan.h"}} - - -{{/* -------------------------------------------------------------------------------- - Entry point -------------------------------------------------------------------------------- -*/}} -{{define "vulkan.h"}} -#ifndef __vulkan_h_ -#define __vulkan_h_ 1 -¶ -#ifdef __cplusplus -extern "C" { -#endif -¶ -/* -** Copyright (c) 2015-2016 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ -¶ -/* -** This header is generated from the Khronos Vulkan API Registry. -** -*/ -¶ -#define VK_VERSION_1_0 1 -#include "vk_platform.h" -¶ -#define VK_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch)) -¶ -// Vulkan API version supported by this file -#define VK_API_VERSION \ - VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}}) -¶ -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) -#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) -¶ -#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L) - #define VK_NULL_HANDLE nullptr -#else - #define VK_NULL_HANDLE 0 -#endif -¶ -#define VK_DEFINE_HANDLE(obj) typedef struct obj##_T* obj; -¶ -#if defined(__cplusplus) -#if ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L) -// The bool operator only works if there are no implicit conversions from an obj to -// a bool-compatible type, which can then be used to unintentionally violate type safety. -// C++11 and above supports the "explicit" keyword on conversion operators to stop this -// from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating -// the object handle as a bool in expressions like: -// if (obj) vkDestroy(obj); -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - explicit operator bool() const { return handle != 0; } -#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - explicit obj(uint64_t x) : handle(x) { } \ - obj(decltype(nullptr)) : handle(0) { } -#else -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() -#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj(uint64_t x) : handle(x) { } -#endif -#define VK_DEFINE_NONDISP_HANDLE(obj) \ - struct obj { \ - obj() : handle(0) { } \ - VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj& operator=(uint64_t x) { \ - handle = x; \ - return *this; \ - } \ - bool operator==(const obj& other) const { return handle == other.handle; } \ - bool operator!=(const obj& other) const { return handle != other.handle; } \ - bool operator!() const { return !handle; } \ - VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - uint64_t handle; \ - }; -#else -#define VK_DEFINE_NONDISP_HANDLE(obj) \ - typedef struct obj##_T { uint64_t handle; } obj; -#endif -¶ -#define VK_LOD_CLAMP_NONE 1000.0f -#define VK_REMAINING_MIP_LEVELS (~0U) -#define VK_REMAINING_ARRAY_LAYERS (~0U) -#define VK_WHOLE_SIZE (~0ULL) -#define VK_ATTACHMENT_UNUSED (~0U) -define VK_QUEUE_FAMILY_IGNORED (~0U) -define VK_SUBPASS_EXTERNAL (~0U) -{{range $d := $.Definitions}} - {{if HasPrefix $d.Name "VK_"}}#define {{$d.Name}} {{$d.Expression}}{{end}} -{{end}} -¶ -{{range $i, $p := $.Pseudonyms}} - {{if GetAnnotation $p "dispatchHandle"}}VK_DEFINE_HANDLE({{$p.Name}}) - {{else if GetAnnotation $p "nonDispatchHandle"}}VK_DEFINE_NONDISP_HANDLE({{$p.Name}}) - {{end}} -{{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Enumerations -¶ - {{range $e := $.Enums}} - {{if not $e.IsBitfield}} - {{Macro "Enum" $e}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Flags -¶ - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{Macro "Bitfield" $e}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Vulkan structures -¶ - {{/* Function pointers */}} - {{range $f := AllCommands $}} - {{if GetAnnotation $f "pfn"}} - {{Macro "FunctionTypedef" $f}} - {{end}} - {{end}} -¶ - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{Macro "Struct" $c}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// API functions -¶ - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "FunctionTypedef" $f}} - {{end}} - {{end}} -¶ -#ifdef VK_NO_PROTOTYPES -¶ - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "FunctionDecl" $f}} - {{end}} - {{end}} -¶ -#endif -¶ -#ifdef __cplusplus -} -#endif -¶ -#endif -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "Bitfield"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef VkFlags {{Macro "EnumName" $}}; - {{if $.Entries}} - typedef enum { - {{range $b := $.Entries}} - {{Macro "BitfieldEntryName" $b}} = {{printf "0x%.8X" $b.Value}}, {{Macro "Docs" $b.Docs}} - {{end}} - } {{Macro "EnumName" $ | TrimRight "s"}}Bits; - {{end}} - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified enum. -------------------------------------------------------------------------------- -*/}} -{{define "Enum"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef enum { - {{range $i, $e := $.Entries}} - {{Macro "EnumEntry" $e}} = {{printf "0x%.8X" $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - ¶ - {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}} - {{if GetAnnotation $ "enumMaxOnly"}} - VK_MAX_ENUM({{$name | SplitOn "VK_"}}) - {{else}} - {{$first := Macro "EnumFirstEntry" $ | SplitOn $name | TrimLeft "_"}} - {{$last := Macro "EnumLastEntry" $ | SplitOn $name | TrimLeft "_"}} - VK_ENUM_RANGE({{$name | SplitOn "VK_"}}, {{$first}}, {{$last}}) - {{end}} - } {{Macro "EnumName" $}}; - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "Struct"}} - {{AssertType $ "Class"}} - - {{Macro "Docs" $.Docs}} - typedef {{Macro "StructType" $}} { - {{ForEach $.Fields "Field" | JoinWith "\n"}} - } {{Macro "StructName" $}}; - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class field. -------------------------------------------------------------------------------- -*/}} -{{define "Field"}} - {{AssertType $ "Field"}} - - {{Node "Type" $}} {{$.Name}}§ - {{Macro "ArrayPostfix" (TypeOf $)}}; {{Macro "Docs" $.Docs}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits either 'struct' or 'union' for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "StructType"}} - {{AssertType $ "Class"}} - - {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function pointer typedef declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "FunctionTypedef"}} - {{AssertType $ "Function"}} - - typedef {{Node "Type" $.Return}} (VKAPI* {{Macro "FunctionPtrName" $}})({{Macro "Parameters" $}}); -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "FunctionDecl"}} - {{AssertType $ "Function"}} - - {{if not (GetAnnotation $ "fptr")}} - {{Macro "Docs" $.Docs}} - {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}}); - {{end}} -{{end}} diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 23506bad54..d33e5528e8 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -16,30 +16,29 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "driver.h" + +#include <dlfcn.h> #include <malloc.h> #include <stdlib.h> #include <string.h> -#include <sys/prctl.h> - -#include <dlfcn.h> -#include <algorithm> -#include <array> -#include <new> - -#include <log/log.h> #include <android/dlext.h> #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> +#include <android-base/properties.h> #include <configstore/Utils.h> #include <cutils/properties.h> #include <graphicsenv/GraphicsEnv.h> +#include <log/log.h> +#include <sys/prctl.h> #include <utils/Timers.h> #include <utils/Trace.h> -#include <utils/Vector.h> -#include "android-base/properties.h" +#include <algorithm> +#include <array> +#include <new> +#include <vector> -#include "driver.h" #include "stubhal.h" using namespace android::hardware::configstore; @@ -809,8 +808,7 @@ VkResult EnumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { - - android::Vector<VkExtensionProperties> loader_extensions; + std::vector<VkExtensionProperties> loader_extensions; loader_extensions.push_back({ VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION}); @@ -833,7 +831,7 @@ VkResult EnumerateInstanceExtensionProperties( uint32_t count = std::min( *pPropertyCount, static_cast<uint32_t>(loader_extensions.size())); - std::copy_n(loader_extensions.begin(), count, pProperties); + std::copy_n(loader_extensions.data(), count, pProperties); if (count < loader_extensions.size()) { *pPropertyCount = count; @@ -879,8 +877,7 @@ VkResult EnumerateInstanceExtensionProperties( bool QueryPresentationProperties( VkPhysicalDevice physicalDevice, - VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) -{ + VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) { const InstanceData& data = GetData(physicalDevice); // GPDP2 must be present and enabled on the instance. @@ -920,7 +917,7 @@ VkResult EnumerateDeviceExtensionProperties( VkExtensionProperties* pProperties) { const InstanceData& data = GetData(physicalDevice); // extensions that are unconditionally exposed by the loader - android::Vector<VkExtensionProperties> loader_extensions; + std::vector<VkExtensionProperties> loader_extensions; loader_extensions.push_back({ VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION}); @@ -956,7 +953,7 @@ VkResult EnumerateDeviceExtensionProperties( uint32_t count = std::min( *pPropertyCount, static_cast<uint32_t>(loader_extensions.size())); - std::copy_n(loader_extensions.begin(), count, pProperties); + std::copy_n(loader_extensions.data(), count, pProperties); if (count < loader_extensions.size()) { *pPropertyCount = count; @@ -1245,11 +1242,10 @@ VkResult EnumeratePhysicalDeviceGroups( if (!device_count) return VK_INCOMPLETE; - android::Vector<VkPhysicalDevice> devices; - devices.resize(device_count); + std::vector<VkPhysicalDevice> devices(device_count); *pPhysicalDeviceGroupCount = device_count; - result = EnumeratePhysicalDevices(instance, &device_count, - devices.editArray()); + result = + EnumeratePhysicalDevices(instance, &device_count, devices.data()); if (result < 0) return result; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 524fe0e594..761d128d79 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -24,7 +24,6 @@ #include <ui/BufferQueueDefs.h> #include <utils/StrongPointer.h> #include <utils/Trace.h> -#include <utils/Vector.h> #include <algorithm> #include <unordered_set> @@ -132,7 +131,6 @@ int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { class TimingInfo { public: - TimingInfo() = default; TimingInfo(const VkPresentTimeGOOGLE* qp, uint64_t nativeFrameId) : vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0}, native_frame_id_(nativeFrameId) {} @@ -266,7 +264,7 @@ struct Swapchain { bool dequeued; } images[android::BufferQueueDefs::NUM_BUFFER_SLOTS]; - android::Vector<TimingInfo> timing; + std::vector<TimingInfo> timing; }; VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) { @@ -349,7 +347,7 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { uint32_t num_ready = 0; const size_t num_timings = swapchain.timing.size() - MIN_NUM_FRAMES_AGO + 1; for (uint32_t i = 0; i < num_timings; i++) { - TimingInfo& ti = swapchain.timing.editItemAt(i); + TimingInfo& ti = swapchain.timing[i]; if (ti.ready()) { // This TimingInfo is ready to be reported to the user. Add it // to the num_ready. @@ -419,7 +417,7 @@ void copy_ready_timings(Swapchain& swapchain, } uint32_t num_copied = 0; - size_t num_to_remove = 0; + int32_t num_to_remove = 0; for (uint32_t i = 0; i <= last_ready && num_copied < *count; i++) { const TimingInfo& ti = swapchain.timing[i]; if (ti.ready()) { @@ -431,7 +429,8 @@ void copy_ready_timings(Swapchain& swapchain, // Discard old frames that aren't ready if newer frames are ready. // We don't expect to get the timing info for those old frames. - swapchain.timing.removeItemsAt(0, num_to_remove); + swapchain.timing.erase(swapchain.timing.begin(), + swapchain.timing.begin() + num_to_remove); *count = num_copied; } @@ -817,11 +816,10 @@ VkResult GetPhysicalDeviceSurfaceFormats2KHR( } else { // temp vector for forwarding; we'll marshal it into the pSurfaceFormats // after the call. - android::Vector<VkSurfaceFormatKHR> surface_formats; - surface_formats.resize(*pSurfaceFormatCount); + std::vector<VkSurfaceFormatKHR> surface_formats(*pSurfaceFormatCount); VkResult result = GetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount, - &surface_formats.editItemAt(0)); + surface_formats.data()); if (result == VK_SUCCESS || result == VK_INCOMPLETE) { // marshal results individually due to stride difference. @@ -863,7 +861,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, } uint32_t max_buffer_count = static_cast<uint32_t>(query_value); - android::Vector<VkPresentModeKHR> present_modes; + std::vector<VkPresentModeKHR> present_modes; if (min_undequeued_buffers + 1 < max_buffer_count) present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR); @@ -883,7 +881,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, if (*count < num_modes) result = VK_INCOMPLETE; *count = std::min(*count, num_modes); - std::copy(present_modes.begin(), present_modes.begin() + int(*count), modes); + std::copy_n(present_modes.data(), *count, modes); } else { *count = num_modes; } @@ -1647,9 +1645,9 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { // Add a new timing record with the user's presentID and // the nativeFrameId. - swapchain.timing.push_back(TimingInfo(time, nativeFrameId)); + swapchain.timing.emplace_back(time, nativeFrameId); while (swapchain.timing.size() > MAX_TIMING_INFOS) { - swapchain.timing.removeAt(0); + swapchain.timing.erase(swapchain.timing.begin()); } if (time->desiredPresentTime) { // Set the desiredPresentTime: |