diff options
47 files changed, 615 insertions, 256 deletions
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp index 8dad47502f..be2c702034 100644 --- a/cmds/cmd/cmd.cpp +++ b/cmds/cmd/cmd.cpp @@ -185,7 +185,7 @@ int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, Te int argc = argv.size(); if (argc == 0) { - errorLog << "cmd: No service specified; use -l to list all services" << endl; + errorLog << "cmd: No service specified; use -l to list all running services. Use -w to start and wait for a service." << endl; return 20; } @@ -203,14 +203,22 @@ int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, Te return 0; } - const auto cmd = argv[0]; + bool waitForService = ((argc > 1) && (argv[0] == "-w")); + int serviceIdx = (waitForService) ? 1 : 0; + const auto cmd = argv[serviceIdx]; Vector<String16> args; String16 serviceName = String16(cmd.data(), cmd.size()); - for (int i = 1; i < argc; i++) { + for (int i = serviceIdx + 1; i < argc; i++) { args.add(String16(argv[i].data(), argv[i].size())); } - sp<IBinder> service = sm->checkService(serviceName); + sp<IBinder> service; + if(waitForService) { + service = sm->waitForService(serviceName); + } else { + service = sm->checkService(serviceName); + } + if (service == nullptr) { if (runMode == RunMode::kStandalone) { ALOGW("Can't find service %.*s", static_cast<int>(cmd.size()), cmd.data()); diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 83a34a3af2..772b9fe069 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2173,7 +2173,7 @@ static void PrepareToWriteToFile() { } if (ds.options_->do_screenshot) { - ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png"); + ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-png.tmp" : ".png"); } ds.tmp_path_ = ds.GetPath(".tmp"); ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt"); @@ -2192,7 +2192,7 @@ static void PrepareToWriteToFile() { ds.tmp_path_.c_str(), ds.screenshot_path_.c_str()); if (ds.options_->do_zip_file) { - ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip"); + ds.path_ = ds.GetPath(ds.CalledByApi() ? "-zip.tmp" : ".zip"); MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str()); create_parent_dirs(ds.path_.c_str()); ds.zip_file.reset(fopen(ds.path_.c_str(), "wb")); diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index eefbe4ffe2..d773790091 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -138,10 +138,10 @@ class OTAPreoptService { return 4; } - PrepareEnvironment(); + PrepareEnvironmentVariables(); - if (!PrepareBootImage(/* force */ false)) { - LOG(ERROR) << "Failed preparing boot image."; + if (!EnsureBootImageAndDalvikCache()) { + LOG(ERROR) << "Bad boot image."; return 5; } @@ -302,7 +302,7 @@ private: return parameters_.ReadArguments(argc, const_cast<const char**>(argv)); } - void PrepareEnvironment() { + void PrepareEnvironmentVariables() { environ_.push_back(StringPrintf("BOOTCLASSPATH=%s", boot_classpath_.c_str())); environ_.push_back(StringPrintf("ANDROID_DATA=%s", GetOTADataDirectory().c_str())); environ_.push_back(StringPrintf("ANDROID_ROOT=%s", android_root_.c_str())); @@ -312,9 +312,8 @@ private: } } - // Ensure that we have the right boot image. The first time any app is - // compiled, we'll try to generate it. - bool PrepareBootImage(bool force) const { + // Ensure that we have the right boot image and cache file structures. + bool EnsureBootImageAndDalvikCache() const { if (parameters_.instruction_set == nullptr) { LOG(ERROR) << "Instruction set missing."; return false; @@ -340,34 +339,19 @@ private: } } - // Check whether we have files in /data. - // TODO: check that the files are correct wrt/ jars. - std::string art_path = isa_path + "/system@framework@boot.art"; - std::string oat_path = isa_path + "/system@framework@boot.oat"; - bool cleared = false; - if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) { - // Files exist, assume everything is alright if not forced. Otherwise clean up. - if (!force) { - return true; - } - ClearDirectory(isa_path); - cleared = true; - } + // Clear cached artifacts. + ClearDirectory(isa_path); - // Check whether we have an image in /system. + // Check whether we have a boot image. // TODO: check that the files are correct wrt/ jars. - std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa); - if (access(preopted_boot_art_path.c_str(), F_OK) == 0) { - // Note: we ignore |force| here. - return true; - } - - - if (!cleared) { - ClearDirectory(isa_path); + std::string preopted_boot_art_path = + StringPrintf("/apex/com.android.art/javalib/%s/boot.art", isa); + if (access(preopted_boot_art_path.c_str(), F_OK) != 0) { + PLOG(ERROR) << "Bad access() to " << preopted_boot_art_path; + return false; } - return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa); + return true; } static bool CreatePath(const std::string& path) { @@ -432,77 +416,6 @@ private: CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory."; } - bool Dex2oatBootImage(const std::string& boot_cp, - const std::string& art_path, - const std::string& oat_path, - const char* isa) const { - // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc. - std::vector<std::string> cmd; - cmd.push_back(kDex2oatPath); - cmd.push_back(StringPrintf("--image=%s", art_path.c_str())); - for (const std::string& boot_part : Split(boot_cp, ":")) { - cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str())); - } - cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str())); - - 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)); - - // These things are pushed by AndroidRuntime, see frameworks/base/core/jni/AndroidRuntime.cpp. - AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xms", - "-Xms", - true, - cmd); - AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xmx", - "-Xmx", - true, - cmd); - AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-filter", - "--compiler-filter=", - false, - cmd); - 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"); - if (extra_opts != nullptr) { - std::vector<std::string> extra_vals = Split(*extra_opts, " "); - cmd.insert(cmd.end(), extra_vals.begin(), extra_vals.end()); - } - // TODO: Should we lower this? It's usually set close to max, because - // normally there's not much else going on at boot. - AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-threads", - "-j", - false, - cmd); - AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-cpu-set", - "--cpu-set=", - false, - cmd); - AddCompilerOptionFromSystemProperty( - StringPrintf("dalvik.vm.isa.%s.variant", isa).c_str(), - "--instruction-set-variant=", - false, - cmd); - AddCompilerOptionFromSystemProperty( - StringPrintf("dalvik.vm.isa.%s.features", isa).c_str(), - "--instruction-set-features=", - false, - cmd); - - std::string error_msg; - bool result = Exec(cmd, &error_msg); - if (!result) { - LOG(ERROR) << "Could not generate boot image: " << error_msg; - } - return result; - } - static const char* ParseNull(const char* arg) { return (strcmp(arg, "!") == 0) ? nullptr : arg; } @@ -592,22 +505,6 @@ private: return 0; } - // If the dexopt failed, we may have a stale boot image from a previous OTA run. - // Then regenerate and retry. - if (WEXITSTATUS(dexopt_result) == - static_cast<int>(::art::dex2oat::ReturnCode::kCreateRuntime)) { - if (!PrepareBootImage(/* force */ true)) { - LOG(ERROR) << "Forced boot image creating failed. Original error return was " - << dexopt_result; - return dexopt_result; - } - - int dexopt_result_boot_image_retry = Dexopt(); - if (dexopt_result_boot_image_retry == 0) { - return 0; - } - } - // If this was a profile-guided run, we may have profile version issues. Try to downgrade, // if possible. if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) { diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index abe64365f3..cbbea128a6 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -522,6 +522,11 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IB return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } + if (serviceIt->second.guaranteeClient) { + LOG(INFO) << "Tried to unregister " << name << ", but there is about to be a client."; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + int clients = handleServiceClientCallback(name, false); // clients < 0: feature not implemented or other error. Assume clients. @@ -532,6 +537,8 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IB if (clients < 0 || clients > 2) { // client callbacks are either disabled or there are other clients LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients; + // Set this flag to ensure the clients are acknowledged in the next callback + serviceIt->second.guaranteeClient = true; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } diff --git a/include/android/thermal.h b/include/android/thermal.h index 0f4b4d9b8d..3247fa167b 100644 --- a/include/android/thermal.h +++ b/include/android/thermal.h @@ -109,7 +109,7 @@ typedef struct AThermalManager AThermalManager; * It's passed the updated thermal status as parameter, as well as the * pointer provided by the client that registered a callback. */ -typedef int (*AThermal_StatusCallback)(void *data, AThermalStatus status); +typedef void (*AThermal_StatusCallback)(void *data, AThermalStatus status); /** * Acquire an instance of the thermal manager. This must be freed using diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp index 5e4c98fc7a..4f2709d91a 100644 --- a/libs/binder/ActivityManager.cpp +++ b/libs/binder/ActivityManager.cpp @@ -98,6 +98,15 @@ int32_t ActivityManager::getUidProcessState(const uid_t uid, const String16& cal return PROCESS_STATE_UNKNOWN; } +bool ActivityManager::isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) +{ + sp<IActivityManager> service = getService(); + if (service != nullptr) { + return service->isUidActiveOrForeground(uid, callingPackage); + } + return false; +} + status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) { sp<IActivityManager> service = getService(); if (service != nullptr) { diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index bc541f4d31..e6cfeb4943 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -158,7 +158,9 @@ cc_library { filegroup { name: "libbinder_aidl", srcs: [ + "aidl/android/content/pm/IPackageChangeObserver.aidl", "aidl/android/content/pm/IPackageManagerNative.aidl", + "aidl/android/content/pm/PackageChangeEvent.aidl", "aidl/android/os/IClientCallback.aidl", "aidl/android/os/IServiceCallback.aidl", "aidl/android/os/IServiceManager.aidl", diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 1eb5363ae2..9e1249baf4 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -104,6 +104,18 @@ public: } return reply.readInt32(); } + + virtual bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeInt32(uid); + data.writeString16(callingPackage); + remote()->transact(IS_UID_ACTIVE_OR_FOREGROUND_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32() == 1; + } }; // ------------------------------------------------------------------------------------ diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp index 71d8130df9..74aece81f7 100644 --- a/libs/binder/LazyServiceRegistrar.cpp +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -31,11 +31,16 @@ using AidlServiceManager = android::os::IServiceManager; class ClientCounterCallback : public ::android::os::BnClientCallback { public: - ClientCounterCallback() : mNumConnectedServices(0) {} + ClientCounterCallback() : mNumConnectedServices(0), mForcePersist(false) {} bool registerService(const sp<IBinder>& service, const std::string& name, bool allowIsolated, int dumpFlags); + /** + * Set a flag to prevent services from automatically shutting down + */ + void forcePersist(bool persist); + protected: Status onClients(const sp<IBinder>& service, bool clients) override; @@ -60,6 +65,8 @@ private: * Map of registered names and services */ std::map<std::string, Service> mRegisteredServices; + + bool mForcePersist; }; bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name, @@ -88,6 +95,14 @@ bool ClientCounterCallback::registerService(const sp<IBinder>& service, const st return true; } +void ClientCounterCallback::forcePersist(bool persist) { + mForcePersist = persist; + if(!mForcePersist) { + // Attempt a shutdown in case the number of clients hit 0 while the flag was on + tryShutdown(); + } +} + /** * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple * invocations could occur on different threads however. @@ -103,14 +118,21 @@ Status ClientCounterCallback::onClients(const sp<IBinder>& service, bool clients mNumConnectedServices, mRegisteredServices.size(), String8(service->getInterfaceDescriptor()).string(), clients); - if (mNumConnectedServices == 0) { - tryShutdown(); - } - + tryShutdown(); return Status::ok(); } void ClientCounterCallback::tryShutdown() { + if(mNumConnectedServices > 0) { + // Should only shut down if there are no clients + return; + } + + if(mForcePersist) { + ALOGI("Shutdown prevented by forcePersist override flag."); + return; + } + ALOGI("Trying to shut down the service. No clients in use for any service in process."); auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager())); @@ -165,5 +187,9 @@ status_t LazyServiceRegistrar::registerService(const sp<IBinder>& service, const return OK; } +void LazyServiceRegistrar::forcePersist(bool persist) { + mClientCC->forcePersist(persist); +} + } // namespace hardware } // namespace android
\ No newline at end of file diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl new file mode 100644 index 0000000000..6929a6cb49 --- /dev/null +++ b/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.content.pm.PackageChangeEvent; + +/** + * This is a non-blocking notification when a package has changed. + * + * @hide + */ +oneway interface IPackageChangeObserver { + void onPackageChanged(in PackageChangeEvent event); +} diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 618f88c66d..dc8d74c052 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -17,6 +17,8 @@ package android.content.pm; +import android.content.pm.IPackageChangeObserver; + /** * Parallel implementation of certain {@link PackageManager} APIs that need to * be exposed to native code. @@ -90,4 +92,13 @@ interface IPackageManagerNative { /* Returns the names of all packages. */ @utf8InCpp String[] getAllPackages(); + + /** Register an extra package change observer to receive the multi-cast. */ + void registerPackageChangeObserver(in IPackageChangeObserver observer); + + /** + * Unregister an existing package change observer. + * This does nothing if this observer was not already registered. + */ + void unregisterPackageChangeObserver(in IPackageChangeObserver observer); } diff --git a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl b/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl new file mode 100644 index 0000000000..e30e9072fc --- /dev/null +++ b/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +/** + * This event is designed for notification to native code listener about + * any changes on a package including update, deletion and etc. + * + * @hide + */ +parcelable PackageChangeEvent { + @utf8InCpp String packageName; + long version; + long lastUpdateTimeMillis; + boolean newInstalled; + boolean dataRemoved; + boolean isDeleted; +} diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h index 9108e31758..0bb6d28da4 100644 --- a/libs/binder/include/binder/ActivityManager.h +++ b/libs/binder/include/binder/ActivityManager.h @@ -46,25 +46,24 @@ public: PROCESS_STATE_PERSISTENT = 0, PROCESS_STATE_PERSISTENT_UI = 1, PROCESS_STATE_TOP = 2, - PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3, - PROCESS_STATE_BOUND_TOP = 4, - PROCESS_STATE_FOREGROUND_SERVICE = 5, - PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6, - PROCESS_STATE_IMPORTANT_FOREGROUND = 7, - PROCESS_STATE_IMPORTANT_BACKGROUND = 8, - PROCESS_STATE_TRANSIENT_BACKGROUND = 9, - PROCESS_STATE_BACKUP = 10, - PROCESS_STATE_SERVICE = 11, - PROCESS_STATE_RECEIVER = 12, - PROCESS_STATE_TOP_SLEEPING = 13, - PROCESS_STATE_HEAVY_WEIGHT = 14, - PROCESS_STATE_HOME = 15, - PROCESS_STATE_LAST_ACTIVITY = 16, - PROCESS_STATE_CACHED_ACTIVITY = 17, - PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18, - PROCESS_STATE_CACHED_RECENT = 19, - PROCESS_STATE_CACHED_EMPTY = 20, - PROCESS_STATE_NONEXISTENT = 21, + PROCESS_STATE_BOUND_TOP = 3, + PROCESS_STATE_FOREGROUND_SERVICE = 4, + PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5, + PROCESS_STATE_IMPORTANT_FOREGROUND = 6, + PROCESS_STATE_IMPORTANT_BACKGROUND = 7, + PROCESS_STATE_TRANSIENT_BACKGROUND = 8, + PROCESS_STATE_BACKUP = 9, + PROCESS_STATE_SERVICE = 10, + PROCESS_STATE_RECEIVER = 11, + PROCESS_STATE_TOP_SLEEPING = 12, + PROCESS_STATE_HEAVY_WEIGHT = 13, + PROCESS_STATE_HOME = 14, + PROCESS_STATE_LAST_ACTIVITY = 15, + PROCESS_STATE_CACHED_ACTIVITY = 16, + PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17, + PROCESS_STATE_CACHED_RECENT = 18, + PROCESS_STATE_CACHED_EMPTY = 19, + PROCESS_STATE_NONEXISTENT = 20, }; ActivityManager(); @@ -77,6 +76,7 @@ public: void unregisterUidObserver(const sp<IUidObserver>& observer); bool isUidActive(const uid_t uid, const String16& callingPackage); int getUidProcessState(const uid_t uid, const String16& callingPackage); + bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage); status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient); diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index e0248f6624..1815ecc67f 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -39,13 +39,15 @@ public: virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0; virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0; virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage) = 0; + virtual bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) = 0; enum { OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, REGISTER_UID_OBSERVER_TRANSACTION, UNREGISTER_UID_OBSERVER_TRANSACTION, IS_UID_ACTIVE_TRANSACTION, - GET_UID_PROCESS_STATE_TRANSACTION + GET_UID_PROCESS_STATE_TRANSACTION, + IS_UID_ACTIVE_OR_FOREGROUND_TRANSACTION, }; }; diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h index efdecc4eca..6d711bc10f 100644 --- a/libs/binder/include/binder/LazyServiceRegistrar.h +++ b/libs/binder/include/binder/LazyServiceRegistrar.h @@ -34,6 +34,12 @@ class LazyServiceRegistrar { const std::string& name = "default", bool allowIsolated = false, int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT); + /** + * Force the service to persist, even when it has 0 clients. + * If setting this flag from the server side, make sure to do so before calling registerService, + * or there may be a race with the default dynamic shutdown. + */ + void forcePersist(bool persist); private: std::shared_ptr<internal::ClientCounterCallback> mClientCC; diff --git a/libs/gui/tests/AndroidTest.xml b/libs/gui/tests/AndroidTest.xml index c02e020be6..5e09fff6bb 100644 --- a/libs/gui/tests/AndroidTest.xml +++ b/libs/gui/tests/AndroidTest.xml @@ -18,6 +18,10 @@ <option name="cleanup" value="true" /> <option name="push" value="libgui_test->/data/local/tmp/libgui_test" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> + <option name="screen-always-on" value="on" /> + </target_preparer> <option name="test-suite-tag" value="apct" /> <test class="com.android.tradefed.testtype.GTest" > <option name="native-test-device-path" value="/data/local/tmp" /> diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h index c2cda17a6f..f1e825286e 100644 --- a/libs/ui/include/ui/Size.h +++ b/libs/ui/include/ui/Size.h @@ -109,11 +109,11 @@ struct Size { // Takes a value of type FromType, and ensures it can be represented as a value of type ToType, // clamping the input value to the output range if necessary. template <typename ToType, typename FromType> - static Size::remove_cv_reference_t<ToType> clamp( - typename std::enable_if< - std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_bounded && - std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_bounded, - FromType&&>::type v) { + static Size::remove_cv_reference_t<ToType> + clamp(typename std::enable_if< + std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_specialized && + std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_specialized, + FromType>::type v) { using BareToType = remove_cv_reference_t<ToType>; using BareFromType = remove_cv_reference_t<FromType>; static constexpr auto toHighest = std::numeric_limits<BareToType>::max(); @@ -121,21 +121,58 @@ struct Size { static constexpr auto fromHighest = std::numeric_limits<BareFromType>::max(); static constexpr auto fromLowest = std::numeric_limits<BareFromType>::lowest(); - // A clamp is needed if the range of FromType is not a subset of the range of ToType - static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest); + // Get the closest representation of [toLowest, toHighest] in type + // FromType to use to clamp the input value before conversion. + + // std::common_type<...> is used to get a value-preserving type for the + // top end of the range. + using CommonHighestType = std::common_type_t<BareToType, BareFromType>; + + // std::make_signed<std::common_type<...>> is used to get a + // value-preserving type for the bottom end of the range, except this is + // a bit trickier for non-integer types like float. + using CommonLowestType = + std::conditional_t<std::numeric_limits<CommonHighestType>::is_integer, + std::make_signed_t<std::conditional_t< + std::numeric_limits<CommonHighestType>::is_integer, + CommonHighestType, int /* not used */>>, + CommonHighestType>; + + // We can then compute the clamp range in a way that can be later + // trivially converted to either the 'from' or 'to' types, and be + // representabile in either. + static constexpr auto commonClampHighest = + std::min(static_cast<CommonHighestType>(fromHighest), + static_cast<CommonHighestType>(toHighest)); + static constexpr auto commonClampLowest = + std::max(static_cast<CommonLowestType>(fromLowest), + static_cast<CommonLowestType>(toLowest)); + + static constexpr auto fromClampHighest = static_cast<BareFromType>(commonClampHighest); + static constexpr auto fromClampLowest = static_cast<BareFromType>(commonClampLowest); + + // A clamp is needed only if the range we are clamping to is not the + // same as the range of the input. + static constexpr bool isClampNeeded = + (fromLowest != fromClampLowest) || (fromHighest != fromClampHighest); // If a clamp is not needed, the conversion is just a trivial cast. if (!isClampNeeded) { - return static_cast<ToType>(v); + return static_cast<BareToType>(v); } - // Otherwise we need to carefully compare the limits of ToType (casted - // for the comparisons to be warning free to FromType) while still - // ensuring we return a value clamped to the range of ToType. - return v < static_cast<const BareFromType>(toLowest) - ? toLowest - : (v > static_cast<const BareFromType>(toHighest) ? toHighest - : static_cast<ToType>(v)); + // Note: Clang complains about the value of INT32_MAX not being + // convertible back to int32_t from float if this is made "constexpr", + // when clamping a float value to an int32_t value. This is however + // covered by a test case to ensure the run-time cast works correctly. + const auto toClampHighest = static_cast<BareToType>(commonClampHighest); + const auto toClampLowest = static_cast<BareToType>(commonClampLowest); + + // Otherwise clamping is done by using the already computed endpoints + // for each type. + return (v <= fromClampLowest) + ? toClampLowest + : ((v >= fromClampHighest) ? toClampHighest : static_cast<BareToType>(v)); } }; diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp index 40dc702a8b..38f37ad827 100644 --- a/libs/ui/tests/Size_test.cpp +++ b/libs/ui/tests/Size_test.cpp @@ -186,9 +186,34 @@ TEST(SizeTest, Int8RangeIsNotClamped) { TEST(SizeTest, FloatRangeIsClamped) { ClampTest(std::numeric_limits<float>::max(), std::numeric_limits<int32_t>::max()); + ClampTest(nexttowardf(std::numeric_limits<int32_t>::max(), std::numeric_limits<float>::max()), + std::numeric_limits<int32_t>::max()); + ClampTest(static_cast<float>(std::numeric_limits<int32_t>::max()), + std::numeric_limits<int32_t>::max()); + ClampTest(nexttowardf(std::numeric_limits<int32_t>::max(), 0), + static_cast<int32_t>(nexttowardf(std::numeric_limits<int32_t>::max(), 0))); ClampTest(float(0), int32_t(0)); + ClampTest(nexttowardf(std::numeric_limits<int32_t>::lowest(), 0), + static_cast<int32_t>(nexttowardf(std::numeric_limits<int32_t>::lowest(), 0))); + ClampTest(static_cast<float>(std::numeric_limits<int32_t>::lowest()), + std::numeric_limits<int32_t>::lowest()); + ClampTest(nexttowardf(std::numeric_limits<int32_t>::lowest(), + std::numeric_limits<float>::lowest()), + std::numeric_limits<int32_t>::lowest()); ClampTest(std::numeric_limits<float>::lowest(), std::numeric_limits<int32_t>::lowest()); } +TEST(SizeTest, Uint32RangeIsClamped) { + ClampTest(std::numeric_limits<uint32_t>::max(), std::numeric_limits<int32_t>::max()); + ClampTest(std::numeric_limits<uint32_t>::max() - 1, std::numeric_limits<int32_t>::max()); + ClampTest(static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) + 1, + std::numeric_limits<int32_t>::max()); + ClampTest(static_cast<uint32_t>(std::numeric_limits<int32_t>::max()), + std::numeric_limits<int32_t>::max()); + ClampTest(static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) - 1, + std::numeric_limits<int32_t>::max() - 1); + ClampTest(uint32_t(0), int32_t(0)); +} + } // namespace ui } // namespace android diff --git a/opengl/TEST_MAPPING b/opengl/TEST_MAPPING new file mode 100644 index 0000000000..d391dce2de --- /dev/null +++ b/opengl/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsGpuToolsHostTestCases" + } + ] +} diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp index 8ff0711f55..c3da216002 100644 --- a/services/automotive/display/Android.bp +++ b/services/automotive/display/Android.bp @@ -40,4 +40,8 @@ cc_binary { cflags: [ "-DLOG_TAG=\"AutomotiveDisplayService\"" ], + + vintf_fragments: [ + "manifest_android.frameworks.automotive.display@1.0.xml", + ], } diff --git a/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml b/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml new file mode 100644 index 0000000000..464dcac8bb --- /dev/null +++ b/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="framework"> + <hal> + <name>android.frameworks.automotive.display</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IAutomotiveDisplayProxyService</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index aeffb0e185..4c3b3e502d 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -183,10 +183,7 @@ void FramebufferSurface::onFrameCommitted() { } ui::Size FramebufferSurface::limitFramebufferSize(uint32_t width, uint32_t height) { - // TODO(b/149495759): Use the ui::Size constructor once it no longer is broken. - ui::Size framebufferSize; - framebufferSize.width = width; - framebufferSize.height = height; + ui::Size framebufferSize(width, height); bool wasLimited = true; if (width > mMaxWidth && mMaxWidth != 0) { float aspectRatio = float(width) / float(height); diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 776e98463f..4e3f85f53e 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -30,6 +30,7 @@ #include "EventThread.h" namespace android { +using base::StringAppendF; DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name) @@ -107,6 +108,12 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { } } +void DispSyncSource::dump(std::string& result) const { + std::lock_guard lock(mVsyncMutex); + StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled"); + mDispSync->dump(result); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 328b8c176f..f278712407 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -36,6 +36,8 @@ public: void setCallback(VSyncSource::Callback* callback) override; void setPhaseOffset(nsecs_t phaseOffset) override; + void dump(std::string&) const override; + private: // The following method is the implementation of the DispSync::Callback. virtual void onDispSyncEvent(nsecs_t when); @@ -52,7 +54,7 @@ private: std::mutex mCallbackMutex; VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr; - std::mutex mVsyncMutex; + mutable std::mutex mVsyncMutex; TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex); bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index acab5a6249..0d6a92e08f 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -425,7 +425,12 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { // display is off, keep feeding clients at 60 Hz. const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms; if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) { - ALOGW_IF(mState == State::VSync, "Faking VSYNC due to driver stall"); + if (mState == State::VSync) { + ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName); + std::string debugInfo = "VsyncSource debug info:\n"; + mVSyncSource->dump(debugInfo); + ALOGW("%s", debugInfo.c_str()); + } LOG_FATAL_IF(!mVSyncState); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 466234d3d7..98b1876994 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -66,6 +66,8 @@ public: virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(Callback* callback) = 0; virtual void setPhaseOffset(nsecs_t phaseOffset) = 0; + + virtual void dump(std::string& result) const = 0; }; class EventThreadConnection : public BnDisplayEventConnection { diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h index fa46e6f589..31da588b72 100644 --- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h +++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h @@ -45,6 +45,7 @@ public: const char* getName() const override { return "inject"; } void setVSyncEnabled(bool) override {} void setPhaseOffset(nsecs_t) override {} + void dump(std::string&) const override {} private: std::mutex mCallbackMutex; diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 7941cda6ef..43883fb387 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -36,6 +36,19 @@ bool fpsEqualsWithMargin(float fpsA, float fpsB) { return std::abs(fpsA - fpsB) <= MARGIN; } +std::vector<float> getRefreshRatesFromConfigs( + const android::scheduler::RefreshRateConfigs& refreshRateConfigs) { + const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates(); + std::vector<float> refreshRates; + refreshRates.reserve(allRefreshRates.size()); + + for (const auto& [ignored, refreshRate] : allRefreshRates) { + refreshRates.emplace_back(refreshRate->fps); + } + + return refreshRates; +} + } // namespace namespace android::scheduler { @@ -45,14 +58,21 @@ PhaseConfiguration::~PhaseConfiguration() = default; namespace impl { PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs) - : // Below defines the threshold when an offset is considered to be negative, i.e. targeting - // for the N+2 vsync instead of N+1. This means that: - // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync. - // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync. - mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") - .value_or(std::numeric_limits<nsecs_t>::max())), - mOffsets(initializeOffsets(refreshRateConfigs)), - mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {} + : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs), + refreshRateConfigs.getCurrentRefreshRate().fps, + // Below defines the threshold when an offset is considered to be negative, + // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset + // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For + // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW + // vsync. + getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") + .value_or(std::numeric_limits<nsecs_t>::max())) {} + +PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps, + nsecs_t thresholdForNextVsync) + : mThresholdForNextVsync(thresholdForNextVsync), + mOffsets(initializeOffsets(refreshRates)), + mRefreshRateFps(currentFps) {} void PhaseOffsets::dump(std::string& result) const { const auto [early, earlyGl, late] = getCurrentOffsets(); @@ -67,12 +87,12 @@ void PhaseOffsets::dump(std::string& result) const { } std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets( - const scheduler::RefreshRateConfigs& refreshRateConfigs) const { + const std::vector<float>& refreshRates) const { std::unordered_map<float, Offsets> offsets; - for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) { - const float fps = refreshRate->fps; - offsets.emplace(fps, getPhaseOffsets(fps, refreshRate->vsyncPeriod)); + for (const auto& refreshRate : refreshRates) { + offsets.emplace(refreshRate, + getPhaseOffsets(refreshRate, static_cast<nsecs_t>(1e9f / refreshRate))); } return offsets; } @@ -243,19 +263,6 @@ PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) }; } -static std::vector<float> getRefreshRatesFromConfigs( - const android::scheduler::RefreshRateConfigs& refreshRateConfigs) { - const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates(); - std::vector<float> refreshRates; - refreshRates.reserve(allRefreshRates.size()); - - for (const auto& [ignored, refreshRate] : allRefreshRates) { - refreshRates.emplace_back(refreshRate->fps); - } - - return refreshRates; -} - std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets( const std::vector<float>& refreshRates) const { std::unordered_map<float, Offsets> offsets; diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index 208f06b185..fa8011d74b 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -66,9 +66,12 @@ public: // Returns current offsets in human friendly format. void dump(std::string& result) const override; -private: +protected: + // Used for unit tests + PhaseOffsets(const std::vector<float>& refreshRates, float currentFps, + nsecs_t thresholdForNextVsync); std::unordered_map<float, Offsets> initializeOffsets( - const scheduler::RefreshRateConfigs&) const; + const std::vector<float>& refreshRates) const; Offsets getDefaultOffsets(nsecs_t vsyncPeriod) const; Offsets getHighFpsOffsets(nsecs_t vsyncPeriod) const; Offsets getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 920f0ec331..cd6075f5b4 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -419,20 +419,6 @@ void Scheduler::registerLayer(Layer* layer) { mRefreshRateConfigs.getMaxRefreshRate().fps, scheduler::LayerHistory::LayerVoteType::Heuristic); } - - // TODO(146935143): Simulate youtube app vote. This should be removed once youtube calls the - // API to set desired rate - { - const auto vote = property_get_int32("experimental.sf.force_youtube_vote", 0); - if (vote != 0 && - layer->getName() == - "SurfaceView - " - "com.google.android.youtube/" - "com.google.android.apps.youtube.app.WatchWhileActivity#0") { - layer->setFrameRate( - Layer::FrameRate(vote, Layer::FrameRateCompatibility::ExactOrMultiple)); - } - } } } diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h index a6fb3a4df0..2a2d7c5279 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -108,6 +108,8 @@ public: */ virtual CancelResult cancel(CallbackToken token) = 0; + virtual void dump(std::string& result) const = 0; + protected: VSyncDispatch() = default; VSyncDispatch(VSyncDispatch const&) = delete; diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index d0f18abe77..460d4a5c3c 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -15,6 +15,7 @@ */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <android-base/stringprintf.h> #include <utils/Trace.h> #include <vector> @@ -23,6 +24,7 @@ #include "VSyncTracker.h" namespace android::scheduler { +using base::StringAppendF; VSyncDispatch::~VSyncDispatch() = default; VSyncTracker::~VSyncTracker() = default; @@ -122,6 +124,28 @@ void VSyncDispatchTimerQueueEntry::ensureNotRunning() { mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; }); } +void VSyncDispatchTimerQueueEntry::dump(std::string& result) const { + std::lock_guard<std::mutex> lk(mRunningMutex); + std::string armedInfo; + if (mArmedInfo) { + StringAppendF(&armedInfo, "[wake up in %.2fms for vsync %.2fms from now]", + (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f, + (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f); + } + + StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(), + mRunning ? "(in callback function)" : "", armedInfo.c_str()); + StringAppendF(&result, "\t\t\tmWorkDuration: %.2fms mEarliestVsync: %.2fms relative to now\n", + mWorkDuration / 1e6f, (mEarliestVsync - systemTime()) / 1e6f); + + if (mLastDispatchTime) { + StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n", + (systemTime() - *mLastDispatchTime) / 1e6f); + } else { + StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n"); + } +} + VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncTracker& tracker, nsecs_t timerSlack, nsecs_t minVsyncDistance) @@ -296,6 +320,18 @@ CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) { return CancelResult::TooLate; } +void VSyncDispatchTimerQueue::dump(std::string& result) const { + std::lock_guard<decltype(mMutex)> lk(mMutex); + StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f, + mMinVsyncDistance / 1e6f); + StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n", + (mIntendedWakeupTime - systemTime()) / 1e6f); + StringAppendF(&result, "\tCallbacks:\n"); + for (const auto& [token, entry] : mCallbacks) { + entry->dump(result); + } +} + VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch, VSyncDispatch::Callback const& callbackFn, std::string const& callbackName) diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index fd0a034423..390e0c460f 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -71,6 +71,8 @@ public: // Block calling thread while the callback is executing. void ensureNotRunning(); + void dump(std::string& result) const; + private: std::string const mName; VSyncDispatch::Callback const mCallback; @@ -86,7 +88,7 @@ private: std::optional<ArmingInfo> mArmedInfo; std::optional<nsecs_t> mLastDispatchTime; - std::mutex mRunningMutex; + mutable std::mutex mRunningMutex; std::condition_variable mCv; bool mRunning GUARDED_BY(mRunningMutex) = false; }; @@ -112,6 +114,7 @@ public: void unregisterCallback(CallbackToken token) final; ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final; CancelResult cancel(CallbackToken token) final; + void dump(std::string& result) const final; private: VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 257b8b16bf..a3cb7725a7 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -22,6 +22,7 @@ //#define LOG_NDEBUG 0 #include "VSyncPredictor.h" #include <android-base/logging.h> +#include <android-base/stringprintf.h> #include <cutils/compiler.h> #include <cutils/properties.h> #include <utils/Log.h> @@ -31,6 +32,7 @@ #include <sstream> namespace android::scheduler { +using base::StringAppendF; static auto constexpr kMaxPercent = 100u; @@ -263,6 +265,18 @@ void VSyncPredictor::resetModel() { clearTimestamps(); } +void VSyncPredictor::dump(std::string& result) const { + std::lock_guard<std::mutex> lk(mMutex); + StringAppendF(&result, "\tmIdealPeriod=%.2f\n", mIdealPeriod / 1e6f); + StringAppendF(&result, "\tRefresh Rate Map:\n"); + for (const auto& [idealPeriod, periodInterceptTuple] : mRateMap) { + StringAppendF(&result, + "\t\tFor ideal period %.2fms: period = %.2fms, intercept = %" PRId64 "\n", + idealPeriod / 1e6f, std::get<0>(periodInterceptTuple) / 1e6f, + std::get<1>(periodInterceptTuple)); + } +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index ef1d88ac27..3ca878d77d 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -60,6 +60,8 @@ public: std::tuple<nsecs_t /* slope */, nsecs_t /* intercept */> getVSyncPredictionModel() const; + void dump(std::string& result) const final; + private: VSyncPredictor(VSyncPredictor const&) = delete; VSyncPredictor& operator=(VSyncPredictor const&) = delete; diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 8987dcdc58..892ae62027 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -28,6 +28,7 @@ #include "VSyncTracker.h" namespace android::scheduler { +using base::StringAppendF; Clock::~Clock() = default; nsecs_t SystemClock::now() const { @@ -73,11 +74,12 @@ class CallbackRepeater { public: CallbackRepeater(VSyncDispatch& dispatch, DispSync::Callback* cb, const char* name, nsecs_t period, nsecs_t offset, nsecs_t notBefore) - : mCallback(cb), + : mName(name), + mCallback(cb), mRegistration(dispatch, std::bind(&CallbackRepeater::callback, this, std::placeholders::_1, std::placeholders::_2), - std::string(name)), + mName), mPeriod(period), mOffset(offset), mLastCallTime(notBefore) {} @@ -112,6 +114,13 @@ public: mRegistration.cancel(); } + void dump(std::string& result) const { + std::lock_guard<std::mutex> lk(mMutex); + StringAppendF(&result, "\t%s: mPeriod=%.2f last vsync time %.2fms relative to now (%s)\n", + mName.c_str(), mPeriod / 1e6f, (mLastCallTime - systemTime()) / 1e6f, + mStopped ? "stopped" : "running"); + } + private: void callback(nsecs_t vsynctime, nsecs_t wakeupTime) { { @@ -137,6 +146,7 @@ private: // Note change in sign between the two defnitions. nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; } + const std::string mName; DispSync::Callback* const mCallback; std::mutex mutable mMutex; @@ -349,7 +359,35 @@ status_t VSyncReactor::changePhaseOffset(DispSync::Callback* callback, nsecs_t p } void VSyncReactor::dump(std::string& result) const { - result += "VsyncReactor in use\n"; // TODO (b/144927823): add more information! + std::lock_guard<std::mutex> lk(mMutex); + StringAppendF(&result, "VsyncReactor in use\n"); + StringAppendF(&result, "Has %zu unfired fences\n", mUnfiredFences.size()); + StringAppendF(&result, "mInternalIgnoreFences=%d mExternalIgnoreFences=%d\n", + mInternalIgnoreFences, mExternalIgnoreFences); + StringAppendF(&result, "mMoreSamplesNeeded=%d mPeriodConfirmationInProgress=%d\n", + mMoreSamplesNeeded, mPeriodConfirmationInProgress); + if (mPeriodTransitioningTo) { + StringAppendF(&result, "mPeriodTransitioningTo=%" PRId64 "\n", *mPeriodTransitioningTo); + } else { + StringAppendF(&result, "mPeriodTransitioningTo=nullptr\n"); + } + + if (mLastHwVsync) { + StringAppendF(&result, "Last HW vsync was %.2fms ago\n", + (mClock->now() - *mLastHwVsync) / 1e6f); + } else { + StringAppendF(&result, "No Last HW vsync\n"); + } + + StringAppendF(&result, "CallbackRepeaters:\n"); + for (const auto& [callback, repeater] : mCallbacks) { + repeater->dump(result); + } + + StringAppendF(&result, "VSyncTracker:\n"); + mTracker->dump(result); + StringAppendF(&result, "VSyncDispatch:\n"); + mDispatch->dump(result); } void VSyncReactor::reset() {} diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 7d8a8e3bb0..5ee29f86d4 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -75,7 +75,7 @@ private: std::unique_ptr<VSyncDispatch> const mDispatch; size_t const mPendingLimit; - std::mutex mMutex; + mutable std::mutex mMutex; bool mInternalIgnoreFences GUARDED_BY(mMutex) = false; bool mExternalIgnoreFences GUARDED_BY(mMutex) = false; std::vector<std::shared_ptr<FenceTime>> mUnfiredFences GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h index a25b8a98de..05a6fc3a8d 100644 --- a/services/surfaceflinger/Scheduler/VSyncTracker.h +++ b/services/surfaceflinger/Scheduler/VSyncTracker.h @@ -66,6 +66,8 @@ public: /* Inform the tracker that the samples it has are not accurate for prediction. */ virtual void resetModel() = 0; + virtual void dump(std::string& result) const = 0; + protected: VSyncTracker(VSyncTracker const&) = delete; VSyncTracker& operator=(VSyncTracker const&) = delete; diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index 20c8d7a3aa..a9c33327c8 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -129,7 +129,12 @@ void SurfaceTracing::enable() { } status_t SurfaceTracing::writeToFile() { - mThread.join(); + std::thread thread; + { + std::scoped_lock lock(mTraceLock); + thread = std::move(mThread); + } + thread.join(); return mLastErr; } diff --git a/services/surfaceflinger/tests/AndroidTest.xml b/services/surfaceflinger/tests/AndroidTest.xml index 8315037b94..000628f598 100644 --- a/services/surfaceflinger/tests/AndroidTest.xml +++ b/services/surfaceflinger/tests/AndroidTest.xml @@ -18,6 +18,7 @@ <option name="cleanup" value="true" /> <option name="push" value="SurfaceFlinger_test->/data/local/tmp/SurfaceFlinger_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" /> diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 65b3e35d32..ba5c0c2988 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -48,6 +48,7 @@ public: MOCK_METHOD1(setCallback, void(VSyncSource::Callback*)); MOCK_METHOD1(setPhaseOffset, void(nsecs_t)); MOCK_METHOD1(pauseVsyncCallback, void(bool)); + MOCK_CONST_METHOD1(dump, void(std::string&)); }; } // namespace diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp index 910e73baf2..8d49201c61 100644 --- a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp +++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp @@ -42,25 +42,25 @@ public: appEarlyGlDuration) {} }; -class PhaseOffsetsTest : public testing::Test { +class PhaseDurationTest : public testing::Test { protected: - PhaseOffsetsTest() - : mPhaseOffsets(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000, - 38'000'000) {} + PhaseDurationTest() + : mPhaseDurations(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000, + 38'000'000) {} - ~PhaseOffsetsTest() = default; + ~PhaseDurationTest() = default; - TestablePhaseOffsetsAsDurations mPhaseOffsets; + TestablePhaseOffsetsAsDurations mPhaseDurations; }; namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) { - mPhaseOffsets.setRefreshRateFps(60.0f); - auto currentOffsets = mPhaseOffsets.getCurrentOffsets(); - auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(60.0f); +TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_60Hz) { + mPhaseDurations.setRefreshRateFps(60.0f); + auto currentOffsets = mPhaseDurations.getCurrentOffsets(); + auto offsets = mPhaseDurations.getOffsetsForRefreshRate(60.0f); EXPECT_EQ(currentOffsets, offsets); EXPECT_EQ(offsets.late.sf, 6'166'667); @@ -76,10 +76,10 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) { EXPECT_EQ(offsets.earlyGl.app, 15'166'668); } -TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) { - mPhaseOffsets.setRefreshRateFps(90.0f); - auto currentOffsets = mPhaseOffsets.getCurrentOffsets(); - auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(90.0f); +TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_90Hz) { + mPhaseDurations.setRefreshRateFps(90.0f); + auto currentOffsets = mPhaseDurations.getCurrentOffsets(); + auto offsets = mPhaseDurations.getOffsetsForRefreshRate(90.0f); EXPECT_EQ(currentOffsets, offsets); EXPECT_EQ(offsets.late.sf, 611'111); @@ -95,7 +95,7 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) { EXPECT_EQ(offsets.earlyGl.app, 4'055'555); } -TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) { +TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_DefaultOffsets) { TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1); auto validateOffsets = [](auto& offsets) { @@ -125,6 +125,54 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) { validateOffsets(offsets); } +TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_unknownRefreshRate) { + auto offsets = mPhaseDurations.getOffsetsForRefreshRate(14.7f); + + EXPECT_EQ(offsets.late.sf, 57'527'208); + + EXPECT_EQ(offsets.late.app, 37'027'208); + + EXPECT_EQ(offsets.early.sf, 52'027'208); + + EXPECT_EQ(offsets.early.app, 18'527'208); + + EXPECT_EQ(offsets.earlyGl.sf, 54'527'208); + + EXPECT_EQ(offsets.earlyGl.app, 16'527'208); +} + +} // namespace + +class TestablePhaseOffsets : public impl::PhaseOffsets { +public: + TestablePhaseOffsets() : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 10'000'000) {} +}; + +class PhaseOffsetsTest : public testing::Test { +protected: + PhaseOffsetsTest() = default; + ~PhaseOffsetsTest() = default; + + TestablePhaseOffsets mPhaseOffsets; +}; + +namespace { +TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) { + auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(14.7f); + + EXPECT_EQ(offsets.late.sf, 1'000'000); + + EXPECT_EQ(offsets.late.app, 1'000'000); + + EXPECT_EQ(offsets.early.sf, 1'000'000); + + EXPECT_EQ(offsets.early.app, 1'000'000); + + EXPECT_EQ(offsets.earlyGl.sf, 1'000'000); + + EXPECT_EQ(offsets.earlyGl.app, 1'000'000); +} + } // namespace } // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index caac61da29..be49ef33f2 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -51,6 +51,7 @@ public: void setPeriod(nsecs_t) final {} void resetModel() final {} + void dump(std::string&) const final {} private: nsecs_t const mPeriod; @@ -85,6 +86,7 @@ public: void setPeriod(nsecs_t) final {} void resetModel() final {} + void dump(std::string&) const final {} private: std::mutex mutable mMutex; diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 3ab38e40ef..3543361f7b 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -47,6 +47,7 @@ public: MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(resetModel, void()); + MOCK_CONST_METHOD1(dump, void(std::string&)); nsecs_t nextVSyncTime(nsecs_t timePoint) const { if (timePoint % mPeriod == 0) { diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index ac959388c2..4f150ef1e0 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -41,6 +41,7 @@ public: MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(resetModel, void()); + MOCK_CONST_METHOD1(dump, void(std::string&)); }; class VSyncTrackerWrapper : public VSyncTracker { @@ -56,6 +57,7 @@ public: nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); } void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); } void resetModel() final { mTracker->resetModel(); } + void dump(std::string& result) const final { mTracker->dump(result); } private: std::shared_ptr<VSyncTracker> const mTracker; @@ -83,6 +85,7 @@ public: MOCK_METHOD1(unregisterCallback, void(CallbackToken)); MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t)); MOCK_METHOD1(cancel, CancelResult(CallbackToken token)); + MOCK_CONST_METHOD1(dump, void(std::string&)); }; class VSyncDispatchWrapper : public VSyncDispatch { @@ -102,6 +105,8 @@ public: CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); } + void dump(std::string& result) const final { return mDispatch->dump(result); } + private: std::shared_ptr<VSyncDispatch> const mDispatch; }; diff --git a/vulkan/TEST_MAPPING b/vulkan/TEST_MAPPING new file mode 100644 index 0000000000..d391dce2de --- /dev/null +++ b/vulkan/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsGpuToolsHostTestCases" + } + ] +} diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp index e607b058eb..5b9affd03a 100644 --- a/vulkan/libvulkan/api.cpp +++ b/vulkan/libvulkan/api.cpp @@ -1196,6 +1196,23 @@ bool EnsureInitialized() { return initialized; } +template <typename Functor> +void ForEachLayerFromSettings(Functor functor) { + const std::string layersSetting = + android::GraphicsEnv::getInstance().getDebugLayers(); + if (!layersSetting.empty()) { + std::vector<std::string> layers = + android::base::Split(layersSetting, ":"); + for (uint32_t i = 0; i < layers.size(); i++) { + const Layer* layer = FindLayer(layers[i].c_str()); + if (!layer) { + continue; + } + functor(layer); + } + } +} + } // anonymous namespace VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, @@ -1291,28 +1308,18 @@ VkResult EnumerateInstanceExtensionProperties( std::unordered_set<std::string> extensionNames; // Expose extensions from implicitly enabled layers. - const std::string layersSetting = - android::GraphicsEnv::getInstance().getDebugLayers(); - if (!layersSetting.empty()) { - std::vector<std::string> layers = - android::base::Split(layersSetting, ":"); - for (uint32_t i = 0; i < layers.size(); i++) { - const Layer* layer = FindLayer(layers[i].c_str()); - if (!layer) { - continue; - } - uint32_t count = 0; - const VkExtensionProperties* props = - GetLayerInstanceExtensions(*layer, count); - if (count > 0) { - for (uint32_t i = 0; i < count; ++i) { - if (extensionNames.emplace(props[i].extensionName).second) { - properties.push_back(props[i]); - } + ForEachLayerFromSettings([&](const Layer* layer) { + uint32_t count = 0; + const VkExtensionProperties* props = + GetLayerInstanceExtensions(*layer, count); + if (count > 0) { + for (uint32_t i = 0; i < count; ++i) { + if (extensionNames.emplace(props[i].extensionName).second) { + properties.push_back(props[i]); } } } - } + }); // TODO(b/143293104): Parse debug.vulkan.layers properties @@ -1393,10 +1400,57 @@ VkResult EnumerateDeviceExtensionProperties( return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; } - // TODO(b/143293104): expose extensions from implicitly enabled layers - const InstanceData& data = GetData(physicalDevice); - return data.dispatch.EnumerateDeviceExtensionProperties( - physicalDevice, nullptr, pPropertyCount, pProperties); + // If the pLayerName is nullptr, we must advertise all device extensions + // from all implicitly enabled layers and the driver implementation. If + // there are duplicates among layers and the driver implementation, always + // only preserve the top layer closest to the application regardless of the + // spec version. + std::vector<VkExtensionProperties> properties; + std::unordered_set<std::string> extensionNames; + + // Expose extensions from implicitly enabled layers. + ForEachLayerFromSettings([&](const Layer* layer) { + uint32_t count = 0; + const VkExtensionProperties* props = + GetLayerDeviceExtensions(*layer, count); + if (count > 0) { + for (uint32_t i = 0; i < count; ++i) { + if (extensionNames.emplace(props[i].extensionName).second) { + properties.push_back(props[i]); + } + } + } + }); + + // TODO(b/143293104): Parse debug.vulkan.layers properties + + // Expose extensions from driver implementation. + { + const InstanceData& data = GetData(physicalDevice); + uint32_t count = 0; + VkResult result = data.dispatch.EnumerateDeviceExtensionProperties( + physicalDevice, nullptr, &count, nullptr); + if (result == VK_SUCCESS && count > 0) { + std::vector<VkExtensionProperties> props(count); + result = data.dispatch.EnumerateDeviceExtensionProperties( + physicalDevice, nullptr, &count, props.data()); + for (auto prop : props) { + if (extensionNames.emplace(prop.extensionName).second) { + properties.push_back(prop); + } + } + } + } + + uint32_t totalCount = properties.size(); + if (!pProperties || *pPropertyCount > totalCount) { + *pPropertyCount = totalCount; + } + if (pProperties) { + std::copy(properties.data(), properties.data() + *pPropertyCount, + pProperties); + } + return *pPropertyCount < totalCount ? VK_INCOMPLETE : VK_SUCCESS; } VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) { |