Merge "Implement Envelope Effect Limitations APIs" into main
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index 65c2914..358a191 100644
--- a/include/input/InputConsumerNoResampling.h
+++ b/include/input/InputConsumerNoResampling.h
@@ -17,6 +17,7 @@
#pragma once
#include <input/InputTransport.h>
+#include <input/LooperInterface.h>
#include <input/Resampler.h>
#include <utils/Looper.h>
@@ -66,6 +67,16 @@
class InputConsumerNoResampling final {
public:
/**
+ * This constructor is exclusively for test code. Any real use of InputConsumerNoResampling must
+ * use the constructor that takes an sp<Looper> parameter instead of
+ * std::shared_ptr<LooperInterface>.
+ */
+ explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
+ std::shared_ptr<LooperInterface> looper,
+ InputConsumerCallbacks& callbacks,
+ std::unique_ptr<Resampler> resampler);
+
+ /**
* @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever
* the event is ready to consume.
* @param looper needs to be sp and not shared_ptr because it inherits from
@@ -108,7 +119,7 @@
private:
std::shared_ptr<InputChannel> mChannel;
- sp<Looper> mLooper;
+ std::shared_ptr<LooperInterface> mLooper;
InputConsumerCallbacks& mCallbacks;
std::unique_ptr<Resampler> mResampler;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 7d11f76..0cd8720 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -263,7 +263,7 @@
* Return DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t sendMessage(const InputMessage* msg);
+ virtual status_t sendMessage(const InputMessage* msg);
/* Receive a message sent by the other endpoint.
*
@@ -275,14 +275,14 @@
* Return DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- android::base::Result<InputMessage> receiveMessage();
+ virtual android::base::Result<InputMessage> receiveMessage();
/* Tells whether there is a message in the channel available to be received.
*
* This is only a performance hint and may return false negative results. Clients should not
* rely on availability of the message based on the return value.
*/
- bool probablyHasInput() const;
+ virtual bool probablyHasInput() const;
/* Wait until there is a message in the channel.
*
@@ -323,11 +323,12 @@
*/
sp<IBinder> getConnectionToken() const;
+protected:
+ InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
+
private:
static std::unique_ptr<InputChannel> create(const std::string& name,
android::base::unique_fd fd, sp<IBinder> token);
-
- InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
};
/*
diff --git a/include/input/LooperInterface.h b/include/input/LooperInterface.h
new file mode 100644
index 0000000..2d6719c
--- /dev/null
+++ b/include/input/LooperInterface.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2024 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 <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+/**
+ * LooperInterface allows the use of TestLooper in InputConsumerNoResampling without reassigning to
+ * Looper. LooperInterface is needed to control how InputConsumerNoResampling consumes and batches
+ * InputMessages.
+ */
+class LooperInterface {
+public:
+ virtual ~LooperInterface() = default;
+
+ virtual int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+ void* data) = 0;
+ virtual int removeFd(int fd) = 0;
+
+ virtual sp<Looper> getLooper() const = 0;
+};
+} // namespace android
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 54f687b..5680798 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -24,11 +24,111 @@
namespace android {
+#ifdef LIBBINDER_CLIENT_CACHE
+constexpr bool kUseCache = true;
+#else
+constexpr bool kUseCache = false;
+#endif
+
using AidlServiceManager = android::os::IServiceManager;
using IAccessor = android::os::IAccessor;
+static const char* kStaticCachableList[] = {
+ "activity",
+ "android.hardware.thermal.IThermal/default",
+ "android.hardware.power.IPower/default",
+ "android.frameworks.stats.IStats/default",
+ "android.system.suspend.ISystemSuspend/default",
+ "appops",
+ "audio",
+ "batterystats",
+ "carrier_config",
+ "connectivity",
+ "content_capture",
+ "device_policy",
+ "display",
+ "dropbox",
+ "econtroller",
+ "isub",
+ "legacy_permission",
+ "location",
+ "media.extractor",
+ "media.metrics",
+ "media.player",
+ "media.resource_manager",
+ "netd_listener",
+ "netstats",
+ "network_management",
+ "nfc",
+ "package_native",
+ "performance_hint",
+ "permission",
+ "permissionmgr",
+ "permission_checker",
+ "phone",
+ "platform_compat",
+ "power",
+ "role",
+ "sensorservice",
+ "statscompanion",
+ "telephony.registry",
+ "thermalservice",
+ "time_detector",
+ "trust",
+ "uimode",
+ "virtualdevice",
+ "virtualdevice_native",
+ "webviewupdate",
+};
+
+bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
+ if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) {
+ ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be "
+ "implemented. serviceName: %s",
+ serviceName.c_str());
+ return false;
+ }
+ for (const char* name : kStaticCachableList) {
+ if (name == serviceName) {
+ return true;
+ }
+ }
+ return false;
+}
+
+binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName,
+ const os::Service& service) {
+ if (!kUseCache) {
+ return binder::Status::ok();
+ }
+ if (service.getTag() == os::Service::Tag::binder) {
+ sp<IBinder> binder = service.get<os::Service::Tag::binder>();
+ if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) &&
+ binder->isBinderAlive()) {
+ return mCacheForGetService->setItem(serviceName, binder);
+ }
+ }
+ return binder::Status::ok();
+}
+
+bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName,
+ os::Service* _out) {
+ if (!kUseCache) {
+ return false;
+ }
+ sp<IBinder> item = mCacheForGetService->getItem(serviceName);
+ // TODO(b/363177618): Enable caching for binders which are always null.
+ if (item != nullptr && item->isBinderAlive()) {
+ *_out = os::Service::make<os::Service::Tag::binder>(item);
+ return true;
+ }
+ return false;
+}
+
BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceManager>& impl)
- : mTheRealServiceManager(impl) {}
+ : mTheRealServiceManager(impl) {
+ mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>();
+}
sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() {
return mTheRealServiceManager;
@@ -44,25 +144,64 @@
binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name,
os::Service* _out) {
+ if (returnIfCached(name, _out)) {
+ return binder::Status::ok();
+ }
os::Service service;
binder::Status status = mTheRealServiceManager->getService2(name, &service);
- toBinderService(service, _out);
+
+ if (status.isOk()) {
+ status = toBinderService(name, service, _out);
+ if (status.isOk()) {
+ return updateCache(name, service);
+ }
+ }
return status;
}
binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name,
os::Service* _out) {
os::Service service;
+ if (returnIfCached(name, _out)) {
+ return binder::Status::ok();
+ }
+
binder::Status status = mTheRealServiceManager->checkService(name, &service);
- toBinderService(service, _out);
+ if (status.isOk()) {
+ status = toBinderService(name, service, _out);
+ if (status.isOk()) {
+ return updateCache(name, service);
+ }
+ }
return status;
}
-void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Service* _out) {
+binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name,
+ const os::Service& in,
+ os::Service* _out) {
switch (in.getTag()) {
case os::Service::Tag::binder: {
+ if (in.get<os::Service::Tag::binder>() == nullptr) {
+ // failed to find a service. Check to see if we have any local
+ // injected Accessors for this service.
+ os::Service accessor;
+ binder::Status status = getInjectedAccessor(name, &accessor);
+ if (!status.isOk()) {
+ *_out = os::Service::make<os::Service::Tag::binder>(nullptr);
+ return status;
+ }
+ if (accessor.getTag() == os::Service::Tag::accessor &&
+ accessor.get<os::Service::Tag::accessor>() != nullptr) {
+ ALOGI("Found local injected service for %s, will attempt to create connection",
+ name.c_str());
+ // Call this again using the accessor Service to get the real
+ // service's binder into _out
+ return toBinderService(name, accessor, _out);
+ }
+ }
+
*_out = in;
- break;
+ return binder::Status::ok();
}
case os::Service::Tag::accessor: {
sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>();
@@ -70,7 +209,7 @@
if (accessor == nullptr) {
ALOGE("Service#accessor doesn't have accessor. VM is maybe starting...");
*_out = os::Service::make<os::Service::Tag::binder>(nullptr);
- break;
+ return binder::Status::ok();
}
auto request = [=] {
os::ParcelFileDescriptor fd;
@@ -83,10 +222,15 @@
}
};
auto session = RpcSession::make();
- session->setupPreconnectedClient(base::unique_fd{}, request);
+ status_t status = session->setupPreconnectedClient(base::unique_fd{}, request);
+ if (status != OK) {
+ ALOGE("Failed to set up preconnected binder RPC client: %s",
+ statusToString(status).c_str());
+ return binder::Status::fromStatusT(status);
+ }
session->setSessionSpecificRoot(accessorBinder);
*_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject());
- break;
+ return binder::Status::ok();
}
default: {
LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag());
@@ -177,4 +321,4 @@
return gUnifiedServiceManager;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index 8f3839f..47b2ec9 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -18,9 +18,87 @@
#include <android/os/BnServiceManager.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
+#include <map>
+#include <memory>
namespace android {
+class BinderCacheWithInvalidation
+ : public std::enable_shared_from_this<BinderCacheWithInvalidation> {
+ class BinderInvalidation : public IBinder::DeathRecipient {
+ public:
+ BinderInvalidation(std::weak_ptr<BinderCacheWithInvalidation> cache, const std::string& key)
+ : mCache(cache), mKey(key) {}
+
+ void binderDied(const wp<IBinder>& who) override {
+ sp<IBinder> binder = who.promote();
+ if (std::shared_ptr<BinderCacheWithInvalidation> cache = mCache.lock()) {
+ cache->removeItem(mKey, binder);
+ } else {
+ ALOGI("Binder Cache pointer expired: %s", mKey.c_str());
+ }
+ }
+
+ private:
+ std::weak_ptr<BinderCacheWithInvalidation> mCache;
+ std::string mKey;
+ };
+ struct Entry {
+ sp<IBinder> service;
+ sp<BinderInvalidation> deathRecipient;
+ };
+
+public:
+ sp<IBinder> getItem(const std::string& key) const {
+ std::lock_guard<std::mutex> lock(mCacheMutex);
+
+ if (auto it = mCache.find(key); it != mCache.end()) {
+ return it->second.service;
+ }
+ return nullptr;
+ }
+
+ bool removeItem(const std::string& key, const sp<IBinder>& who) {
+ std::lock_guard<std::mutex> lock(mCacheMutex);
+ if (auto it = mCache.find(key); it != mCache.end()) {
+ if (it->second.service == who) {
+ status_t result = who->unlinkToDeath(it->second.deathRecipient);
+ if (result != DEAD_OBJECT) {
+ ALOGW("Unlinking to dead binder resulted in: %d", result);
+ }
+ mCache.erase(key);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ binder::Status setItem(const std::string& key, const sp<IBinder>& item) {
+ sp<BinderInvalidation> deathRecipient =
+ sp<BinderInvalidation>::make(shared_from_this(), key);
+
+ // linkToDeath if binder is a remote binder.
+ if (item->localBinder() == nullptr) {
+ status_t status = item->linkToDeath(deathRecipient);
+ if (status != android::OK) {
+ ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(),
+ status);
+ return binder::Status::fromStatusT(status);
+ }
+ }
+ std::lock_guard<std::mutex> lock(mCacheMutex);
+ Entry entry = {.service = item, .deathRecipient = deathRecipient};
+ mCache[key] = entry;
+ return binder::Status::ok();
+ }
+
+ bool isClientSideCachingEnabled(const std::string& serviceName);
+
+private:
+ std::map<std::string, Entry> mCache;
+ mutable std::mutex mCacheMutex;
+};
+
class BackendUnifiedServiceManager : public android::os::BnServiceManager {
public:
explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl);
@@ -58,10 +136,16 @@
}
private:
+ std::shared_ptr<BinderCacheWithInvalidation> mCacheForGetService;
sp<os::IServiceManager> mTheRealServiceManager;
- void toBinderService(const os::Service& in, os::Service* _out);
+ binder::Status toBinderService(const ::std::string& name, const os::Service& in,
+ os::Service* _out);
+ binder::Status updateCache(const std::string& serviceName, const os::Service& service);
+ bool returnIfCached(const std::string& serviceName, os::Service* _out);
};
sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager();
-} // namespace android
\ No newline at end of file
+android::binder::Status getInjectedAccessor(const std::string& name, android::os::Service* service);
+
+} // namespace android
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index 455a433..f0aa801 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -82,7 +82,9 @@
int ret = TEMP_FAILURE_RETRY(poll(pfd, countof(pfd), -1));
if (ret < 0) {
- return -errno;
+ int saved_errno = errno;
+ ALOGE("FdTrigger poll returned error: %d, with error: %s", ret, strerror(saved_errno));
+ return -saved_errno;
}
LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get());
@@ -106,6 +108,7 @@
// POLLNVAL: invalid FD number, e.g. not opened.
if (pfd[0].revents & POLLNVAL) {
+ ALOGE("Invalid FD number (%d) in FdTrigger (POLLNVAL)", pfd[0].fd);
return BAD_VALUE;
}
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c55dd9d..88761d7 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+#include <sys/socket.h>
#define LOG_TAG "ServiceManagerCppClient"
#include <binder/IServiceManager.h>
+#include <binder/IServiceManagerUnitTestHelper.h>
#include "BackendUnifiedServiceManager.h"
#include <inttypes.h>
@@ -24,14 +26,19 @@
#include <chrono>
#include <condition_variable>
+#include <FdTrigger.h>
+#include <RpcSocketAddress.h>
#include <android-base/properties.h>
+#include <android/os/BnAccessor.h>
#include <android/os/BnServiceCallback.h>
+#include <android/os/BnServiceManager.h>
#include <android/os/IAccessor.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <binder/RpcSession.h>
#include <utils/String8.h>
-
+#include <variant>
#ifndef __ANDROID_VNDK__
#include <binder/IPermissionController.h>
#endif
@@ -148,8 +155,142 @@
}
};
+class AccessorProvider {
+public:
+ AccessorProvider(RpcAccessorProvider&& provider) : mProvider(std::move(provider)) {}
+ sp<IBinder> provide(const String16& name) { return mProvider(name); }
+
+private:
+ AccessorProvider() = delete;
+
+ RpcAccessorProvider mProvider;
+};
+
+class AccessorProviderEntry {
+public:
+ AccessorProviderEntry(std::shared_ptr<AccessorProvider>&& provider)
+ : mProvider(std::move(provider)) {}
+ std::shared_ptr<AccessorProvider> mProvider;
+
+private:
+ AccessorProviderEntry() = delete;
+};
+
[[clang::no_destroy]] static std::once_flag gSmOnce;
[[clang::no_destroy]] static sp<IServiceManager> gDefaultServiceManager;
+[[clang::no_destroy]] static std::mutex gAccessorProvidersMutex;
+[[clang::no_destroy]] static std::vector<AccessorProviderEntry> gAccessorProviders;
+
+class LocalAccessor : public android::os::BnAccessor {
+public:
+ LocalAccessor(const String16& instance, RpcSocketAddressProvider&& connectionInfoProvider)
+ : mInstance(instance), mConnectionInfoProvider(std::move(connectionInfoProvider)) {
+ LOG_ALWAYS_FATAL_IF(!mConnectionInfoProvider,
+ "LocalAccessor object needs a valid connection info provider");
+ }
+
+ ~LocalAccessor() {
+ if (mOnDelete) mOnDelete();
+ }
+
+ ::android::binder::Status addConnection(::android::os::ParcelFileDescriptor* outFd) {
+ using android::os::IAccessor;
+ sockaddr_storage addrStorage;
+ std::unique_ptr<FdTrigger> trigger = FdTrigger::make();
+ RpcTransportFd fd;
+ status_t status =
+ mConnectionInfoProvider(mInstance, reinterpret_cast<sockaddr*>(&addrStorage),
+ sizeof(addrStorage));
+ if (status != OK) {
+ const std::string error = "The connection info provider was unable to provide "
+ "connection info for instance " +
+ std::string(String8(mInstance).c_str()) +
+ " with status: " + statusToString(status);
+ ALOGE("%s", error.c_str());
+ return Status::fromServiceSpecificError(IAccessor::ERROR_CONNECTION_INFO_NOT_FOUND,
+ error.c_str());
+ }
+ if (addrStorage.ss_family == AF_VSOCK) {
+ sockaddr_vm* addr = reinterpret_cast<sockaddr_vm*>(&addrStorage);
+ status = singleSocketConnection(VsockSocketAddress(addr->svm_cid, addr->svm_port),
+ trigger, &fd);
+ } else if (addrStorage.ss_family == AF_UNIX) {
+ sockaddr_un* addr = reinterpret_cast<sockaddr_un*>(&addrStorage);
+ status = singleSocketConnection(UnixSocketAddress(addr->sun_path), trigger, &fd);
+ } else if (addrStorage.ss_family == AF_INET) {
+ sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&addrStorage);
+ status = singleSocketConnection(InetSocketAddress(reinterpret_cast<sockaddr*>(addr),
+ sizeof(sockaddr_in),
+ inet_ntoa(addr->sin_addr),
+ ntohs(addr->sin_port)),
+ trigger, &fd);
+ } else {
+ const std::string error =
+ "Unsupported socket family type or the ConnectionInfoProvider failed to find a "
+ "valid address. Family type: " +
+ std::to_string(addrStorage.ss_family);
+ ALOGE("%s", error.c_str());
+ return Status::fromServiceSpecificError(IAccessor::ERROR_UNSUPPORTED_SOCKET_FAMILY,
+ error.c_str());
+ }
+ if (status != OK) {
+ const std::string error = "Failed to connect to socket for " +
+ std::string(String8(mInstance).c_str()) +
+ " with status: " + statusToString(status);
+ ALOGE("%s", error.c_str());
+ int err = 0;
+ if (status == -EACCES) {
+ err = IAccessor::ERROR_FAILED_TO_CONNECT_EACCES;
+ } else {
+ err = IAccessor::ERROR_FAILED_TO_CONNECT_TO_SOCKET;
+ }
+ return Status::fromServiceSpecificError(err, error.c_str());
+ }
+ *outFd = os::ParcelFileDescriptor(std::move(fd.fd));
+ return Status::ok();
+ }
+
+ ::android::binder::Status getInstanceName(String16* instance) {
+ *instance = mInstance;
+ return Status::ok();
+ }
+
+private:
+ LocalAccessor() = delete;
+ String16 mInstance;
+ RpcSocketAddressProvider mConnectionInfoProvider;
+ std::function<void()> mOnDelete;
+};
+
+android::binder::Status getInjectedAccessor(const std::string& name,
+ android::os::Service* service) {
+ std::vector<AccessorProviderEntry> copiedProviders;
+ {
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ copiedProviders.insert(copiedProviders.begin(), gAccessorProviders.begin(),
+ gAccessorProviders.end());
+ }
+
+ // Unlocked to call the providers. This requires the providers to be
+ // threadsafe and not contain any references to objects that could be
+ // deleted.
+ for (const auto& provider : copiedProviders) {
+ sp<IBinder> binder = provider.mProvider->provide(String16(name.c_str()));
+ if (binder == nullptr) continue;
+ status_t status = validateAccessor(String16(name.c_str()), binder);
+ if (status != OK) {
+ ALOGE("A provider returned a binder that is not an IAccessor for instance %s. Status: "
+ "%s",
+ name.c_str(), statusToString(status).c_str());
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ *service = os::Service::make<os::Service::Tag::accessor>(binder);
+ return android::binder::Status::ok();
+ }
+
+ *service = os::Service::make<os::Service::Tag::accessor>(nullptr);
+ return android::binder::Status::ok();
+}
sp<IServiceManager> defaultServiceManager()
{
@@ -172,6 +313,81 @@
}
}
+sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
+ const sp<AidlServiceManager>& sm) {
+ return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm));
+}
+
+std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) {
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ std::shared_ptr<AccessorProvider> provider =
+ std::make_shared<AccessorProvider>(std::move(providerCallback));
+ std::weak_ptr<AccessorProvider> receipt = provider;
+ gAccessorProviders.push_back(AccessorProviderEntry(std::move(provider)));
+
+ return receipt;
+}
+
+status_t removeAccessorProvider(std::weak_ptr<AccessorProvider> wProvider) {
+ std::shared_ptr<AccessorProvider> provider = wProvider.lock();
+ if (provider == nullptr) {
+ ALOGE("The provider supplied to removeAccessorProvider has already been removed.");
+ return NAME_NOT_FOUND;
+ }
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ size_t sizeBefore = gAccessorProviders.size();
+ gAccessorProviders.erase(std::remove_if(gAccessorProviders.begin(), gAccessorProviders.end(),
+ [&](AccessorProviderEntry entry) {
+ return entry.mProvider == provider;
+ }),
+ gAccessorProviders.end());
+ if (sizeBefore == gAccessorProviders.size()) {
+ ALOGE("Failed to find an AccessorProvider for removeAccessorProvider");
+ return NAME_NOT_FOUND;
+ }
+
+ return OK;
+}
+
+status_t validateAccessor(const String16& instance, const sp<IBinder>& binder) {
+ if (binder == nullptr) {
+ ALOGE("Binder is null");
+ return BAD_VALUE;
+ }
+ sp<IAccessor> accessor = interface_cast<IAccessor>(binder);
+ if (accessor == nullptr) {
+ ALOGE("This binder for %s is not an IAccessor binder", String8(instance).c_str());
+ return BAD_TYPE;
+ }
+ String16 reportedInstance;
+ Status status = accessor->getInstanceName(&reportedInstance);
+ if (!status.isOk()) {
+ ALOGE("Failed to validate the binder being used to create a new ARpc_Accessor for %s with "
+ "status: %s",
+ String8(instance).c_str(), status.toString8().c_str());
+ return NAME_NOT_FOUND;
+ }
+ if (reportedInstance != instance) {
+ ALOGE("Instance %s doesn't match the Accessor's instance of %s", String8(instance).c_str(),
+ String8(reportedInstance).c_str());
+ return NAME_NOT_FOUND;
+ }
+ return OK;
+}
+
+sp<IBinder> createAccessor(const String16& instance,
+ RpcSocketAddressProvider&& connectionInfoProvider) {
+ // Try to create a new accessor
+ if (!connectionInfoProvider) {
+ ALOGE("Could not find an Accessor for %s and no ConnectionInfoProvider provided to "
+ "create a new one",
+ String8(instance).c_str());
+ return nullptr;
+ }
+ sp<IBinder> binder = sp<LocalAccessor>::make(instance, std::move(connectionInfoProvider));
+ return binder;
+}
+
#if !defined(__ANDROID_VNDK__)
// IPermissionController is not accessible to vendors
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 49def82..cd21a91 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -589,6 +589,21 @@
status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
const std::vector<uint8_t>& sessionId,
bool incoming) {
+ RpcTransportFd transportFd;
+ status_t status = singleSocketConnection(addr, mShutdownTrigger, &transportFd);
+ if (status != OK) return status;
+
+ return initAndAddConnection(std::move(transportFd), sessionId, incoming);
+}
+
+status_t singleSocketConnection(const RpcSocketAddress& addr,
+ const std::unique_ptr<FdTrigger>& shutdownTrigger,
+ RpcTransportFd* outFd) {
+ LOG_ALWAYS_FATAL_IF(outFd == nullptr,
+ "There is no reason to call this function without an outFd");
+ LOG_ALWAYS_FATAL_IF(shutdownTrigger == nullptr,
+ "FdTrigger argument is required so we don't get stuck in the connect call "
+ "if the server process shuts down.");
for (size_t tries = 0; tries < 5; tries++) {
if (tries > 0) usleep(10000);
@@ -620,7 +635,7 @@
if (connErrno == EAGAIN || connErrno == EINPROGRESS) {
// For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
// EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
- status_t pollStatus = mShutdownTrigger->triggerablePoll(transportFd, POLLOUT);
+ status_t pollStatus = shutdownTrigger->triggerablePoll(transportFd, POLLOUT);
if (pollStatus != OK) {
ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
statusToString(pollStatus).c_str());
@@ -654,7 +669,8 @@
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(),
transportFd.fd.get());
- return initAndAddConnection(std::move(transportFd), sessionId, incoming);
+ *outFd = std::move(transportFd);
+ return OK;
}
ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h
index c7ba5d9..ee7d448 100644
--- a/libs/binder/RpcSocketAddress.h
+++ b/libs/binder/RpcSocketAddress.h
@@ -113,4 +113,11 @@
unsigned int mPort;
};
+/**
+ * Connects to a single socket and produces a RpcTransportFd.
+ */
+status_t singleSocketConnection(const RpcSocketAddress& address,
+ const std::unique_ptr<FdTrigger>& shutdownTrigger,
+ RpcTransportFd* outFd);
+
} // namespace android
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 1256173..95a5da2 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -133,6 +133,9 @@
{
"name": "binder_sdk_test",
"host": true
+ },
+ {
+ "name": "binderCacheUnitTest"
}
],
"imports": [
diff --git a/libs/binder/aidl/android/os/IAccessor.aidl b/libs/binder/aidl/android/os/IAccessor.aidl
index a3134a3..c06e05c 100644
--- a/libs/binder/aidl/android/os/IAccessor.aidl
+++ b/libs/binder/aidl/android/os/IAccessor.aidl
@@ -25,15 +25,56 @@
*/
interface IAccessor {
/**
+ * The connection info was not available for this service.
+ * This happens when the user-supplied callback fails to produce
+ * valid connection info.
+ * Depending on the implementation of the callback, it might be helpful
+ * to retry.
+ */
+ const int ERROR_CONNECTION_INFO_NOT_FOUND = 0;
+ /**
+ * Failed to create the socket. Often happens when the process trying to create
+ * the socket lacks the permissions to do so.
+ * This may be a temporary issue, so retrying the operation is OK.
+ */
+ const int ERROR_FAILED_TO_CREATE_SOCKET = 1;
+ /**
+ * Failed to connect to the socket. This can happen for many reasons, so be sure
+ * log the error message and check it.
+ * This may be a temporary issue, so retrying the operation is OK.
+ */
+ const int ERROR_FAILED_TO_CONNECT_TO_SOCKET = 2;
+ /**
+ * Failed to connect to the socket with EACCES because this process does not
+ * have perimssions to connect.
+ * There is no need to retry the connection as this access will not be granted
+ * upon retry.
+ */
+ const int ERROR_FAILED_TO_CONNECT_EACCES = 3;
+ /**
+ * Unsupported socket family type returned.
+ * There is no need to retry the connection as this socket family is not
+ * supported.
+ */
+ const int ERROR_UNSUPPORTED_SOCKET_FAMILY = 4;
+
+ /**
* Adds a connection to the RPC server of the service managed by the IAccessor.
*
* This method can be called multiple times to establish multiple distinct
* connections to the same RPC server.
*
+ * @throws ServiceSpecificError with message and one of the IAccessor::ERROR_ values.
+ *
* @return A file descriptor connected to the RPC session of the service managed
* by IAccessor.
*/
ParcelFileDescriptor addConnection();
- // TODO(b/350941051): Add API for debugging.
+ /**
+ * Get the instance name for the service this accessor is responsible for.
+ *
+ * This is used to verify the proxy binder is associated with the expected instance name.
+ */
+ String getInstanceName();
}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 5fb7307..879f319 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -17,14 +17,16 @@
#pragma once
#include <binder/Common.h>
#include <binder/IInterface.h>
-#include <utils/Vector.h>
+// Trusty has its own definition of socket APIs from trusty_ipc.h
+#ifndef __TRUSTY__
+#include <sys/socket.h>
+#endif // __TRUSTY__
#include <utils/String16.h>
+#include <utils/Vector.h>
#include <optional>
namespace android {
-// ----------------------------------------------------------------------
-
/**
* Service manager for C++ services.
*
@@ -216,6 +218,64 @@
LIBBINDER_EXPORTED bool checkPermission(const String16& permission, pid_t pid, uid_t uid,
bool logPermissionFailure = true);
+// ----------------------------------------------------------------------
+// Trusty's definition of the socket APIs does not include sockaddr types
+#ifndef __TRUSTY__
+typedef std::function<status_t(const String16& name, sockaddr* outAddr, socklen_t addrSize)>
+ RpcSocketAddressProvider;
+
+typedef std::function<sp<IBinder>(const String16& name)> RpcAccessorProvider;
+
+class AccessorProvider;
+
+/**
+ * Register an accessor provider for the service manager APIs.
+ *
+ * \param provider callback that generates Accessors.
+ *
+ * \return A pointer used as a recept for the successful addition of the
+ * AccessorProvider. This is needed to unregister it later.
+ */
+[[nodiscard]] LIBBINDER_EXPORTED std::weak_ptr<AccessorProvider> addAccessorProvider(
+ RpcAccessorProvider&& providerCallback);
+
+/**
+ * Remove an accessor provider using the pointer provided by addAccessorProvider
+ * along with the cookie pointer that was used.
+ *
+ * \param provider cookie that was returned by addAccessorProvider to keep track
+ * of this instance.
+ */
+[[nodiscard]] LIBBINDER_EXPORTED status_t
+removeAccessorProvider(std::weak_ptr<AccessorProvider> provider);
+
+/**
+ * Create an Accessor associated with a service that can create a socket connection based
+ * on the connection info from the supplied RpcSocketAddressProvider.
+ *
+ * \param instance name of the service that this Accessor is associated with
+ * \param connectionInfoProvider a callback that returns connection info for
+ * connecting to the service.
+ * \return the binder of the IAccessor implementation from libbinder
+ */
+LIBBINDER_EXPORTED sp<IBinder> createAccessor(const String16& instance,
+ RpcSocketAddressProvider&& connectionInfoProvider);
+
+/**
+ * Check to make sure this binder is the expected binder that is an IAccessor
+ * associated with a specific instance.
+ *
+ * This helper function exists to avoid adding the IAccessor type to
+ * libbinder_ndk.
+ *
+ * \param instance name of the service that this Accessor should be associated with
+ * \param binder to validate
+ *
+ * \return OK if the binder is an IAccessor for `instance`
+ */
+LIBBINDER_EXPORTED status_t validateAccessor(const String16& instance, const sp<IBinder>& binder);
+#endif // __TRUSTY__
+
#ifndef __ANDROID__
// Create an IServiceManager that delegates the service manager on the device via adb.
// This is can be set as the default service manager at program start, so that
diff --git a/libs/binder/include/binder/IServiceManagerUnitTestHelper.h b/libs/binder/include/binder/IServiceManagerUnitTestHelper.h
new file mode 100644
index 0000000..ff25163
--- /dev/null
+++ b/libs/binder/include/binder/IServiceManagerUnitTestHelper.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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/IServiceManager.h>
+#include "IServiceManager.h"
+namespace android {
+
+/**
+ * Encapsulate an AidlServiceManager in a CppBackendShim. Only used for testing.
+ */
+LIBBINDER_EXPORTED sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
+ const sp<os::IServiceManager>& sm);
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 4e02ace..5f45cb2 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -230,12 +230,24 @@
},
apex_available: [
"//apex_available:platform",
+ "//apex_available:anyapex",
"com.android.media",
"com.android.media.swcodec",
],
min_sdk_version: "29",
}
+// TODO: if you try to export libbinder_headers_platform_shared from libbinder_ndk.ndk, it will
+// not select the NDK variant of libbinder_headers_platform_shared and instead, it will error
+// that the NDK can't depend on glibc C++.
+cc_library_headers {
+ name: "libbinder_headers_platform_shared_ndk",
+ export_include_dirs: ["include_cpp"],
+ sdk_version: "29",
+ min_sdk_version: "29",
+ visibility: [":__subpackages__"],
+}
+
ndk_headers {
name: "libbinder_ndk_headers",
from: "include_ndk/android",
@@ -246,26 +258,14 @@
license: "NOTICE",
}
-// TODO(b/160624671): package with the aidl compiler
-ndk_headers {
- name: "libbinder_ndk_helper_headers",
- from: "include_cpp/android",
- to: "android",
- srcs: [
- "include_cpp/android/*.h",
- ],
- license: "NOTICE",
- // These are intentionally not C. It's a mistake that they're in the NDK.
- // See the bug above.
- skip_verification: true,
-}
+// include_cpp are packaged in development/build/sdk.atree with the AIDL compiler
ndk_library {
name: "libbinder_ndk",
symbol_file: "libbinder_ndk.map.txt",
first_version: "29",
export_header_libs: [
- "libbinder_ndk_headers",
- "libbinder_ndk_helper_headers",
+ // used to be part of the NDK, platform things depend on it
+ "libbinder_headers_platform_shared_ndk",
],
}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 340014a..04f1517 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -195,7 +195,7 @@
impl PartialEq for SpIBinder {
fn eq(&self, other: &Self) -> bool {
- ptr::eq(self.0.as_ptr(), other.0.as_ptr())
+ self.cmp(other) == Ordering::Equal
}
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 1e463a4..0e653af 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -51,6 +51,30 @@
],
}
+cc_test {
+ name: "binderCacheUnitTest",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: [
+ "binderCacheUnitTest.cpp",
+ ],
+ shared_libs: [
+ "liblog",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+ static_libs: [
+ "libfakeservicemanager",
+ ],
+ defaults: ["libbinder_client_cache_flag"],
+ test_suites: ["general-tests"],
+ require_root: true,
+}
+
// unit test only, which can run on host and doesn't use /dev/binder
cc_test {
name: "binderUnitTest",
diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp
new file mode 100644
index 0000000..92dab19
--- /dev/null
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2024 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 <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include <android/os/IServiceManager.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IServiceManagerUnitTestHelper.h>
+#include "fakeservicemanager/FakeServiceManager.h"
+
+#include <sys/prctl.h>
+#include <thread>
+
+using namespace android;
+
+#ifdef LIBBINDER_CLIENT_CACHE
+constexpr bool kUseLibbinderCache = true;
+#else
+constexpr bool kUseLibbinderCache = false;
+#endif
+
+// A service name which is in the static list of cachable services
+const String16 kCachedServiceName = String16("isub");
+
+#define EXPECT_OK(status) \
+ do { \
+ binder::Status stat = (status); \
+ EXPECT_TRUE(stat.isOk()) << stat; \
+ } while (false)
+
+const String16 kServerName = String16("binderCacheUnitTest");
+
+class FooBar : public BBinder {
+public:
+ status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t) {
+ // exit the server
+ std::thread([] { exit(EXIT_FAILURE); }).detach();
+ return OK;
+ }
+ void killServer(sp<IBinder> binder) {
+ Parcel data, reply;
+ binder->transact(0, data, &reply, 0);
+ }
+};
+
+class MockAidlServiceManager : public os::IServiceManagerDefault {
+public:
+ MockAidlServiceManager() : innerSm() {}
+
+ binder::Status checkService(const ::std::string& name, os::Service* _out) override {
+ sp<IBinder> binder = innerSm.getService(String16(name.c_str()));
+ *_out = os::Service::make<os::Service::Tag::binder>(binder);
+ return binder::Status::ok();
+ }
+
+ binder::Status addService(const std::string& name, const sp<IBinder>& service,
+ bool allowIsolated, int32_t dumpPriority) override {
+ return binder::Status::fromStatusT(
+ innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority));
+ }
+
+ FakeServiceManager innerSm;
+};
+
+class LibbinderCacheTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ sp<MockAidlServiceManager> sm = sp<MockAidlServiceManager>::make();
+ mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(sm);
+ }
+
+ void TearDown() override {}
+
+public:
+ void cacheAndConfirmCacheHit(const sp<IBinder>& binder1, const sp<IBinder>& binder2) {
+ // Add a service
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
+ // Get the service. This caches it.
+ sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+ ASSERT_EQ(binder1, result);
+
+ // Add the different binder and replace the service.
+ // The cache should still hold the original binder.
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+ result = mServiceManager->checkService(kCachedServiceName);
+ if (kUseLibbinderCache) {
+ // If cache is enabled, we should get the binder to Service Manager.
+ EXPECT_EQ(binder1, result);
+ } else {
+ // If cache is disabled, then we should get the newer binder
+ EXPECT_EQ(binder2, result);
+ }
+ }
+
+ sp<android::IServiceManager> mServiceManager;
+};
+
+TEST_F(LibbinderCacheTest, AddLocalServiceAndConfirmCacheHit) {
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ cacheAndConfirmCacheHit(binder1, binder2);
+}
+
+TEST_F(LibbinderCacheTest, AddRemoteServiceAndConfirmCacheHit) {
+ sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+ ASSERT_NE(binder1, nullptr);
+ sp<IBinder> binder2 = IInterface::asBinder(mServiceManager);
+
+ cacheAndConfirmCacheHit(binder1, binder2);
+}
+
+TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) {
+ sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+ FooBar foo = FooBar();
+
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
+
+ // Check Service, this caches the binder
+ sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+ ASSERT_EQ(binder1, result);
+
+ // Kill the server, this should remove from cache.
+ foo.killServer(binder1);
+ pid_t pid;
+ ASSERT_EQ(OK, binder1->getDebugPid(&pid));
+ system(("kill -9 " + std::to_string(pid)).c_str());
+
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ // Add new service with the same name.
+ // This will replace the service in FakeServiceManager.
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+ // Confirm that new service is returned instead of old.
+ sp<IBinder> result2 = mServiceManager->checkService(kCachedServiceName);
+ ASSERT_EQ(binder2, result2);
+}
+
+TEST_F(LibbinderCacheTest, NullBinderNotCached) {
+ sp<IBinder> binder1 = nullptr;
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ // Check for a cacheble service which isn't registered.
+ // FakeServiceManager should return nullptr.
+ // This shouldn't be cached.
+ sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+ ASSERT_EQ(binder1, result);
+
+ // Add the same service
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+ // This should return the newly added service.
+ result = mServiceManager->checkService(kCachedServiceName);
+ EXPECT_EQ(binder2, result);
+}
+
+TEST_F(LibbinderCacheTest, DoNotCacheServiceNotInList) {
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ sp<IBinder> binder2 = sp<BBinder>::make();
+ String16 serviceName = String16("NewLibbinderCacheTest");
+ // Add a service
+ EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder1));
+ // Get the service. This shouldn't caches it.
+ sp<IBinder> result = mServiceManager->checkService(serviceName);
+ ASSERT_EQ(binder1, result);
+
+ // Add the different binder and replace the service.
+ EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder2));
+
+ // Confirm that we get the new service
+ result = mServiceManager->checkService(serviceName);
+ EXPECT_EQ(binder2, result);
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+ // Start a FooBar service and add it to the servicemanager.
+ sp<IBinder> server = new FooBar();
+ defaultServiceManager()->addService(kServerName, server);
+
+ IPCThreadState::self()->joinThreadPool(true);
+ exit(1); // should not reach
+ }
+
+ status_t err = ProcessState::self()->setThreadPoolMaxThreadCount(3);
+ ProcessState::self()->startThreadPool();
+ CHECK_EQ(ProcessState::self()->isThreadPoolStarted(), true);
+ CHECK_GT(ProcessState::self()->getThreadPoolMaxTotalThreadCount(), 0);
+
+ auto binder = defaultServiceManager()->waitForService(kServerName);
+ CHECK_NE(nullptr, binder.get());
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3038de9..fbca35e 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -365,26 +365,57 @@
session->setMaxOutgoingConnections(options.numOutgoingConnections);
session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
+ sockaddr_storage addr{};
+ socklen_t addrLen = 0;
+
switch (socketType) {
- case SocketType::PRECONNECTED:
+ case SocketType::PRECONNECTED: {
+ sockaddr_un addr_un{};
+ addr_un.sun_family = AF_UNIX;
+ strcpy(addr_un.sun_path, serverConfig.addr.c_str());
+ addr = *reinterpret_cast<sockaddr_storage*>(&addr_un);
+ addrLen = sizeof(sockaddr_un);
+
status = session->setupPreconnectedClient({}, [=]() {
return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
});
- break;
+ } break;
case SocketType::UNIX_RAW:
- case SocketType::UNIX:
+ case SocketType::UNIX: {
+ sockaddr_un addr_un{};
+ addr_un.sun_family = AF_UNIX;
+ strcpy(addr_un.sun_path, serverConfig.addr.c_str());
+ addr = *reinterpret_cast<sockaddr_storage*>(&addr_un);
+ addrLen = sizeof(sockaddr_un);
+
status = session->setupUnixDomainClient(serverConfig.addr.c_str());
- break;
+ } break;
case SocketType::UNIX_BOOTSTRAP:
status = session->setupUnixDomainSocketBootstrapClient(
unique_fd(dup(bootstrapClientFd.get())));
break;
- case SocketType::VSOCK:
+ case SocketType::VSOCK: {
+ sockaddr_vm addr_vm{
+ .svm_family = AF_VSOCK,
+ .svm_port = static_cast<unsigned int>(serverInfo.port),
+ .svm_cid = VMADDR_CID_LOCAL,
+ };
+ addr = *reinterpret_cast<sockaddr_storage*>(&addr_vm);
+ addrLen = sizeof(sockaddr_vm);
+
status = session->setupVsockClient(VMADDR_CID_LOCAL, serverInfo.port);
- break;
- case SocketType::INET:
- status = session->setupInetClient("127.0.0.1", serverInfo.port);
- break;
+ } break;
+ case SocketType::INET: {
+ const std::string ip_addr = "127.0.0.1";
+ sockaddr_in addr_in{};
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = htons(serverInfo.port);
+ inet_aton(ip_addr.c_str(), &addr_in.sin_addr);
+ addr = *reinterpret_cast<sockaddr_storage*>(&addr_in);
+ addrLen = sizeof(sockaddr_in);
+
+ status = session->setupInetClient(ip_addr.c_str(), serverInfo.port);
+ } break;
case SocketType::TIPC:
status = session->setupPreconnectedClient({}, [=]() {
#ifdef BINDER_RPC_TO_TRUSTY_TEST
@@ -413,7 +444,7 @@
break;
}
LOG_ALWAYS_FATAL_IF(status != OK, "Could not connect: %s", statusToString(status).c_str());
- ret->sessions.push_back({session, session->getRootObject()});
+ ret->sessions.push_back({session, session->getRootObject(), addr, addrLen});
}
return ret;
}
@@ -1127,6 +1158,139 @@
ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
}
+// TODO need to add IServiceManager.cpp/.h to libbinder_no_kernel
+#ifdef BINDER_WITH_KERNEL_IPC
+
+class BinderRpcAccessor : public BinderRpc {
+ void SetUp() override {
+ if (serverSingleThreaded()) {
+ // This blocks on android::FdTrigger::triggerablePoll when attempting to set
+ // up the client RpcSession
+ GTEST_SKIP() << "Accessors are not supported for single threaded libbinder";
+ }
+ if (rpcSecurity() == RpcSecurity::TLS) {
+ GTEST_SKIP() << "Accessors are not supported with TLS";
+ // ... for now
+ }
+
+ if (socketType() == SocketType::UNIX_BOOTSTRAP) {
+ GTEST_SKIP() << "Accessors do not support UNIX_BOOTSTRAP because no connection "
+ "information is known";
+ }
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "Accessors do not support TIPC because the socket transport is not "
+ "known in libbinder";
+ }
+ BinderRpc::SetUp();
+ }
+};
+
+inline void waitForExtraSessionCleanup(const BinderRpcTestProcessSession& proc) {
+ // Need to give the server some time to delete its RpcSession after our last
+ // reference is dropped, closing the connection. Check for up to 1 second,
+ // every 10 ms.
+ for (size_t i = 0; i < 100; i++) {
+ std::vector<int32_t> remoteCounts;
+ EXPECT_OK(proc.rootIface->countBinders(&remoteCounts));
+ // We exect the original binder to still be alive, we just want to wait
+ // for this extra session to be cleaned up.
+ if (remoteCounts.size() == proc.proc->sessions.size()) break;
+ usleep(10000);
+ }
+}
+
+TEST_P(BinderRpcAccessor, InjectAndGetServiceHappyPath) {
+ constexpr size_t kNumThreads = 10;
+ const String16 kInstanceName("super.cool.service/better_than_default");
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
+ return createAccessor(name,
+ [&](const String16& name, sockaddr* outAddr,
+ socklen_t addrSize) -> status_t {
+ if (outAddr == nullptr ||
+ addrSize < proc.proc->sessions[0].addrLen) {
+ return BAD_VALUE;
+ }
+ if (name == kInstanceName) {
+ if (proc.proc->sessions[0].addr.ss_family == AF_UNIX) {
+ sockaddr_un* un = reinterpret_cast<sockaddr_un*>(
+ &proc.proc->sessions[0].addr);
+ ALOGE("inside callback: %s", un->sun_path);
+ }
+ std::memcpy(outAddr, &proc.proc->sessions[0].addr,
+ proc.proc->sessions[0].addrLen);
+ return OK;
+ }
+ return NAME_NOT_FOUND;
+ });
+ });
+
+ EXPECT_FALSE(receipt.expired());
+
+ sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+ sp<IBinderRpcTest> service = checked_interface_cast<IBinderRpcTest>(binder);
+ EXPECT_NE(service, nullptr);
+
+ sp<IBinder> out;
+ EXPECT_OK(service->repeatBinder(binder, &out));
+ EXPECT_EQ(binder, out);
+
+ out.clear();
+ binder.clear();
+ service.clear();
+
+ status_t status = removeAccessorProvider(receipt);
+ EXPECT_EQ(status, OK);
+
+ waitForExtraSessionCleanup(proc);
+}
+
+TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) {
+ const String16 kInstanceName("doesnt_matter_nothing_checks");
+
+ bool isProviderDeleted = false;
+
+ auto receipt = addAccessorProvider([&](const String16&) -> sp<IBinder> { return nullptr; });
+ EXPECT_FALSE(receipt.expired());
+
+ sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+ EXPECT_EQ(binder, nullptr);
+
+ status_t status = removeAccessorProvider(receipt);
+ EXPECT_EQ(status, OK);
+}
+
+TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) {
+ constexpr size_t kNumThreads = 10;
+ const String16 kInstanceName("super.cool.service/better_than_default");
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ bool isProviderDeleted = false;
+ bool isAccessorDeleted = false;
+
+ auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
+ return createAccessor(name, [&](const String16&, sockaddr*, socklen_t) -> status_t {
+ // don't fill in outAddr
+ return NAME_NOT_FOUND;
+ });
+ });
+
+ EXPECT_FALSE(receipt.expired());
+
+ sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+ EXPECT_EQ(binder, nullptr);
+
+ status_t status = removeAccessorProvider(receipt);
+ EXPECT_EQ(status, OK);
+}
+
+#endif // BINDER_WITH_KERNEL_IPC
+
#ifdef BINDER_RPC_TO_TRUSTY_TEST
static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() {
@@ -1315,6 +1479,11 @@
INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()),
BinderRpc::PrintParamInfo);
+#ifdef BINDER_WITH_KERNEL_IPC
+INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpcAccessor, ::testing::ValuesIn(getBinderRpcParams()),
+ BinderRpc::PrintParamInfo);
+#endif // BINDER_WITH_KERNEL_IPC
+
class BinderRpcServerRootObject
: public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index 2c9646b..c8a8acc 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -35,6 +35,12 @@
struct SessionInfo {
sp<RpcSession> session;
sp<IBinder> root;
+// Trusty defines its own socket APIs in trusty_ipc.h but doesn't include
+// sockaddr types.
+#ifndef __TRUSTY__
+ sockaddr_storage addr;
+ socklen_t addrLen;
+#endif
};
// client session objects associated with other process
diff --git a/libs/bufferstreams/rust/src/stream_config.rs b/libs/bufferstreams/rust/src/stream_config.rs
index 454bdf1..8288f9f 100644
--- a/libs/bufferstreams/rust/src/stream_config.rs
+++ b/libs/bufferstreams/rust/src/stream_config.rs
@@ -32,10 +32,23 @@
pub stride: u32,
}
+impl From<StreamConfig> for HardwareBufferDescription {
+ fn from(config: StreamConfig) -> Self {
+ HardwareBufferDescription::new(
+ config.width,
+ config.height,
+ config.layers,
+ config.format,
+ config.usage,
+ config.stride,
+ )
+ }
+}
+
impl StreamConfig {
/// Tries to create a new HardwareBuffer from settings in a [StreamConfig].
pub fn create_hardware_buffer(&self) -> Option<HardwareBuffer> {
- HardwareBuffer::new(self.width, self.height, self.layers, self.format, self.usage)
+ HardwareBuffer::new(&(*self).into())
}
}
@@ -59,9 +72,10 @@
assert!(maybe_buffer.is_some());
let buffer = maybe_buffer.unwrap();
- assert_eq!(config.width, buffer.width());
- assert_eq!(config.height, buffer.height());
- assert_eq!(config.format, buffer.format());
- assert_eq!(config.usage, buffer.usage());
+ let description = buffer.description();
+ assert_eq!(config.width, description.width());
+ assert_eq!(config.height, description.height());
+ assert_eq!(config.format, description.format());
+ assert_eq!(config.usage, description.usage());
}
}
diff --git a/libs/gui/aidl/android/gui/JankData.aidl b/libs/gui/aidl/android/gui/JankData.aidl
index 7ea9d22..ec13681 100644
--- a/libs/gui/aidl/android/gui/JankData.aidl
+++ b/libs/gui/aidl/android/gui/JankData.aidl
@@ -29,7 +29,17 @@
int jankType;
/**
- * Expected duration in nanoseconds of this frame.
+ * Time between frames in nanoseconds.
*/
long frameIntervalNs;
+
+ /**
+ * Time allocated to the application to render this frame.
+ */
+ long scheduledAppFrameTimeNs;
+
+ /**
+ * Time taken by the application to render this frame.
+ */
+ long actualAppFrameTimeNs;
}
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index 7468401..df9b73b 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -98,4 +98,12 @@
description: "Remove usage of IGBPs in the *Processor and Camera3*"
bug: "342199002"
is_fixed_read_only: true
-} # wb_camera3_and_processors
\ No newline at end of file
+} # wb_camera3_and_processors
+
+flag {
+ name: "wb_libcameraservice"
+ namespace: "core_graphics"
+ description: "Remove usage of IGBPs in the libcameraservice."
+ bug: "342197849"
+ is_fixed_read_only: true
+} # wb_libcameraservice
\ No newline at end of file
diff --git a/libs/gui/tests/Choreographer_test.cpp b/libs/gui/tests/Choreographer_test.cpp
index 2ac2550..8db48d2 100644
--- a/libs/gui/tests/Choreographer_test.cpp
+++ b/libs/gui/tests/Choreographer_test.cpp
@@ -52,25 +52,23 @@
sp<Looper> looper = Looper::prepare(0);
Choreographer* choreographer = Choreographer::getForThread();
VsyncCallback animationCb;
- VsyncCallback inputCb;
-
choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0,
CALLBACK_ANIMATION);
+ VsyncCallback inputCb;
choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &inputCb, 0,
CALLBACK_INPUT);
-
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
- nsecs_t currTime;
- int pollResult;
+ auto startTime = std::chrono::system_clock::now();
do {
- pollResult = looper->pollOnce(16);
- currTime = systemTime(SYSTEM_TIME_MONOTONIC);
- } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()) &&
- (pollResult != Looper::POLL_TIMEOUT && pollResult != Looper::POLL_ERROR) &&
- (currTime - startTime < 3000));
-
- ASSERT_TRUE(inputCb.callbackReceived()) << "did not receive input callback";
- ASSERT_TRUE(animationCb.callbackReceived()) << "did not receive animation callback";
+ static constexpr int32_t timeoutMs = 1000;
+ int pollResult = looper->pollOnce(timeoutMs);
+ ASSERT_TRUE((pollResult != Looper::POLL_TIMEOUT) && (pollResult != Looper::POLL_ERROR))
+ << "Failed to poll looper. Poll result = " << pollResult;
+ auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::system_clock::now() - startTime);
+ ASSERT_LE(elapsedMs.count(), timeoutMs)
+ << "Timed out waiting for callbacks. inputCb=" << inputCb.callbackReceived()
+ << " animationCb=" << animationCb.callbackReceived();
+ } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()));
ASSERT_EQ(inputCb.frameTime, animationCb.frameTime)
<< android::base::StringPrintf("input and animation callback frame times don't match. "
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index 99ffa68..eb41918 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "InputTransport"
+#define LOG_TAG "InputConsumerNoResampling"
#define ATRACE_TAG ATRACE_TAG_INPUT
#include <chrono>
@@ -33,8 +33,6 @@
#include <input/PrintTools.h>
#include <input/TraceTools.h>
-namespace input_flags = com::android::input::flags;
-
namespace android {
namespace {
@@ -46,6 +44,27 @@
const bool DEBUG_TRANSPORT_CONSUMER =
__android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO);
+/**
+ * RealLooper is a wrapper of Looper. All the member functions exclusively call the internal looper.
+ * This class' behavior is the same as Looper.
+ */
+class RealLooper final : public LooperInterface {
+public:
+ RealLooper(sp<Looper> looper) : mLooper{looper} {}
+
+ int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+ void* data) override {
+ return mLooper->addFd(fd, ident, events, callback, data);
+ }
+
+ int removeFd(int fd) override { return mLooper->removeFd(fd); }
+
+ sp<Looper> getLooper() const override { return mLooper; }
+
+private:
+ sp<Looper> mLooper;
+};
+
std::unique_ptr<KeyEvent> createKeyEvent(const InputMessage& msg) {
std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>();
event->initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source,
@@ -173,22 +192,20 @@
bool isPointerEvent(const MotionEvent& motionEvent) {
return (motionEvent.getSource() & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
}
-
} // namespace
using android::base::Result;
-using android::base::StringPrintf;
// --- InputConsumerNoResampling ---
InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- sp<Looper> looper,
+ std::shared_ptr<LooperInterface> looper,
InputConsumerCallbacks& callbacks,
std::unique_ptr<Resampler> resampler)
- : mChannel(channel),
- mLooper(looper),
+ : mChannel{channel},
+ mLooper{looper},
mCallbacks(callbacks),
- mResampler(std::move(resampler)),
+ mResampler{std::move(resampler)},
mFdEvents(0) {
LOG_ALWAYS_FATAL_IF(mLooper == nullptr);
mCallback = sp<LooperEventCallback>::make(
@@ -199,6 +216,13 @@
setFdEvents(ALOOPER_EVENT_INPUT);
}
+InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
+ sp<Looper> looper,
+ InputConsumerCallbacks& callbacks,
+ std::unique_ptr<Resampler> resampler)
+ : InputConsumerNoResampling(channel, std::make_shared<RealLooper>(looper), callbacks,
+ std::move(resampler)) {}
+
InputConsumerNoResampling::~InputConsumerNoResampling() {
ensureCalledOnLooperThread(__func__);
consumeBatchedInputEvents(std::nullopt);
@@ -513,7 +537,7 @@
void InputConsumerNoResampling::ensureCalledOnLooperThread(const char* func) const {
sp<Looper> callingThreadLooper = Looper::getForThread();
- if (callingThreadLooper != mLooper) {
+ if (callingThreadLooper != mLooper->getLooper()) {
LOG(FATAL) << "The function " << func << " can only be called on the looper thread";
}
}
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 9b6fe3c..4f4ea85 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -31,6 +31,7 @@
pub use keyboard_classifier::KeyboardClassifier;
#[cxx::bridge(namespace = "android::input")]
+#[allow(clippy::needless_maybe_sized)]
#[allow(unsafe_op_in_unsafe_fn)]
mod ffi {
#[namespace = "android"]
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 132866b..43bc894 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -16,6 +16,7 @@
"BlockingQueue_test.cpp",
"IdGenerator_test.cpp",
"InputChannel_test.cpp",
+ "InputConsumer_test.cpp",
"InputDevice_test.cpp",
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
@@ -25,6 +26,8 @@
"MotionPredictorMetricsManager_test.cpp",
"Resampler_test.cpp",
"RingBuffer_test.cpp",
+ "TestInputChannel.cpp",
+ "TestLooper.cpp",
"TfLiteMotionPredictor_test.cpp",
"TouchResampling_test.cpp",
"TouchVideoFrame_test.cpp",
diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp
new file mode 100644
index 0000000..c30f243
--- /dev/null
+++ b/libs/input/tests/InputConsumer_test.cpp
@@ -0,0 +1,123 @@
+/**
+ * Copyright 2024 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 <input/InputConsumerNoResampling.h>
+
+#include <memory>
+#include <optional>
+#include <utility>
+
+#include <TestInputChannel.h>
+#include <TestLooper.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <input/BlockingQueue.h>
+#include <input/InputEventBuilders.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class InputConsumerTest : public testing::Test, public InputConsumerCallbacks {
+protected:
+ InputConsumerTest()
+ : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
+ mTestLooper{std::make_shared<TestLooper>()} {
+ Looper::setForThread(mTestLooper->getLooper());
+ mConsumer = std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper,
+ *this, /*resampler=*/nullptr);
+ }
+
+ void assertOnBatchedInputEventPendingWasCalled();
+
+ std::shared_ptr<TestInputChannel> mClientTestChannel;
+ std::shared_ptr<TestLooper> mTestLooper;
+ std::unique_ptr<InputConsumerNoResampling> mConsumer;
+
+ BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents;
+ BlockingQueue<std::unique_ptr<MotionEvent>> mMotionEvents;
+ BlockingQueue<std::unique_ptr<FocusEvent>> mFocusEvents;
+ BlockingQueue<std::unique_ptr<CaptureEvent>> mCaptureEvents;
+ BlockingQueue<std::unique_ptr<DragEvent>> mDragEvents;
+ BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
+
+private:
+ size_t onBatchedInputEventPendingInvocationCount{0};
+
+ // InputConsumerCallbacks interface
+ void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
+ mKeyEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ }
+ void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override {
+ mMotionEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ }
+ void onBatchedInputEventPending(int32_t pendingBatchSource) override {
+ if (!mConsumer->probablyHasInput()) {
+ ADD_FAILURE() << "should deterministically have input because there is a batch";
+ }
+ ++onBatchedInputEventPendingInvocationCount;
+ };
+ void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
+ mFocusEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ };
+ void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) override {
+ mCaptureEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ };
+ void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) override {
+ mDragEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ }
+ void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) override {
+ mTouchModeEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ };
+};
+
+void InputConsumerTest::assertOnBatchedInputEventPendingWasCalled() {
+ ASSERT_GT(onBatchedInputEventPendingInvocationCount, 0UL)
+ << "onBatchedInputEventPending has not been called.";
+ --onBatchedInputEventPendingInvocationCount;
+}
+
+TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {
+ mClientTestChannel->enqueueMessage(
+ InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}.build());
+ mClientTestChannel->enqueueMessage(
+ InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}.build());
+ mClientTestChannel->enqueueMessage(
+ InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}.build());
+
+ mClientTestChannel->assertNoSentMessages();
+
+ mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT);
+
+ assertOnBatchedInputEventPendingWasCalled();
+
+ mConsumer->consumeBatchedInputEvents(std::nullopt);
+
+ std::unique_ptr<MotionEvent> batchedMotionEvent = mMotionEvents.pop();
+ ASSERT_NE(batchedMotionEvent, nullptr);
+
+ mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+
+ EXPECT_EQ(batchedMotionEvent->getHistorySize() + 1, 3UL);
+}
+} // namespace android
diff --git a/libs/input/tests/TestInputChannel.cpp b/libs/input/tests/TestInputChannel.cpp
new file mode 100644
index 0000000..d5f00b6
--- /dev/null
+++ b/libs/input/tests/TestInputChannel.cpp
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2024 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 "TestInputChannel"
+#define ATRACE_TAG ATRACE_TAG_INPUT
+
+#include <TestInputChannel.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace {
+constexpr int FAKE_FD{-1};
+} // namespace
+
+// --- TestInputChannel ---
+
+TestInputChannel::TestInputChannel(const std::string& name)
+ : InputChannel{name, base::unique_fd(FAKE_FD), sp<BBinder>::make()} {}
+
+void TestInputChannel::enqueueMessage(const InputMessage& message) {
+ mReceivedMessages.push(message);
+}
+
+status_t TestInputChannel::sendMessage(const InputMessage* message) {
+ LOG_IF(FATAL, message == nullptr)
+ << "TestInputChannel " << getName() << ". No message was passed to sendMessage.";
+
+ mSentMessages.push(*message);
+ return OK;
+}
+
+base::Result<InputMessage> TestInputChannel::receiveMessage() {
+ if (mReceivedMessages.empty()) {
+ return base::Error(WOULD_BLOCK);
+ }
+ InputMessage message = mReceivedMessages.front();
+ mReceivedMessages.pop();
+ return message;
+}
+
+bool TestInputChannel::probablyHasInput() const {
+ return !mReceivedMessages.empty();
+}
+
+void TestInputChannel::assertFinishMessage(uint32_t seq, bool handled) {
+ ASSERT_FALSE(mSentMessages.empty())
+ << "TestInputChannel " << getName() << ". Cannot assert. mSentMessages is empty.";
+
+ const InputMessage& finishMessage = mSentMessages.front();
+
+ EXPECT_EQ(finishMessage.header.seq, seq)
+ << "TestInputChannel " << getName()
+ << ". Sequence mismatch. Message seq: " << finishMessage.header.seq
+ << " Expected seq: " << seq;
+
+ EXPECT_EQ(finishMessage.body.finished.handled, handled)
+ << "TestInputChannel " << getName()
+ << ". Handled value mismatch. Message val: " << std::boolalpha
+ << finishMessage.body.finished.handled << "Expected val: " << handled
+ << std::noboolalpha;
+ mSentMessages.pop();
+}
+
+void TestInputChannel::assertNoSentMessages() const {
+ ASSERT_TRUE(mSentMessages.empty());
+}
+} // namespace android
\ No newline at end of file
diff --git a/libs/input/tests/TestInputChannel.h b/libs/input/tests/TestInputChannel.h
new file mode 100644
index 0000000..43253ec
--- /dev/null
+++ b/libs/input/tests/TestInputChannel.h
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2024 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 <queue>
+#include <string>
+
+#include <android-base/result.h>
+#include <gtest/gtest.h>
+#include <input/InputTransport.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class TestInputChannel final : public InputChannel {
+public:
+ explicit TestInputChannel(const std::string& name);
+
+ /**
+ * Enqueues a message in mReceivedMessages.
+ */
+ void enqueueMessage(const InputMessage& message);
+
+ /**
+ * Pushes message to mSentMessages. In the default implementation, InputChannel sends messages
+ * through a file descriptor. TestInputChannel, on the contrary, stores sent messages in
+ * mSentMessages for assertion reasons.
+ */
+ status_t sendMessage(const InputMessage* message) override;
+
+ /**
+ * Returns an InputMessage from mReceivedMessages. This is done instead of retrieving data
+ * directly from fd.
+ */
+ base::Result<InputMessage> receiveMessage() override;
+
+ /**
+ * Returns if mReceivedMessages is not empty.
+ */
+ bool probablyHasInput() const override;
+
+ void assertFinishMessage(uint32_t seq, bool handled);
+
+ void assertNoSentMessages() const;
+
+private:
+ // InputMessages received by the endpoint.
+ std::queue<InputMessage> mReceivedMessages;
+ // InputMessages sent by the endpoint.
+ std::queue<InputMessage> mSentMessages;
+};
+} // namespace android
diff --git a/libs/input/tests/TestLooper.cpp b/libs/input/tests/TestLooper.cpp
new file mode 100644
index 0000000..e0f01ed
--- /dev/null
+++ b/libs/input/tests/TestLooper.cpp
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2024 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 <TestLooper.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+
+TestLooper::TestLooper() : mLooper(sp<Looper>::make(/*allowNonCallbacks=*/false)) {}
+
+int TestLooper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+ void* data) {
+ mCallbacks[fd] = callback;
+ constexpr int SUCCESS{1};
+ return SUCCESS;
+}
+
+int TestLooper::removeFd(int fd) {
+ if (auto it = mCallbacks.find(fd); it != mCallbacks.cend()) {
+ mCallbacks.erase(fd);
+ constexpr int SUCCESS{1};
+ return SUCCESS;
+ }
+ constexpr int FAILURE{0};
+ return FAILURE;
+}
+
+void TestLooper::invokeCallback(int fd, int events) {
+ auto it = mCallbacks.find(fd);
+ LOG_IF(FATAL, it == mCallbacks.cend()) << "Fd does not exist in mCallbacks.";
+ mCallbacks[fd]->handleEvent(fd, events, /*data=*/nullptr);
+}
+
+sp<Looper> TestLooper::getLooper() const {
+ return mLooper;
+}
+} // namespace android
\ No newline at end of file
diff --git a/libs/input/tests/TestLooper.h b/libs/input/tests/TestLooper.h
new file mode 100644
index 0000000..3242bc7
--- /dev/null
+++ b/libs/input/tests/TestLooper.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2024 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 <map>
+
+#include <input/LooperInterface.h>
+
+namespace android {
+/**
+ * TestLooper provides a mechanism to directly trigger Looper's callback.
+ */
+class TestLooper final : public LooperInterface {
+public:
+ TestLooper();
+
+ /**
+ * Adds a file descriptor to mCallbacks. Ident, events, and data parameters are ignored. If
+ * addFd is called with an existent file descriptor and a different callback, the previous
+ * callback is overwritten.
+ */
+ int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+ void* data) override;
+
+ /**
+ * Removes a file descriptor from mCallbacks. If fd is not in mCallbacks, returns FAILURE.
+ */
+ int removeFd(int fd) override;
+
+ /**
+ * Calls handleEvent of the file descriptor. Fd must be in mCallbacks. Otherwise, invokeCallback
+ * fatally logs.
+ */
+ void invokeCallback(int fd, int events);
+
+ sp<Looper> getLooper() const override;
+
+private:
+ std::map<int /*fd*/, sp<LooperCallback>> mCallbacks;
+ sp<Looper> mLooper;
+};
+} // namespace android
\ No newline at end of file
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 8558074..a8a86ba 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -67,9 +67,6 @@
// Android O
first_version: "26",
- export_header_libs: [
- "libnativewindow_ndk_headers",
- ],
}
cc_library {
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
index 97740db..d68d6ba 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -29,6 +29,8 @@
"--bitfield-enum=AHardwareBuffer_UsageFlags",
"--allowlist-file=.*/nativewindow/include/.*\\.h",
+ "--allowlist-file=.*/include/cutils/.*\\.h",
+ "--allowlist-file=.*/include_outside_system/cutils/.*\\.h",
"--blocklist-type",
"AParcel",
"--raw-line",
@@ -39,6 +41,7 @@
],
shared_libs: [
"libbinder_ndk",
+ "libcutils",
"libnativewindow",
],
rustlibs: [
@@ -66,6 +69,7 @@
srcs: [":libnativewindow_bindgen_internal"],
shared_libs: [
"libbinder_ndk",
+ "libcutils",
"libnativewindow",
],
rustlibs: [
diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs
new file mode 100644
index 0000000..a3a9dc6
--- /dev/null
+++ b/libs/nativewindow/rust/src/handle.rs
@@ -0,0 +1,92 @@
+// Copyright (C) 2024 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.
+
+use std::{mem::forget, ptr::NonNull};
+
+/// Rust wrapper around `native_handle_t`.
+///
+/// This owns the `native_handle_t` and its file descriptors, and will close them and free it when
+/// it is dropped.
+#[derive(Debug)]
+pub struct NativeHandle(NonNull<ffi::native_handle_t>);
+
+impl NativeHandle {
+ /// Wraps a raw `native_handle_t` pointer, taking ownership of it.
+ ///
+ /// # Safety
+ ///
+ /// `native_handle` must be a valid pointer to a `native_handle_t`, and must not be used
+ /// anywhere else after calling this method.
+ pub unsafe fn from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self {
+ Self(native_handle)
+ }
+
+ /// Creates a new `NativeHandle` wrapping a clone of the given `native_handle_t` pointer.
+ ///
+ /// Unlike [`from_raw`](Self::from_raw) this doesn't take ownership of the pointer passed in, so
+ /// the caller remains responsible for closing and freeing it.
+ ///
+ /// # Safety
+ ///
+ /// `native_handle` must be a valid pointer to a `native_handle_t`.
+ pub unsafe fn clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self> {
+ // SAFETY: The caller promised that `native_handle` was valid.
+ let cloned = unsafe { ffi::native_handle_clone(native_handle.as_ptr()) };
+ NonNull::new(cloned).map(Self)
+ }
+
+ /// Returns a raw pointer to the wrapped `native_handle_t`.
+ ///
+ /// This is only valid as long as this `NativeHandle` exists, so shouldn't be stored. It mustn't
+ /// be closed or deleted.
+ pub fn as_raw(&self) -> NonNull<ffi::native_handle_t> {
+ self.0
+ }
+
+ /// Turns the `NativeHandle` into a raw `native_handle_t`.
+ ///
+ /// The caller takes ownership of the `native_handle_t` and its file descriptors, so is
+ /// responsible for closing and freeing it.
+ pub fn into_raw(self) -> NonNull<ffi::native_handle_t> {
+ let raw = self.0;
+ forget(self);
+ raw
+ }
+}
+
+impl Clone for NativeHandle {
+ fn clone(&self) -> Self {
+ // SAFETY: Our wrapped `native_handle_t` pointer is always valid.
+ unsafe { Self::clone_from_raw(self.0) }.expect("native_handle_clone returned null")
+ }
+}
+
+impl Drop for NativeHandle {
+ fn drop(&mut self) {
+ // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
+ // after this because we own it and are being dropped.
+ unsafe {
+ assert_eq!(ffi::native_handle_close(self.0.as_ptr()), 0);
+ assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
+ }
+ }
+}
+
+// SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file
+// descriptors, which aren't tied to any particular thread.
+unsafe impl Send for NativeHandle {}
+
+// SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just
+// integers and file descriptors.
+unsafe impl Sync for NativeHandle {}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index dc3f51f..931c311 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -16,7 +16,10 @@
extern crate nativewindow_bindgen as ffi;
+mod handle;
mod surface;
+
+pub use handle::NativeHandle;
pub use surface::Surface;
pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
@@ -27,11 +30,86 @@
unstable_api::{status_result, AsNative},
StatusCode,
};
-use ffi::{AHardwareBuffer, AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel};
+use ffi::{
+ AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_readFromParcel,
+ AHardwareBuffer_writeToParcel,
+};
use std::fmt::{self, Debug, Formatter};
use std::mem::ManuallyDrop;
use std::ptr::{self, null_mut, NonNull};
+/// Wrapper around a C `AHardwareBuffer_Desc`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct HardwareBufferDescription(AHardwareBuffer_Desc);
+
+impl HardwareBufferDescription {
+ /// Creates a new `HardwareBufferDescription` with the given parameters.
+ pub fn new(
+ width: u32,
+ height: u32,
+ layers: u32,
+ format: AHardwareBuffer_Format::Type,
+ usage: AHardwareBuffer_UsageFlags,
+ stride: u32,
+ ) -> Self {
+ Self(AHardwareBuffer_Desc {
+ width,
+ height,
+ layers,
+ format,
+ usage: usage.0,
+ stride,
+ rfu0: 0,
+ rfu1: 0,
+ })
+ }
+
+ /// Returns the width from the buffer description.
+ pub fn width(&self) -> u32 {
+ self.0.width
+ }
+
+ /// Returns the height from the buffer description.
+ pub fn height(&self) -> u32 {
+ self.0.height
+ }
+
+ /// Returns the number from layers from the buffer description.
+ pub fn layers(&self) -> u32 {
+ self.0.layers
+ }
+
+ /// Returns the format from the buffer description.
+ pub fn format(&self) -> AHardwareBuffer_Format::Type {
+ self.0.format
+ }
+
+ /// Returns the usage bitvector from the buffer description.
+ pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
+ AHardwareBuffer_UsageFlags(self.0.usage)
+ }
+
+ /// Returns the stride from the buffer description.
+ pub fn stride(&self) -> u32 {
+ self.0.stride
+ }
+}
+
+impl Default for HardwareBufferDescription {
+ fn default() -> Self {
+ Self(AHardwareBuffer_Desc {
+ width: 0,
+ height: 0,
+ layers: 0,
+ format: 0,
+ usage: 0,
+ stride: 0,
+ rfu0: 0,
+ rfu1: 0,
+ })
+ }
+}
+
/// Wrapper around an opaque C `AHardwareBuffer`.
#[derive(PartialEq, Eq)]
pub struct HardwareBuffer(NonNull<AHardwareBuffer>);
@@ -43,26 +121,9 @@
/// that the allocation of the given description will never succeed.
///
/// Available since API 29
- pub fn is_supported(
- width: u32,
- height: u32,
- layers: u32,
- format: AHardwareBuffer_Format::Type,
- usage: AHardwareBuffer_UsageFlags,
- stride: u32,
- ) -> bool {
- let buffer_desc = ffi::AHardwareBuffer_Desc {
- width,
- height,
- layers,
- format,
- usage: usage.0,
- stride,
- rfu0: 0,
- rfu1: 0,
- };
- // SAFETY: *buffer_desc will never be null.
- let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
+ pub fn is_supported(buffer_description: &HardwareBufferDescription) -> bool {
+ // SAFETY: The pointer comes from a reference so must be valid.
+ let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_description.0) };
status == 1
}
@@ -74,27 +135,11 @@
///
/// Available since API level 26.
#[inline]
- pub fn new(
- width: u32,
- height: u32,
- layers: u32,
- format: AHardwareBuffer_Format::Type,
- usage: AHardwareBuffer_UsageFlags,
- ) -> Option<Self> {
- let buffer_desc = ffi::AHardwareBuffer_Desc {
- width,
- height,
- layers,
- format,
- usage: usage.0,
- stride: 0,
- rfu0: 0,
- rfu1: 0,
- };
+ pub fn new(buffer_description: &HardwareBufferDescription) -> Option<Self> {
let mut ptr = ptr::null_mut();
// SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
// and return a status, but we check it later.
- let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) };
+ let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_description.0, &mut ptr) };
if status == 0 {
Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null")))
@@ -103,6 +148,50 @@
}
}
+ /// Creates a `HardwareBuffer` from a native handle.
+ ///
+ /// The native handle is cloned, so this doesn't take ownership of the original handle passed
+ /// in.
+ pub fn create_from_handle(
+ handle: &NativeHandle,
+ buffer_description: &HardwareBufferDescription,
+ ) -> Result<Self, StatusCode> {
+ let mut buffer = ptr::null_mut();
+ // SAFETY: The caller guarantees that `handle` is valid, and the buffer pointer is valid
+ // because it comes from a reference. The method we pass means that
+ // `AHardwareBuffer_createFromHandle` will clone the handle rather than taking ownership of
+ // it.
+ let status = unsafe {
+ ffi::AHardwareBuffer_createFromHandle(
+ &buffer_description.0,
+ handle.as_raw().as_ptr(),
+ ffi::CreateFromHandleMethod_AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE
+ .try_into()
+ .unwrap(),
+ &mut buffer,
+ )
+ };
+ status_result(status)?;
+ Ok(Self(NonNull::new(buffer).expect("Allocated AHardwareBuffer was null")))
+ }
+
+ /// Returns a clone of the native handle of the buffer.
+ ///
+ /// Returns `None` if the operation fails for any reason.
+ pub fn cloned_native_handle(&self) -> Option<NativeHandle> {
+ // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid
+ // because it must have been allocated by `AHardwareBuffer_allocate`,
+ // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet
+ // released it.
+ let native_handle = unsafe { ffi::AHardwareBuffer_getNativeHandle(self.0.as_ptr()) };
+ NonNull::new(native_handle.cast_mut()).and_then(|native_handle| {
+ // SAFETY: `AHardwareBuffer_getNativeHandle` should have returned a valid pointer which
+ // is valid at least as long as the buffer is, and `clone_from_raw` clones it rather
+ // than taking ownership of it so the original `native_handle` isn't stored.
+ unsafe { NativeHandle::clone_from_raw(native_handle) }
+ })
+ }
+
/// Adopts the given raw pointer and wraps it in a Rust HardwareBuffer.
///
/// # Safety
@@ -155,37 +244,8 @@
out_id
}
- /// Get the width of this buffer
- pub fn width(&self) -> u32 {
- self.description().width
- }
-
- /// Get the height of this buffer
- pub fn height(&self) -> u32 {
- self.description().height
- }
-
- /// Get the number of layers of this buffer
- pub fn layers(&self) -> u32 {
- self.description().layers
- }
-
- /// Get the format of this buffer
- pub fn format(&self) -> AHardwareBuffer_Format::Type {
- self.description().format
- }
-
- /// Get the usage bitvector of this buffer
- pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
- AHardwareBuffer_UsageFlags(self.description().usage)
- }
-
- /// Get the stride of this buffer
- pub fn stride(&self) -> u32 {
- self.description().stride
- }
-
- fn description(&self) -> ffi::AHardwareBuffer_Desc {
+ /// Returns the description of this buffer.
+ pub fn description(&self) -> HardwareBufferDescription {
let mut buffer_desc = ffi::AHardwareBuffer_Desc {
width: 0,
height: 0,
@@ -198,7 +258,7 @@
};
// SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) };
- buffer_desc
+ HardwareBufferDescription(buffer_desc)
}
}
@@ -281,19 +341,27 @@
#[test]
fn create_valid_buffer_returns_ok() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
512,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- );
+ 0,
+ ));
assert!(buffer.is_some());
}
#[test]
fn create_invalid_buffer_returns_err() {
- let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
+ 512,
+ 512,
+ 1,
+ 0,
+ AHardwareBuffer_UsageFlags(0),
+ 0,
+ ));
assert!(buffer.is_none());
}
@@ -319,39 +387,45 @@
// SAFETY: The pointer must be valid because it was just allocated successfully, and we
// don't use it after calling this.
let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) };
- assert_eq!(buffer.width(), 1024);
+ assert_eq!(buffer.description().width(), 1024);
}
#[test]
fn basic_getters() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
1024,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.expect("Buffer with some basic parameters was not created successfully");
- assert_eq!(buffer.width(), 1024);
- assert_eq!(buffer.height(), 512);
- assert_eq!(buffer.layers(), 1);
- assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
+ let description = buffer.description();
+ assert_eq!(description.width(), 1024);
+ assert_eq!(description.height(), 512);
+ assert_eq!(description.layers(), 1);
assert_eq!(
- buffer.usage(),
+ description.format(),
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
+ );
+ assert_eq!(
+ description.usage(),
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
);
}
#[test]
fn id_getter() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
1024,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.expect("Buffer with some basic parameters was not created successfully");
assert_ne!(0, buffer.id());
@@ -359,13 +433,14 @@
#[test]
fn clone() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
1024,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.expect("Buffer with some basic parameters was not created successfully");
let buffer2 = buffer.clone();
@@ -374,13 +449,14 @@
#[test]
fn into_raw() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
1024,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.expect("Buffer with some basic parameters was not created successfully");
let buffer2 = buffer.clone();
@@ -390,4 +466,26 @@
assert_eq!(remade_buffer, buffer2);
}
+
+ #[test]
+ fn native_handle_and_back() {
+ let buffer_description = HardwareBufferDescription::new(
+ 1024,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ 1024,
+ );
+ let buffer = HardwareBuffer::new(&buffer_description)
+ .expect("Buffer with some basic parameters was not created successfully");
+
+ let native_handle =
+ buffer.cloned_native_handle().expect("Failed to get native handle for buffer");
+ let buffer2 = HardwareBuffer::create_from_handle(&native_handle, &buffer_description)
+ .expect("Failed to create buffer from native handle");
+
+ assert_eq!(buffer.description(), buffer_description);
+ assert_eq!(buffer2.description(), buffer_description);
+ }
}
diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h
index 5689f7d..5046a80 100644
--- a/libs/nativewindow/rust/sys/nativewindow_bindings.h
+++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h
@@ -20,3 +20,5 @@
#include <android/hdr_metadata.h>
#include <android/native_window.h>
#include <android/native_window_aidl.h>
+#include <cutils/native_handle.h>
+#include <vndk/hardware_buffer.h>
diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
index 876f6c8..73a7e95 100644
--- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
@@ -22,13 +22,14 @@
#[inline]
fn create_720p_buffer() -> HardwareBuffer {
- HardwareBuffer::new(
+ HardwareBuffer::new(&HardwareBufferDescription::new(
1280,
720,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.unwrap()
}
@@ -51,7 +52,7 @@
// underlying call to AHardwareBuffer_describe.
c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| {
b.iter(|| {
- buffer.width();
+ buffer.description().width();
})
});
}
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 326d1ce..a9264b3 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -29,6 +29,16 @@
using namespace android;
using namespace android::renderengine;
+// To run tests:
+/**
+ * mmm frameworks/native/libs/renderengine/benchmark;\
+ * adb push $OUT/data/benchmarktest/librenderengine_bench/librenderengine_bench
+ * /data/benchmarktest/librenderengine_bench/librenderengine_bench;\
+ * adb shell /data/benchmarktest/librenderengine_bench/librenderengine_bench
+ *
+ * (64-bit devices: out directory contains benchmarktest64 instead of benchmarktest)
+ */
+
///////////////////////////////////////////////////////////////////////////////
// Helpers for calling drawLayers
///////////////////////////////////////////////////////////////////////////////
@@ -173,29 +183,67 @@
}
}
+/**
+ * Return a buffer with the image in the provided path, relative to the executable directory
+ */
+static std::shared_ptr<ExternalTexture> createTexture(RenderEngine& re, const char* relPathImg) {
+ // Initially use cpu access so we can decode into it with AImageDecoder.
+ auto [width, height] = getDisplaySize();
+ auto srcBuffer =
+ allocateBuffer(re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source");
+ std::string fileName = base::GetExecutableDirectory().append(relPathImg);
+ renderenginebench::decode(fileName.c_str(), srcBuffer->getBuffer());
+ // Now copy into GPU-only buffer for more realistic timing.
+ srcBuffer = copyBuffer(re, srcBuffer, 0, "source");
+ return srcBuffer;
+}
+
///////////////////////////////////////////////////////////////////////////////
// Benchmarks
///////////////////////////////////////////////////////////////////////////////
+constexpr char kHomescreenPath[] = "/resources/homescreen.png";
+
+/**
+ * Draw a layer with texture and no additional shaders as a baseline to evaluate a shader's impact
+ * on performance
+ */
template <class... Args>
-void BM_blur(benchmark::State& benchState, Args&&... args) {
+void BM_homescreen(benchmark::State& benchState, Args&&... args) {
auto args_tuple = std::make_tuple(std::move(args)...);
auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
- static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)),
- static_cast<RenderEngine::BlurAlgorithm>(std::get<2>(args_tuple)));
+ static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
- // Initially use cpu access so we can decode into it with AImageDecoder.
auto [width, height] = getDisplaySize();
- auto srcBuffer =
- allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source");
- {
- std::string srcImage = base::GetExecutableDirectory();
- srcImage.append("/resources/homescreen.png");
- renderenginebench::decode(srcImage.c_str(), srcBuffer->getBuffer());
+ auto srcBuffer = createTexture(*re, kHomescreenPath);
- // Now copy into GPU-only buffer for more realistic timing.
- srcBuffer = copyBuffer(*re, srcBuffer, 0, "source");
- }
+ const FloatRect layerRect(0, 0, width, height);
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .boundaries = layerRect,
+ },
+ .source =
+ PixelSource{
+ .buffer =
+ Buffer{
+ .buffer = srcBuffer,
+ },
+ },
+ .alpha = half(1.0f),
+ };
+ auto layers = std::vector<LayerSettings>{layer};
+ benchDrawLayers(*re, layers, benchState, "homescreen");
+}
+
+template <class... Args>
+void BM_homescreen_blur(benchmark::State& benchState, Args&&... args) {
+ auto args_tuple = std::make_tuple(std::move(args)...);
+ auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
+ static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
+
+ auto [width, height] = getDisplaySize();
+ auto srcBuffer = createTexture(*re, kHomescreenPath);
const FloatRect layerRect(0, 0, width, height);
LayerSettings layer{
@@ -223,14 +271,55 @@
};
auto layers = std::vector<LayerSettings>{layer, blurLayer};
- benchDrawLayers(*re, layers, benchState, "blurred");
+ benchDrawLayers(*re, layers, benchState, "homescreen_blurred");
}
-BENCHMARK_CAPTURE(BM_blur, gaussian, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL,
- RenderEngine::BlurAlgorithm::GAUSSIAN);
+template <class... Args>
+void BM_homescreen_edgeExtension(benchmark::State& benchState, Args&&... args) {
+ auto args_tuple = std::make_tuple(std::move(args)...);
+ auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
+ static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
-BENCHMARK_CAPTURE(BM_blur, kawase, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL,
- RenderEngine::BlurAlgorithm::KAWASE);
+ auto [width, height] = getDisplaySize();
+ auto srcBuffer = createTexture(*re, kHomescreenPath);
-BENCHMARK_CAPTURE(BM_blur, kawase_dual_filter, RenderEngine::Threaded::YES,
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .boundaries = FloatRect(0, 0, width, height),
+ },
+ .source =
+ PixelSource{
+ .buffer =
+ Buffer{
+ .buffer = srcBuffer,
+ // Part of the screen is not covered by the texture but
+ // will be filled in by the shader
+ .textureTransform =
+ mat4(mat3(),
+ vec3(width * 0.3f, height * 0.3f, 0.0f)),
+ },
+ },
+ .alpha = half(1.0f),
+ .edgeExtensionEffect =
+ EdgeExtensionEffect(/* left */ true,
+ /* right */ false, /* top */ true, /* bottom */ false),
+ };
+ auto layers = std::vector<LayerSettings>{layer};
+ benchDrawLayers(*re, layers, benchState, "homescreen_edge_extension");
+}
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, gaussian, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::GAUSSIAN);
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, kawase, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE);
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, kawase_dual_filter, RenderEngine::Threaded::YES,
RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER);
+
+BENCHMARK_CAPTURE(BM_homescreen, SkiaGLThreaded, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL);
+
+BENCHMARK_CAPTURE(BM_homescreen_edgeExtension, SkiaGLThreaded, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL);
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
index 74daf47..a570ad0 100644
--- a/libs/renderengine/skia/AutoBackendTexture.h
+++ b/libs/renderengine/skia/AutoBackendTexture.h
@@ -16,9 +16,9 @@
#pragma once
-#include <GrDirectContext.h>
#include <SkImage.h>
#include <SkSurface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <sys/types.h>
#include <ui/GraphicTypes.h>
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index af24600..4ef7d5b 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -21,16 +21,15 @@
#include "SkiaGLRenderEngine.h"
-#include "compat/SkiaGpuContext.h"
-
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <GrContextOptions.h>
-#include <GrTypes.h>
#include <android-base/stringprintf.h>
#include <common/trace.h>
-#include <gl/GrGLInterface.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
+#include <log/log_main.h>
#include <sync/sync.h>
#include <ui/DebugUtils.h>
@@ -40,7 +39,7 @@
#include <numeric>
#include "GLExtensions.h"
-#include "log/log_main.h"
+#include "compat/SkiaGpuContext.h"
namespace android {
namespace renderengine {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index bd177e6..7651038 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -20,9 +20,10 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
-#include <GrDirectContext.h>
#include <SkSurface.h>
#include <android-base/thread_annotations.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
#include <sys/types.h>
@@ -32,7 +33,6 @@
#include "AutoBackendTexture.h"
#include "EGL/egl.h"
-#include "GrContextOptions.h"
#include "SkImageInfo.h"
#include "SkiaRenderEngine.h"
#include "android-base/macros.h"
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index d58f303..056e8fe 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -20,9 +20,6 @@
#include "SkiaRenderEngine.h"
-#include <GrBackendSemaphore.h>
-#include <GrContextOptions.h>
-#include <GrTypes.h>
#include <SkBlendMode.h>
#include <SkCanvas.h>
#include <SkColor.h>
@@ -56,6 +53,9 @@
#include <common/FlagManager.h>
#include <common/trace.h>
#include <gui/FenceMonitor.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <pthread.h>
#include <src/core/SkTraceEventCommon.h>
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 224a1ca..721dbce 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -18,11 +18,12 @@
#define SF_SKIARENDERENGINE_H_
#include <renderengine/RenderEngine.h>
-#include <sys/types.h>
-#include <GrBackendSemaphore.h>
-#include <SkSurface.h>
#include <android-base/thread_annotations.h>
+#include <include/core/SkImageInfo.h>
+#include <include/core/SkSurface.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
#include <sys/types.h>
@@ -32,8 +33,6 @@
#include <unordered_map>
#include "AutoBackendTexture.h"
-#include "GrContextOptions.h"
-#include "SkImageInfo.h"
#include "android-base/macros.h"
#include "compat/SkiaGpuContext.h"
#include "debug/SkiaCapture.h"
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index d89e818..677a2b6 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -24,12 +24,12 @@
#include "GaneshVkRenderEngine.h"
#include "compat/SkiaGpuContext.h"
-#include <GrBackendSemaphore.h>
-#include <GrContextOptions.h>
-#include <GrDirectContext.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
-#include <vk/GrVkTypes.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
#include <android-base/stringprintf.h>
#include <common/trace.h>
diff --git a/libs/renderengine/skia/compat/GaneshBackendTexture.cpp b/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
index 3fbc6ca..88282e7 100644
--- a/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
+++ b/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
@@ -21,12 +21,12 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <include/core/SkImage.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <include/gpu/ganesh/SkImageGanesh.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
#include <include/gpu/ganesh/vk/GrVkBackendSurface.h>
-#include <include/gpu/vk/GrVkTypes.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
#include "skia/ColorSpaces.h"
#include "skia/compat/SkiaBackendTexture.h"
diff --git a/libs/renderengine/skia/compat/GaneshBackendTexture.h b/libs/renderengine/skia/compat/GaneshBackendTexture.h
index 5cf8647..4337df1 100644
--- a/libs/renderengine/skia/compat/GaneshBackendTexture.h
+++ b/libs/renderengine/skia/compat/GaneshBackendTexture.h
@@ -21,7 +21,7 @@
#include <include/android/GrAHardwareBufferUtils.h>
#include <include/core/SkColorSpace.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <android-base/macros.h>
diff --git a/libs/renderengine/skia/compat/GaneshGpuContext.cpp b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
index b121fe8..931f843 100644
--- a/libs/renderengine/skia/compat/GaneshGpuContext.cpp
+++ b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
@@ -19,12 +19,12 @@
#include <include/core/SkImageInfo.h>
#include <include/core/SkSurface.h>
#include <include/core/SkTraceMemoryDump.h>
-#include <include/gpu/GrDirectContext.h>
-#include <include/gpu/GrTypes.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
-#include <include/gpu/gl/GrGLInterface.h>
#include <include/gpu/vk/VulkanBackendContext.h>
#include "../AutoBackendTexture.h"
diff --git a/libs/renderengine/skia/compat/SkiaBackendTexture.h b/libs/renderengine/skia/compat/SkiaBackendTexture.h
index 09877a5..fa12624 100644
--- a/libs/renderengine/skia/compat/SkiaBackendTexture.h
+++ b/libs/renderengine/skia/compat/SkiaBackendTexture.h
@@ -18,7 +18,7 @@
#include <include/android/GrAHardwareBufferUtils.h>
#include <include/core/SkColorSpace.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <android/hardware_buffer.h>
#include <ui/GraphicTypes.h>
diff --git a/libs/renderengine/skia/compat/SkiaGpuContext.h b/libs/renderengine/skia/compat/SkiaGpuContext.h
index 9fa6fb8..0bd8283 100644
--- a/libs/renderengine/skia/compat/SkiaGpuContext.h
+++ b/libs/renderengine/skia/compat/SkiaGpuContext.h
@@ -20,10 +20,10 @@
#define LOG_TAG "RenderEngine"
#include <include/core/SkSurface.h>
-#include <include/gpu/GrDirectContext.h>
-#include <include/gpu/gl/GrGLInterface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
#include <include/gpu/graphite/Context.h>
-#include "include/gpu/vk/VulkanBackendContext.h"
+#include <include/gpu/vk/VulkanBackendContext.h>
#include "SkiaBackendTexture.h"
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index d3b3a73..22c196e 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -90,6 +90,7 @@
],
shared_libs: [
+ "libbase",
"liblog",
"libutils",
"server_configurable_flags",
diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp
index ca13afc..4757bdb 100644
--- a/libs/vibrator/ExternalVibrationUtils.cpp
+++ b/libs/vibrator/ExternalVibrationUtils.cpp
@@ -17,6 +17,10 @@
#include <cstring>
+#include <android-base/parsedouble.h>
+#include <android-base/properties.h>
+#include <android-base/thread_annotations.h>
+
#include <android_os_vibrator.h>
#include <algorithm>
@@ -34,6 +38,21 @@
static constexpr float SCALE_GAMMA = 0.65f; // Same as VibrationEffect.SCALE_GAMMA
static constexpr float SCALE_LEVEL_GAIN = 1.4f; // Same as VibrationConfig.DEFAULT_SCALE_LEVEL_GAIN
+float getScaleLevelGain() {
+ static std::mutex gMutex;
+ static float gScaleLevelGain GUARDED_BY(gMutex) = 0;
+ std::lock_guard lock(gMutex);
+ if (gScaleLevelGain != 0) {
+ return gScaleLevelGain;
+ }
+ float scaleGain;
+ std::string value = ::android::base::GetProperty("vendor.vibrator.scale.level.gain", "");
+ if (value.empty() || !::android::base::ParseFloat(value, &scaleGain) || scaleGain <= 1) {
+ scaleGain = SCALE_LEVEL_GAIN;
+ }
+ return gScaleLevelGain = scaleGain;
+}
+
float getOldHapticScaleGamma(HapticLevel level) {
switch (level) {
case HapticLevel::VERY_LOW:
@@ -79,7 +98,8 @@
case HapticLevel::NONE:
return 1.0f;
default:
- float scaleFactor = powf(SCALE_LEVEL_GAIN, static_cast<int32_t>(level));
+ float scaleLevelGain = getScaleLevelGain();
+ float scaleFactor = powf(scaleLevelGain, static_cast<int32_t>(level));
if (scaleFactor <= 0) {
ALOGE("Invalid scale factor %.2f for level %d, using fallback to 1.0",
scaleFactor, static_cast<int32_t>(level));
diff --git a/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp
index 9369f80..e817263 100644
--- a/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp
+++ b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
#include <android_os_vibrator.h>
#include <flag_macros.h>
#include <gtest/gtest.h>
@@ -170,6 +171,12 @@
ExternalVibrationUtilsTest, TestScaleV2ToHapticLevel,
// Value of fix_audio_coupled_haptics_scaling is not important, should work with either
REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
+ // Skip test on devices with custom scale level gain configured.
+ if (!::android::base::GetProperty("vendor.vibrator.scale.level.gain", "").empty()) {
+ GTEST_SKIP() << "system property for scale level gain is set, skip tests based on level";
+ return;
+ }
+
float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 1, -1, 0.8f, -0.38f };
scaleBuffer(HapticLevel::VERY_HIGH);
EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
@@ -191,6 +198,12 @@
ExternalVibrationUtilsTest, TestScaleV2ToScaleFactorUndefinedUsesHapticLevel,
// Value of fix_audio_coupled_haptics_scaling is not important, should work with either
REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
+ // Skip test on devices with custom scale level gain configured.
+ if (!::android::base::GetProperty("vendor.vibrator.scale.level.gain", "").empty()) {
+ GTEST_SKIP() << "system property for scale level gain is set, skip tests based on level";
+ return;
+ }
+
constexpr float adaptiveScaleNone = 1.0f;
float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.8f, -0.38f};
scaleBuffer(HapticScale(HapticLevel::VERY_HIGH, -1.0f /* scaleFactor */, adaptiveScaleNone));
@@ -238,7 +251,7 @@
EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
// Haptic level scale up then adaptive scale down
- float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.13f };
+ float expectedVeryHigh[TEST_BUFFER_LENGTH] = {0.2f, -0.2f, 0.16f, -0.13f};
scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */);
EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
@@ -276,7 +289,7 @@
EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
// Haptic level scale up then adaptive scale down
- float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.07f };
+ float expectedVeryHigh[TEST_BUFFER_LENGTH] = {0.2f, -0.2f, 0.16f, -0.07f};
scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */);
EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
@@ -300,8 +313,8 @@
ExternalVibrationUtilsTest, TestAdaptiveScaleFactorUndefinedIgnoredScaleV2,
// Value of fix_audio_coupled_haptics_scaling is not important, should work with either
REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
- float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.8f, -0.38f};
- scaleBuffer(HapticLevel::VERY_HIGH, -1.0f /* adaptiveScaleFactor */);
+ float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.8, -0.38f};
+ scaleBuffer(HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, -1 /* adaptiveScaleFactor */));
EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
}
@@ -312,27 +325,30 @@
// Adaptive scale mutes vibration
float expectedMuted[TEST_BUFFER_LENGTH];
std::fill(std::begin(expectedMuted), std::end(expectedMuted), 0);
- scaleBuffer(HapticLevel::VERY_HIGH, 0.0f /* adaptiveScaleFactor */);
+ scaleBuffer(HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, 0 /* adaptiveScaleFactor */));
EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
// Haptic level scale up then adaptive scale down
- float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.15f, -0.07f };
- scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */);
+ float expectedVeryHigh[TEST_BUFFER_LENGTH] = {0.2f, -0.2f, 0.16f, -0.07f};
+ scaleBuffer(
+ HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, 0.2f /* adaptiveScaleFactor */));
EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
// Haptic level scale up then adaptive scale up
- float expectedHigh[TEST_BUFFER_LENGTH] = { 1.5f, -1.5f, 0.95f, -0.41f };
- scaleBuffer(HapticLevel::HIGH, 1.5f /* adaptiveScaleFactor */);
+ float expectedHigh[TEST_BUFFER_LENGTH] = {1.5f, -1.5f, 1.2f, -0.57f};
+ scaleBuffer(
+ HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, 1.5f /* adaptiveScaleFactor */));
EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
// Haptic level scale down then adaptive scale down
- float expectedLow[TEST_BUFFER_LENGTH] = { 0.42f, -0.42f, 0.21f, -0.08f };
- scaleBuffer(HapticLevel::LOW, 0.6f /* adaptiveScaleFactor */);
+ float expectedLow[TEST_BUFFER_LENGTH] = {0.3f, -0.3f, 0.15f, -0.06f};
+ scaleBuffer(
+ HapticScale(HapticLevel::LOW, 0.5f /* scaleFactor */, 0.6f /* adaptiveScaleFactor */));
EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
// Haptic level scale down then adaptive scale up
- float expectedVeryLow[TEST_BUFFER_LENGTH] = { 1.02f, -1.02f, 0.51f, -0.2f };
- scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */);
+ float expectedVeryLow[TEST_BUFFER_LENGTH] = {1.0f, -1.0f, 0.51f, -0.2f};
+ scaleBuffer(HapticScale(HapticLevel::LOW, 0.5f /* scaleFactor */, 2 /* adaptiveScaleFactor */));
EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
}
@@ -370,11 +386,13 @@
REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
// Scaled = { 0.2, -0.2, 0.15f, -0.07f };
float expectedClippedVeryHigh[TEST_BUFFER_LENGTH] = { 0.15f, -0.15f, 0.15f, -0.07f };
- scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 0.15f /* limit */);
+ scaleBuffer(HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, 0.2f /* adaptiveScaleFactor */),
+ 0.15f /* limit */);
EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
// Scaled = { 1.02f, -1.02f, 0.51f, -0.2f }
float expectedClippedVeryLow[TEST_BUFFER_LENGTH] = { 0.7f, -0.7f, 0.51f, -0.2f };
- scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */, 0.7f /* limit */);
+ scaleBuffer(HapticScale(HapticLevel::LOW, 0.5 /* scaleFactor */, 2 /* adaptiveScaleFactor */),
+ 0.7f /* limit */);
EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
}
diff --git a/opengl/OWNERS b/opengl/OWNERS
index 3d60a1d..645a578 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -2,5 +2,4 @@
cnorthrop@google.com
ianelliott@google.com
jessehall@google.com
-lpy@google.com
-vantablack@google.com
+tomnom@google.com
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 16de390..5159ffe 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -40,9 +40,6 @@
symbol_file: "libEGL.map.txt",
first_version: "9",
unversioned_until: "current",
- export_header_libs: [
- "libEGL_headers",
- ],
}
ndk_library {
@@ -50,9 +47,6 @@
symbol_file: "libGLESv1_CM.map.txt",
first_version: "9",
unversioned_until: "current",
- export_header_libs: [
- "libGLESv1_CM_headers",
- ],
}
ndk_library {
@@ -60,9 +54,6 @@
symbol_file: "libGLESv2.map.txt",
first_version: "9",
unversioned_until: "current",
- export_header_libs: [
- "libGLESv2_headers",
- ],
}
ndk_library {
@@ -70,9 +61,6 @@
symbol_file: "libGLESv3.map.txt",
first_version: "18",
unversioned_until: "current",
- export_header_libs: [
- "libGLESv3_headers",
- ],
}
cc_defaults {
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
index 00161e6..7628745 100644
--- a/services/gpuservice/gpuwork/GpuWork.cpp
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -44,7 +44,7 @@
#include "gpuwork/gpuWork.h"
-#define ONE_MS_IN_NS (10000000)
+#define MSEC_PER_NSEC (1000LU * 1000LU)
namespace android {
namespace gpuwork {
@@ -385,10 +385,11 @@
ALOGI("pullWorkAtoms: after random selection: uids.size() == %zu", uids.size());
auto now = std::chrono::steady_clock::now();
- long long duration =
- std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint)
- .count();
- if (duration > std::numeric_limits<int32_t>::max() || duration < 0) {
+ int32_t duration =
+ static_cast<int32_t>(
+ std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint)
+ .count());
+ if (duration < 0) {
// This is essentially impossible. If it does somehow happen, give up,
// but still clear the map.
clearMap();
@@ -404,13 +405,14 @@
}
const UidTrackingInfo& info = it->second;
- uint64_t total_active_duration_ms = info.total_active_duration_ns / ONE_MS_IN_NS;
- uint64_t total_inactive_duration_ms = info.total_inactive_duration_ns / ONE_MS_IN_NS;
+ int32_t total_active_duration_ms =
+ static_cast<int32_t>(info.total_active_duration_ns / MSEC_PER_NSEC);
+ int32_t total_inactive_duration_ms =
+ static_cast<int32_t>(info.total_inactive_duration_ns / MSEC_PER_NSEC);
// Skip this atom if any numbers are out of range. |duration| is
// already checked above.
- if (total_active_duration_ms > std::numeric_limits<int32_t>::max() ||
- total_inactive_duration_ms > std::numeric_limits<int32_t>::max()) {
+ if (total_active_duration_ms < 0 || total_inactive_duration_ms < 0) {
continue;
}
@@ -421,11 +423,11 @@
// gpu_id
bitcast_int32(gpuId),
// time_duration_seconds
- static_cast<int32_t>(duration),
+ duration,
// total_active_duration_millis
- static_cast<int32_t>(total_active_duration_ms),
+ total_active_duration_ms,
// total_inactive_duration_millis
- static_cast<int32_t>(total_inactive_duration_ms));
+ total_inactive_duration_ms);
}
}
clearMap();
diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
index e70da54..60cd2c7 100644
--- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
+++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
@@ -125,7 +125,7 @@
static constexpr size_t kNumGpusHardLimit = 32;
// The minimum GPU time needed to actually log stats for a UID.
- static constexpr uint64_t kMinGpuTimeNanoseconds = 30U * 1000000000U; // 30 seconds.
+ static constexpr uint64_t kMinGpuTimeNanoseconds = 10LLU * 1000000000LLU; // 10 seconds.
// The previous time point at which |mGpuWorkMap| was cleared.
std::chrono::steady_clock::time_point mPreviousMapClearTimePoint GUARDED_BY(mMutex);
diff --git a/services/inputflinger/InputFilter.cpp b/services/inputflinger/InputFilter.cpp
index 2d5803b..2ef94fb 100644
--- a/services/inputflinger/InputFilter.cpp
+++ b/services/inputflinger/InputFilter.cpp
@@ -146,6 +146,12 @@
void InputFilter::dump(std::string& dump) {
dump += "InputFilter:\n";
+ if (isFilterEnabled()) {
+ std::string result;
+ LOG_ALWAYS_FATAL_IF(!mInputFilterRust->dumpFilter(&result).isOk());
+ dump += result;
+ dump += "\n";
+ }
}
} // namespace android
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 41e5247..b155122 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -250,6 +250,10 @@
mCollector->dump(dump);
dump += '\n';
}
+ if (ENABLE_INPUT_FILTER_RUST) {
+ mInputFilter->dump(dump);
+ dump += '\n';
+ }
mDispatcher->dump(dump);
dump += '\n';
}
diff --git a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
index 994d1c4..31b7231 100644
--- a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
+++ b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
@@ -54,5 +54,7 @@
/** Notifies when configuration changes */
void notifyConfigurationChanged(in InputFilterConfiguration config);
+
+ String dumpFilter();
}
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
index dd46bbc..c8e7790 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
@@ -20,19 +20,14 @@
#include <sstream>
#include <android-base/stringprintf.h>
-#include <com_android_input_flags.h>
#include <input/PrintTools.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>
-namespace input_flags = com::android::input::flags;
-
namespace android {
namespace {
-static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
-
int32_t actionWithIndex(int32_t action, int32_t index) {
return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
}
@@ -48,12 +43,6 @@
return i;
}
-void addRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
- RawAbsoluteAxisInfo& evdevAxis) {
- deviceInfo.addMotionRange(androidAxis, SOURCE, evdevAxis.minValue, evdevAxis.maxValue,
- evdevAxis.flat, evdevAxis.fuzz, evdevAxis.resolution);
-}
-
} // namespace
CapturedTouchpadEventConverter::CapturedTouchpadEventConverter(
@@ -119,15 +108,8 @@
}
void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const {
- if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
- tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X,
- AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X);
- tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y,
- AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y);
- } else {
- tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
- tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
- }
+ tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
+ tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR);
@@ -153,23 +135,8 @@
int32_t evdevAxis) const {
std::optional<RawAbsoluteAxisInfo> info = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
if (info) {
- addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *info);
- }
-}
-
-void CapturedTouchpadEventConverter::tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo,
- int32_t androidAxis,
- int32_t androidRelativeAxis,
- int32_t evdevAxis) const {
- std::optional<RawAbsoluteAxisInfo> axisInfo = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
- if (axisInfo) {
- addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *axisInfo);
-
- // The largest movement we could possibly report on a relative axis is from the minimum to
- // the maximum (or vice versa) of the absolute axis.
- float range = axisInfo->maxValue - axisInfo->minValue;
- deviceInfo.addMotionRange(androidRelativeAxis, SOURCE, -range, range, axisInfo->flat,
- axisInfo->fuzz, axisInfo->resolution);
+ deviceInfo.addMotionRange(androidAxis, SOURCE, info->minValue, info->maxValue, info->flat,
+ info->fuzz, info->resolution);
}
}
@@ -196,7 +163,7 @@
std::list<NotifyArgs> out;
std::vector<PointerCoords> coords;
std::vector<PointerProperties> properties;
- std::map<size_t /*slotNumber*/, size_t /*coordsIndex*/> coordsIndexForSlotNumber;
+ std::map<size_t, size_t> coordsIndexForSlotNumber;
// For all the touches that were already down, send a MOVE event with their updated coordinates.
// A convention of the MotionEvent API is that pointer coordinates in UP events match the
@@ -208,19 +175,11 @@
// to stay perfectly still between frames, and if it does the worst that can happen is
// an extra MOVE event, so it's not worth the overhead of checking for changes.
coordsIndexForSlotNumber[slotNumber] = coords.size();
- coords.push_back(makePointerCoordsForSlot(slotNumber));
+ coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
properties.push_back({.id = pointerId, .toolType = ToolType::FINGER});
}
out.push_back(
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties));
- if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
- // For any further events we send from this sync, the pointers won't have moved relative
- // to the positions we just reported in this MOVE event, so zero out the relative axes.
- for (PointerCoords& pointer : coords) {
- pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
- pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
- }
- }
}
std::vector<size_t> upSlots, downSlots;
@@ -275,9 +234,6 @@
/*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));
freePointerIdForSlot(slotNumber);
- if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
- mPreviousCoordsForSlotNumber.erase(slotNumber);
- }
coords.erase(coords.begin() + indexToRemove);
properties.erase(properties.begin() + indexToRemove);
// Now that we've removed some coords and properties, we might have to update the slot
@@ -298,7 +254,7 @@
: actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex);
coordsIndexForSlotNumber[slotNumber] = coordsIndex;
- coords.push_back(makePointerCoordsForSlot(slotNumber));
+ coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
properties.push_back(
{.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER});
@@ -330,22 +286,12 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{});
}
-PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(size_t slotNumber) {
- const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(slotNumber);
+PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(
+ const MultiTouchMotionAccumulator::Slot& slot) const {
PointerCoords coords;
coords.clear();
coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX());
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY());
- if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
- if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber);
- it != mPreviousCoordsForSlotNumber.end()) {
- auto [oldX, oldY] = it->second;
- coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX);
- coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY);
- }
- mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY());
- }
-
coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor());
coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor());
coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor());
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
index d6c0708..9b6df7a 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
@@ -21,7 +21,6 @@
#include <map>
#include <set>
#include <string>
-#include <utility>
#include <vector>
#include <android/input.h>
@@ -50,14 +49,12 @@
private:
void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
int32_t evdevAxis) const;
- void tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, int32_t androidAxis,
- int32_t androidRelativeAxis, int32_t evdevAxis) const;
[[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
[[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
const std::vector<PointerCoords>& coords,
const std::vector<PointerProperties>& properties,
int32_t actionButton = 0, int32_t flags = 0);
- PointerCoords makePointerCoordsForSlot(size_t slotNumber);
+ PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const;
int32_t allocatePointerIdToSlot(size_t slotNumber);
void freePointerIdForSlot(size_t slotNumber);
@@ -79,7 +76,8 @@
std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse;
std::map<size_t, int32_t> mPointerIdForSlotNumber;
- std::map<size_t, std::pair<float, float>> mPreviousCoordsForSlotNumber;
+
+ static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index dbc2872..b17e79a 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -425,7 +425,7 @@
std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent);
if (state) {
if (mTouchpadHardwareStateNotificationsEnabled) {
- getPolicy()->notifyTouchpadHardwareState(*state, rawEvent.deviceId);
+ getPolicy()->notifyTouchpadHardwareState(*state, getDeviceId());
}
updatePalmDetectionMetrics();
return sendHardwareState(rawEvent.when, rawEvent.readTime, *state);
diff --git a/services/inputflinger/rust/bounce_keys_filter.rs b/services/inputflinger/rust/bounce_keys_filter.rs
index dc4f1df..e05e8e5 100644
--- a/services/inputflinger/rust/bounce_keys_filter.rs
+++ b/services/inputflinger/rust/bounce_keys_filter.rs
@@ -65,7 +65,10 @@
impl Filter for BounceKeysFilter {
fn notify_key(&mut self, event: &KeyEvent) {
- if !(self.supported_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) {
+ // Check if it is a supported device and event source contains Source::KEYBOARD
+ if !(self.supported_devices.contains(&event.deviceId)
+ && event.source.0 & Source::KEYBOARD.0 != 0)
+ {
self.next.notify_key(event);
return;
}
@@ -130,6 +133,15 @@
fn destroy(&mut self) {
self.next.destroy();
}
+
+ fn dump(&mut self, dump_str: String) -> String {
+ let mut result = "Bounce Keys filter: \n".to_string();
+ result += &format!("\tthreshold = {:?}ns\n", self.bounce_key_threshold_ns);
+ result += &format!("\tkey_event_map = {:?}\n", self.key_event_map);
+ result += &format!("\tblocked_events = {:?}\n", self.blocked_events);
+ result += &format!("\tsupported_devices = {:?}\n", self.supported_devices);
+ self.next.dump(dump_str + &result)
+ }
}
#[cfg(test)]
@@ -191,6 +203,41 @@
}
#[test]
+ fn test_is_notify_key_for_tv_remote() {
+ let mut next = TestFilter::new();
+ let mut filter = setup_filter_with_external_device(
+ Box::new(next.clone()),
+ 1, /* device_id */
+ 100, /* threshold */
+ KeyboardType::NonAlphabetic,
+ );
+
+ let source = Source(Source::KEYBOARD.0 | Source::DPAD.0);
+ let event = KeyEvent { action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ let event = KeyEvent { action: KeyEventAction::UP, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ next.clear();
+ let event = KeyEvent { action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert!(next.last_event().is_none());
+
+ let event =
+ KeyEvent { eventTime: 100, action: KeyEventAction::UP, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert!(next.last_event().is_none());
+
+ let event =
+ KeyEvent { eventTime: 200, action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+ }
+
+ #[test]
fn test_is_notify_key_blocks_for_internal_keyboard() {
let mut next = TestFilter::new();
let mut filter = setup_filter_with_internal_device(
diff --git a/services/inputflinger/rust/input_filter.rs b/services/inputflinger/rust/input_filter.rs
index f166723..e221244 100644
--- a/services/inputflinger/rust/input_filter.rs
+++ b/services/inputflinger/rust/input_filter.rs
@@ -43,6 +43,7 @@
fn notify_key(&mut self, event: &KeyEvent);
fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]);
fn destroy(&mut self);
+ fn dump(&mut self, dump_str: String) -> String;
}
struct InputFilterState {
@@ -122,18 +123,30 @@
self.input_filter_thread.clone(),
));
state.enabled = true;
- info!("Slow keys filter is installed");
+ info!(
+ "Slow keys filter is installed, threshold = {:?}ns",
+ config.slowKeysThresholdNs
+ );
}
if config.bounceKeysThresholdNs > 0 {
first_filter =
Box::new(BounceKeysFilter::new(first_filter, config.bounceKeysThresholdNs));
state.enabled = true;
- info!("Bounce keys filter is installed");
+ info!(
+ "Bounce keys filter is installed, threshold = {:?}ns",
+ config.bounceKeysThresholdNs
+ );
}
state.first_filter = first_filter;
}
Result::Ok(())
}
+
+ fn dumpFilter(&self) -> binder::Result<String> {
+ let first_filter = &mut self.state.lock().unwrap().first_filter;
+ let dump_str = first_filter.dump(String::new());
+ Result::Ok(dump_str)
+ }
}
struct BaseFilter {
@@ -161,6 +174,11 @@
fn destroy(&mut self) {
// do nothing
}
+
+ fn dump(&mut self, dump_str: String) -> String {
+ // do nothing
+ dump_str
+ }
}
/// This struct wraps around IInputFilterCallbacks restricting access to only
@@ -397,6 +415,10 @@
fn destroy(&mut self) {
self.inner().is_destroy_called = true;
}
+ fn dump(&mut self, dump_str: String) -> String {
+ // do nothing
+ dump_str
+ }
}
}
diff --git a/services/inputflinger/rust/slow_keys_filter.rs b/services/inputflinger/rust/slow_keys_filter.rs
index 3e242d8..8830aac 100644
--- a/services/inputflinger/rust/slow_keys_filter.rs
+++ b/services/inputflinger/rust/slow_keys_filter.rs
@@ -100,7 +100,7 @@
// acquire write lock
let mut slow_filter = self.write_inner();
if !(slow_filter.supported_devices.contains(&event.deviceId)
- && event.source == Source::KEYBOARD)
+ && event.source.0 & Source::KEYBOARD.0 != 0)
{
slow_filter.next.notify_key(event);
return;
@@ -186,6 +186,16 @@
slow_filter.input_filter_thread.unregister_thread_callback(Box::new(self.clone()));
slow_filter.next.destroy();
}
+
+ fn dump(&mut self, dump_str: String) -> String {
+ let mut slow_filter = self.write_inner();
+ let mut result = "Slow Keys filter: \n".to_string();
+ result += &format!("\tthreshold = {:?}ns\n", slow_filter.slow_key_threshold_ns);
+ result += &format!("\tongoing_down_events = {:?}\n", slow_filter.ongoing_down_events);
+ result += &format!("\tpending_down_events = {:?}\n", slow_filter.pending_down_events);
+ result += &format!("\tsupported_devices = {:?}\n", slow_filter.supported_devices);
+ slow_filter.next.dump(dump_str + &result)
+ }
}
impl ThreadCallback for SlowKeysFilter {
@@ -286,6 +296,63 @@
}
#[test]
+ fn test_notify_key_for_tv_remote_when_key_pressed_for_threshold_time() {
+ let test_callbacks = TestCallbacks::new();
+ let test_thread = get_thread(test_callbacks.clone());
+ let next = TestFilter::new();
+ let mut filter = setup_filter_with_external_device(
+ Box::new(next.clone()),
+ test_thread.clone(),
+ 1, /* device_id */
+ SLOW_KEYS_THRESHOLD_NS,
+ KeyboardType::NonAlphabetic,
+ );
+ let down_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
+ let source = Source(Source::KEYBOARD.0 | Source::DPAD.0);
+ filter.notify_key(&KeyEvent {
+ action: KeyEventAction::DOWN,
+ downTime: down_time,
+ eventTime: down_time,
+ source,
+ ..BASE_KEY_EVENT
+ });
+ assert!(next.last_event().is_none());
+
+ std::thread::sleep(Duration::from_nanos(2 * SLOW_KEYS_THRESHOLD_NS as u64));
+ assert_eq!(
+ next.last_event().unwrap(),
+ KeyEvent {
+ action: KeyEventAction::DOWN,
+ downTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ eventTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ source,
+ policyFlags: POLICY_FLAG_DISABLE_KEY_REPEAT,
+ ..BASE_KEY_EVENT
+ }
+ );
+
+ let up_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
+ filter.notify_key(&KeyEvent {
+ action: KeyEventAction::UP,
+ downTime: down_time,
+ eventTime: up_time,
+ source,
+ ..BASE_KEY_EVENT
+ });
+
+ assert_eq!(
+ next.last_event().unwrap(),
+ KeyEvent {
+ action: KeyEventAction::UP,
+ downTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ eventTime: up_time,
+ source,
+ ..BASE_KEY_EVENT
+ }
+ );
+ }
+
+ #[test]
fn test_notify_key_for_internal_alphabetic_keyboard_when_key_pressed_for_threshold_time() {
let test_callbacks = TestCallbacks::new();
let test_thread = get_thread(test_callbacks.clone());
diff --git a/services/inputflinger/rust/sticky_keys_filter.rs b/services/inputflinger/rust/sticky_keys_filter.rs
index dfcea79..161a5fc 100644
--- a/services/inputflinger/rust/sticky_keys_filter.rs
+++ b/services/inputflinger/rust/sticky_keys_filter.rs
@@ -134,6 +134,14 @@
fn destroy(&mut self) {
self.next.destroy();
}
+
+ fn dump(&mut self, dump_str: String) -> String {
+ let mut result = "Sticky Keys filter: \n".to_string();
+ result += &format!("\tmodifier_state = {:?}\n", self.modifier_state);
+ result += &format!("\tlocked_modifier_state = {:?}\n", self.locked_modifier_state);
+ result += &format!("\tcontributing_devices = {:?}\n", self.contributing_devices);
+ self.next.dump(dump_str + &result)
+ }
}
fn is_modifier_key(keycode: i32) -> bool {
diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
index d39ad3f..f20c43c 100644
--- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
+++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
@@ -20,7 +20,6 @@
#include <memory>
#include <EventHub.h>
-#include <com_android_input_flags.h>
#include <gtest/gtest.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
@@ -33,8 +32,6 @@
#include "TestEventMatchers.h"
#include "TestInputListener.h"
-namespace input_flags = com::android::input::flags;
-
namespace android {
using testing::AllOf;
@@ -50,8 +47,6 @@
mReader(mFakeEventHub, mFakePolicy, mFakeListener),
mDevice(newDevice()),
mDeviceContext(*mDevice, EVENTHUB_ID) {
- input_flags::include_relative_axis_values_for_captured_touchpads(true);
-
const size_t slotCount = 8;
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0);
mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true);
@@ -131,7 +126,7 @@
TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populatedCorrectly) {
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, 0, 4000, 0, 0, 45);
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 2000, 0, 0, 40);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, 0, 2500, 0, 0, 40);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, 0, 1100, 0, 0, 35);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 1000, 0, 0, 30);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 900, 0, 0, 25);
@@ -155,8 +150,8 @@
const InputDeviceInfo::MotionRange* posY =
info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD);
ASSERT_NE(nullptr, posY);
- EXPECT_NEAR(-500, posY->min, EPSILON);
- EXPECT_NEAR(2000, posY->max, EPSILON);
+ EXPECT_NEAR(0, posY->min, EPSILON);
+ EXPECT_NEAR(2500, posY->max, EPSILON);
EXPECT_NEAR(40, posY->resolution, EPSILON);
const InputDeviceInfo::MotionRange* touchMajor =
@@ -187,22 +182,8 @@
EXPECT_NEAR(800, toolMinor->max, EPSILON);
EXPECT_NEAR(20, toolMinor->resolution, EPSILON);
- // ...except for the relative motion axes, derived from the corresponding absolute ones:
- const InputDeviceInfo::MotionRange* relX =
- info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD);
- ASSERT_NE(nullptr, relX);
- EXPECT_NEAR(-4000, relX->min, EPSILON);
- EXPECT_NEAR(4000, relX->max, EPSILON);
- EXPECT_NEAR(45, relX->resolution, EPSILON);
-
- const InputDeviceInfo::MotionRange* relY =
- info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD);
- ASSERT_NE(nullptr, relY);
- EXPECT_NEAR(-2500, relY->min, EPSILON);
- EXPECT_NEAR(2500, relY->max, EPSILON);
- EXPECT_NEAR(40, relY->resolution, EPSILON);
-
- // ...orientation and pressure, which get scaled:
+ // ...except orientation and pressure, which get scaled, and size, which is generated from other
+ // values.
const InputDeviceInfo::MotionRange* orientation =
info.getMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, AINPUT_SOURCE_TOUCHPAD);
ASSERT_NE(nullptr, orientation);
@@ -217,7 +198,6 @@
EXPECT_NEAR(1, pressure->max, EPSILON);
EXPECT_NEAR(0, pressure->resolution, EPSILON);
- // ... and size, which is generated from other values.
const InputDeviceInfo::MotionRange* size =
info.getMotionRange(AMOTION_EVENT_AXIS_SIZE, AINPUT_SOURCE_TOUCHPAD);
ASSERT_NE(nullptr, size);
@@ -239,9 +219,7 @@
// present, since it's generated from axes that aren't provided by this device).
EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHPAD));
EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD));
- EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD));
- EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD));
- EXPECT_EQ(4u, info.getMotionRanges().size());
+ EXPECT_EQ(2u, info.getMotionRanges().size());
}
TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) {
@@ -257,16 +235,14 @@
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithCoords(50, 100), WithRelativeMotion(0, 0),
- WithToolType(ToolType::FINGER)));
+ WithCoords(50, 100), WithToolType(ToolType::FINGER)));
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 99);
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(52, 99), WithRelativeMotion(2, -1),
- WithToolType(ToolType::FINGER)));
+ WithCoords(52, 99), WithToolType(ToolType::FINGER)));
processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
processAxis(conv, EV_KEY, BTN_TOUCH, 0);
@@ -279,9 +255,8 @@
VariantWith<NotifyMotionArgs>(
WithMotionAction(AMOTION_EVENT_ACTION_UP))));
EXPECT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithCoords(52, 99), WithRelativeMotion(0, 0), WithPointerCount(1u),
- WithToolType(ToolType::FINGER)))));
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(52, 99), WithPointerCount(1u),
+ WithToolType(ToolType::FINGER)))));
}
TEST_F(CapturedTouchpadEventConverterTest, OneFinger_touchDimensionsPassedThrough) {
@@ -532,13 +507,13 @@
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithCoords(51, 100), WithRelativeMotion(0, 0)));
+ WithCoords(51, 100)));
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(52, 100), WithRelativeMotion(1, 0)));
+ WithCoords(52, 100)));
}
TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) {
@@ -578,7 +553,7 @@
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(98, 148), WithRelativeMotion(-2, -2)));
+ WithCoords(98, 148)));
}
TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) {
@@ -685,8 +660,7 @@
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithCoords(50, 100), WithRelativeMotion(0, 0),
- WithToolType(ToolType::FINGER)));
+ WithCoords(50, 100), WithToolType(ToolType::FINGER)));
processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
@@ -704,16 +678,13 @@
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
WithPointerCount(1u), WithCoords(52, 99),
- WithRelativeMotion(2, -1),
WithToolType(ToolType::FINGER))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(
AMOTION_EVENT_ACTION_POINTER_DOWN |
1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
WithPointerCount(2u), WithPointerCoords(0, 52, 99),
- WithPointerRelativeMotion(0, 0, 0),
WithPointerCoords(1, 250, 200),
- WithPointerRelativeMotion(1, 0, 0),
WithPointerToolType(0, ToolType::FINGER),
WithPointerToolType(1, ToolType::FINGER)))));
@@ -729,17 +700,14 @@
std::list<NotifyArgs> args = processSync(conv);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithPointerRelativeMotion(1, 5, 2))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerRelativeMotion(1, 0, 0)))));
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT))));
EXPECT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(
AllOf(WithPointerCount(2u), WithPointerCoords(0, 52, 99),
- WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 255, 202),
+ WithPointerCoords(1, 255, 202),
WithPointerToolType(1, ToolType::FINGER),
WithPointerToolType(0, ToolType::FINGER)))));
@@ -755,69 +723,9 @@
WithMotionAction(AMOTION_EVENT_ACTION_UP))));
EXPECT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithPointerCount(1u), WithCoords(255, 202),
- WithPointerRelativeMotion(1, 0, 0),
WithToolType(ToolType::FINGER)))));
}
-TEST_F(CapturedTouchpadEventConverterTest, RelativeMotionAxesClearedForNewFingerInSlot) {
- CapturedTouchpadEventConverter conv = createConverter();
- // Put down one finger.
- processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
- processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
- processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
- processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
-
- processAxis(conv, EV_KEY, BTN_TOUCH, 1);
- processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
-
- EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithCoords(50, 100), WithRelativeMotion(0, 0)));
-
- // Move it in negative X and Y directions.
- processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 47);
- processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 97);
-
- EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(47, 97),
- WithRelativeMotion(-3, -3)));
-
- // Lift it.
- processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
- processAxis(conv, EV_KEY, BTN_TOUCH, 0);
- processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
-
- std::list<NotifyArgs> args = processSync(conv);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_UP))));
- EXPECT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(47, 97),
- WithRelativeMotion(0, 0),
- WithPointerCount(1u)))));
-
- // Put down another finger using the same slot. Relative axis values should be cleared.
- processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
- processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 60);
- processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 60);
-
- processAxis(conv, EV_KEY, BTN_TOUCH, 1);
- processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
-
- EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithCoords(60, 60), WithRelativeMotion(0, 0)));
-
- processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 64);
- processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 58);
-
- EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(64, 58), WithRelativeMotion(4, -2)));
-}
-
// Pointer IDs max out at 31, and so must be reused once a touch is lifted to avoid running out.
TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) {
CapturedTouchpadEventConverter conv = createConverter();
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
index d77d539..e1f844c 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -32,19 +32,23 @@
} // namespace
void FakeInputReaderPolicy::assertInputDevicesChanged() {
- waitForInputDevices([](bool devicesChanged) {
- if (!devicesChanged) {
- FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
- }
- });
+ waitForInputDevices(
+ [](bool devicesChanged) {
+ if (!devicesChanged) {
+ FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
+ }
+ },
+ ADD_INPUT_DEVICE_TIMEOUT);
}
void FakeInputReaderPolicy::assertInputDevicesNotChanged() {
- waitForInputDevices([](bool devicesChanged) {
- if (devicesChanged) {
- FAIL() << "Expected notifyInputDevicesChanged() to not be called.";
- }
- });
+ waitForInputDevices(
+ [](bool devicesChanged) {
+ if (devicesChanged) {
+ FAIL() << "Expected notifyInputDevicesChanged() to not be called.";
+ }
+ },
+ INPUT_DEVICES_DIDNT_CHANGE_TIMEOUT);
}
void FakeInputReaderPolicy::assertStylusGestureNotified(int32_t deviceId) {
@@ -261,13 +265,13 @@
return "";
}
-void FakeInputReaderPolicy::waitForInputDevices(std::function<void(bool)> processDevicesChanged) {
+void FakeInputReaderPolicy::waitForInputDevices(std::function<void(bool)> processDevicesChanged,
+ std::chrono::milliseconds timeout) {
std::unique_lock<std::mutex> lock(mLock);
base::ScopedLockAssertion assumeLocked(mLock);
const bool devicesChanged =
- mDevicesChangedCondition.wait_for(lock,
- ADD_INPUT_DEVICE_TIMEOUT * HW_TIMEOUT_MULTIPLIER,
+ mDevicesChangedCondition.wait_for(lock, timeout * HW_TIMEOUT_MULTIPLIER,
[this]() REQUIRES(mLock) {
return mInputDevicesChanged;
});
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h
index e5ba620..61bb9fc 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.h
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.h
@@ -88,7 +88,8 @@
std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override;
std::string getDeviceAlias(const InputDeviceIdentifier&) override;
- void waitForInputDevices(std::function<void(bool)> processDevicesChanged);
+ void waitForInputDevices(std::function<void(bool)> processDevicesChanged,
+ std::chrono::milliseconds timeout);
void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override;
mutable std::mutex mLock;
diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h
index 082bbb8..d2337dd 100644
--- a/services/inputflinger/tests/TestConstants.h
+++ b/services/inputflinger/tests/TestConstants.h
@@ -25,7 +25,10 @@
using std::chrono_literals::operator""ms;
// Timeout for waiting for an input device to be added and processed
-static constexpr std::chrono::duration ADD_INPUT_DEVICE_TIMEOUT = 500ms;
+static constexpr std::chrono::duration ADD_INPUT_DEVICE_TIMEOUT = 5000ms;
+
+// Timeout for asserting that an input device change did not occur
+static constexpr std::chrono::duration INPUT_DEVICES_DIDNT_CHANGE_TIMEOUT = 100ms;
// Timeout for waiting for an expected event
static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index f3be041..cfedc6e 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -654,15 +654,6 @@
return argX == x && argY == y;
}
-MATCHER_P3(WithPointerRelativeMotion, pointer, x, y,
- "InputEvent with specified relative motion for pointer") {
- const auto argX = arg.pointerCoords[pointer].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
- const auto argY = arg.pointerCoords[pointer].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
- *result_listener << "expected pointer " << pointer << " to have relative motion (" << x << ", "
- << y << "), but got (" << argX << ", " << argY << ")";
- return argX == x && argY == y;
-}
-
MATCHER_P3(WithGestureOffset, dx, dy, epsilon,
"InputEvent with specified touchpad gesture offset") {
const auto argGestureX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3895ffe..57b473b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1583,7 +1583,11 @@
// Only 4 modes supported for a SensorEventConnection ... NORMAL, DATA_INJECTION,
// REPLAY_DATA_INJECTION and HAL_BYPASS_REPLAY_DATA_INJECTION
if (requestedMode != NORMAL && !isInjectionMode(requestedMode)) {
- return nullptr;
+ ALOGE(
+ "Failed to create sensor event connection: invalid request mode. "
+ "requestMode: %d",
+ requestedMode);
+ return nullptr;
}
resetTargetSdkVersionCache(opPackageName);
@@ -1591,8 +1595,19 @@
// To create a client in DATA_INJECTION mode to inject data, SensorService should already be
// operating in DI mode.
if (requestedMode == DATA_INJECTION) {
- if (mCurrentOperatingMode != DATA_INJECTION) return nullptr;
- if (!isAllowListedPackage(packageName)) return nullptr;
+ if (mCurrentOperatingMode != DATA_INJECTION) {
+ ALOGE(
+ "Failed to create sensor event connection: sensor service not in "
+ "DI mode when creating a client in DATA_INJECTION mode");
+ return nullptr;
+ }
+ if (!isAllowListedPackage(packageName)) {
+ ALOGE(
+ "Failed to create sensor event connection: package %s not in "
+ "allowed list for DATA_INJECTION mode",
+ packageName.c_str());
+ return nullptr;
+ }
}
uid_t uid = IPCThreadState::self()->getCallingUid();
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 20ae74a..66237b9 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -60,6 +60,7 @@
using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities;
using AidlHdrConversionCapability =
aidl::android::hardware::graphics::common::HdrConversionCapability;
+using AidlHdcpLevels = aidl::android::hardware::drm::HdcpLevels;
using AidlHdrConversionStrategy = aidl::android::hardware::graphics::common::HdrConversionStrategy;
using AidlOverlayProperties = aidl::android::hardware::graphics::composer3::OverlayProperties;
using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata;
@@ -223,6 +224,12 @@
return ::ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus onHdcpLevelsChanged(int64_t in_display,
+ const AidlHdcpLevels& levels) override {
+ mCallback.onComposerHalHdcpLevelsChanged(translate<Display>(in_display), levels);
+ return ::ndk::ScopedAStatus::ok();
+ }
+
private:
HWC2::ComposerCallback& mCallback;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index c2dc943..d426bca 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -67,6 +67,7 @@
namespace hal = android::hardware::graphics::composer::hal;
+using aidl::android::hardware::drm::HdcpLevels;
using aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
@@ -85,6 +86,7 @@
virtual void onComposerHalSeamlessPossible(hal::HWDisplayId) = 0;
virtual void onComposerHalVsyncIdle(hal::HWDisplayId) = 0;
virtual void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) = 0;
+ virtual void onComposerHalHdcpLevelsChanged(hal::HWDisplayId, const HdcpLevels& levels) = 0;
protected:
~ComposerCallback() = default;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 2a0ee5a..3736abc 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -697,6 +697,23 @@
jd.jankType = mJankType;
jd.frameIntervalNs =
(mRenderRate ? *mRenderRate : mDisplayFrameRenderRate).getPeriodNsecs();
+
+ if (mPredictionState == PredictionState::Valid) {
+ jd.scheduledAppFrameTimeNs = mPredictions.endTime - mPredictions.startTime;
+
+ // Using expected start, rather than actual, to measure the entire frame time. That is
+ // if the application starts the frame later than scheduled, include that delay in the
+ // frame time, as it usually means main thread being busy with non-rendering work.
+ if (mPresentState == PresentState::Dropped) {
+ jd.actualAppFrameTimeNs = mDropTime - mPredictions.startTime;
+ } else {
+ jd.actualAppFrameTimeNs = mActuals.endTime - mPredictions.startTime;
+ }
+ } else {
+ jd.scheduledAppFrameTimeNs = 0;
+ jd.actualAppFrameTimeNs = 0;
+ }
+
JankTracker::onJankData(mLayerId, jd);
}
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3c8af19..c8bb068 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -60,9 +60,7 @@
#include <utils/StopWatch.h>
#include <algorithm>
-#include <mutex>
#include <optional>
-#include <sstream>
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
@@ -72,7 +70,6 @@
#include "FrontEnd/LayerHandle.h"
#include "Layer.h"
#include "LayerProtoHelper.h"
-#include "MutexUtils.h"
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
#include "TransactionCallbackInvoker.h"
@@ -89,18 +86,6 @@
const ui::Transform kIdentityTransform;
-ui::LogicalDisplayId toLogicalDisplayId(const ui::LayerStack& layerStack) {
- return ui::LogicalDisplayId{static_cast<int32_t>(layerStack.id)};
-}
-
-bool assignTransform(ui::Transform* dst, ui::Transform& from) {
- if (*dst == from) {
- return false;
- }
- *dst = from;
- return true;
-}
-
TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
@@ -149,24 +134,11 @@
: sequence(args.sequence),
mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)),
mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
- mClientRef(args.client),
mWindowType(static_cast<WindowInfo::Type>(
- args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))),
- mLayerCreationFlags(args.flags),
- mLegacyLayerFE(args.flinger->getFactory().createLayerFE(mName, this)) {
+ args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))) {
ALOGV("Creating Layer %s", getDebugName());
- uint32_t layerFlags = 0;
- if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
- if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
- if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
- if (args.flags & ISurfaceComposerClient::eSkipScreenshot)
- layerFlags |= layer_state_t::eLayerSkipScreenshot;
- mDrawingState.flags = layerFlags;
mDrawingState.crop.makeInvalid();
- mDrawingState.z = 0;
- mDrawingState.color.a = 1.0f;
- mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK;
mDrawingState.sequence = 0;
mDrawingState.transform.set(0, 0);
mDrawingState.frameNumber = 0;
@@ -179,33 +151,9 @@
mDrawingState.acquireFence = sp<Fence>::make(-1);
mDrawingState.acquireFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
mDrawingState.dataspace = ui::Dataspace::V0_SRGB;
- mDrawingState.hdrMetadata.validTypes = 0;
- mDrawingState.surfaceDamageRegion = Region::INVALID_REGION;
- mDrawingState.cornerRadius = 0.0f;
- mDrawingState.backgroundBlurRadius = 0;
- mDrawingState.api = -1;
- mDrawingState.hasColorTransform = false;
- mDrawingState.colorSpaceAgnostic = false;
- mDrawingState.frameRateSelectionPriority = PRIORITY_UNSET;
mDrawingState.metadata = args.metadata;
- mDrawingState.shadowRadius = 0.f;
- mDrawingState.fixedTransformHint = ui::Transform::ROT_INVALID;
mDrawingState.frameTimelineInfo = {};
mDrawingState.postTime = -1;
- mDrawingState.destinationFrame.makeInvalid();
- mDrawingState.isTrustedOverlay = false;
- mDrawingState.dropInputMode = gui::DropInputMode::NONE;
- mDrawingState.dimmingEnabled = true;
- mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default;
- mDrawingState.frameRateSelectionStrategy = FrameRateSelectionStrategy::Propagate;
-
- if (args.flags & ISurfaceComposerClient::eNoColorFill) {
- // Set an invalid color so there is no color fill.
- mDrawingState.color.r = -1.0_hf;
- mDrawingState.color.g = -1.0_hf;
- mDrawingState.color.b = -1.0_hf;
- }
-
mFrameTracker.setDisplayRefreshPeriod(
args.flinger->mScheduler->getPacesetterVsyncPeriod().ns());
@@ -213,14 +161,9 @@
mOwnerPid = args.ownerPid;
mOwnerAppId = mOwnerUid % PER_USER_RANGE;
- mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
- mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;
-
- mSnapshot->sequence = sequence;
- mSnapshot->name = getDebugName();
- mSnapshot->premultipliedAlpha = mPremultipliedAlpha;
- mSnapshot->parentTransform = {};
+ mLayerFEs.emplace_back(frontend::LayerHierarchy::TraversalPath{static_cast<uint32_t>(sequence)},
+ args.flinger->getFactory().createLayerFE(mName, this));
}
void Layer::onFirstRef() {
@@ -253,35 +196,8 @@
}
// ---------------------------------------------------------------------------
-// callbacks
-// ---------------------------------------------------------------------------
-
-void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
- if (mDrawingState.zOrderRelativeOf == nullptr) {
- return;
- }
-
- sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote();
- if (strongRelative == nullptr) {
- setZOrderRelativeOf(nullptr);
- return;
- }
-
- if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
- strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
- mFlinger->setTransactionFlags(eTraversalNeeded);
- setZOrderRelativeOf(nullptr);
- }
-}
-
-// ---------------------------------------------------------------------------
// set-up
// ---------------------------------------------------------------------------
-
-bool Layer::getPremultipledAlpha() const {
- return mPremultipliedAlpha;
-}
-
sp<IBinder> Layer::getHandle() {
Mutex::Autolock _l(mLock);
if (mGetHandleCalled) {
@@ -297,46 +213,6 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-static Rect reduce(const Rect& win, const Region& exclude) {
- if (CC_LIKELY(exclude.isEmpty())) {
- return win;
- }
- if (exclude.isRect()) {
- return win.reduce(exclude.getBounds());
- }
- return Region(win).subtract(exclude).getBounds();
-}
-
-static FloatRect reduce(const FloatRect& win, const Region& exclude) {
- if (CC_LIKELY(exclude.isEmpty())) {
- return win;
- }
- // Convert through Rect (by rounding) for lack of FloatRegion
- return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
-}
-
-Rect Layer::getScreenBounds(bool reduceTransparentRegion) const {
- if (!reduceTransparentRegion) {
- return Rect{mScreenBounds};
- }
-
- FloatRect bounds = getBounds();
- ui::Transform t = getTransform();
- // Transform to screen space.
- bounds = t.transform(bounds);
- return Rect{bounds};
-}
-
-FloatRect Layer::getBounds() const {
- const State& s(getDrawingState());
- return getBounds(getActiveTransparentRegion(s));
-}
-
-FloatRect Layer::getBounds(const Region& activeTransparentRegion) const {
- // Subtract the transparent region and snap to the bounds.
- return reduce(mBounds, activeTransparentRegion);
-}
-
// No early returns.
void Layer::updateTrustedPresentationState(const DisplayDevice* display,
const frontend::LayerSnapshot* snapshot,
@@ -438,57 +314,6 @@
return true;
}
-void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform,
- float parentShadowRadius) {
- const State& s(getDrawingState());
-
- // Calculate effective layer transform
- mEffectiveTransform = parentTransform * getActiveTransform(s);
-
- if (CC_UNLIKELY(!isTransformValid())) {
- ALOGW("Stop computing bounds for %s because it has invalid transformation.",
- getDebugName());
- return;
- }
-
- // Transform parent bounds to layer space
- parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
-
- // Calculate source bounds
- mSourceBounds = computeSourceBounds(parentBounds);
-
- // Calculate bounds by croping diplay frame with layer crop and parent bounds
- FloatRect bounds = mSourceBounds;
- const Rect layerCrop = getCrop(s);
- if (!layerCrop.isEmpty()) {
- bounds = mSourceBounds.intersect(layerCrop.toFloatRect());
- }
- bounds = bounds.intersect(parentBounds);
-
- mBounds = bounds;
- mScreenBounds = mEffectiveTransform.transform(mBounds);
-
- // Use the layer's own shadow radius if set. Otherwise get the radius from
- // parent.
- if (s.shadowRadius > 0.f) {
- mEffectiveShadowRadius = s.shadowRadius;
- } else {
- mEffectiveShadowRadius = parentShadowRadius;
- }
-
- // Shadow radius is passed down to only one layer so if the layer can draw shadows,
- // don't pass it to its children.
- const float childShadowRadius = canDrawShadows() ? 0.f : mEffectiveShadowRadius;
-
- for (const sp<Layer>& child : mDrawingChildren) {
- child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius);
- }
-
- if (mPotentialCursor) {
- prepareCursorCompositionState();
- }
-}
-
Rect Layer::getCroppedBufferSize(const State& s) const {
Rect size = getBufferSize(s);
Rect crop = getCrop(s);
@@ -500,180 +325,6 @@
return size;
}
-void Layer::setupRoundedCornersCropCoordinates(Rect win,
- const FloatRect& roundedCornersCrop) const {
- // Translate win by the rounded corners rect coordinates, to have all values in
- // layer coordinate space.
- win.left -= roundedCornersCrop.left;
- win.right -= roundedCornersCrop.left;
- win.top -= roundedCornersCrop.top;
- win.bottom -= roundedCornersCrop.top;
-}
-
-void Layer::prepareBasicGeometryCompositionState() {
- const auto& drawingState{getDrawingState()};
- const auto alpha = static_cast<float>(getAlpha());
- const bool opaque = isOpaque(drawingState);
- const bool usesRoundedCorners = hasRoundedCorners();
-
- auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
- if (!opaque || alpha != 1.0f) {
- blendMode = mPremultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED
- : Hwc2::IComposerClient::BlendMode::COVERAGE;
- }
-
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
- snapshot->outputFilter = getOutputFilter();
- snapshot->isVisible = isVisible();
- snapshot->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
- snapshot->shadowSettings.length = mEffectiveShadowRadius;
-
- snapshot->contentDirty = contentDirty;
- contentDirty = false;
-
- snapshot->geomLayerBounds = mBounds;
- snapshot->geomLayerTransform = getTransform();
- snapshot->geomInverseLayerTransform = snapshot->geomLayerTransform.inverse();
- snapshot->transparentRegionHint = getActiveTransparentRegion(drawingState);
- snapshot->localTransform = getActiveTransform(drawingState);
- snapshot->localTransformInverse = snapshot->localTransform.inverse();
- snapshot->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
- snapshot->alpha = alpha;
- snapshot->backgroundBlurRadius = getBackgroundBlurRadius();
- snapshot->blurRegions = getBlurRegions();
-}
-
-void Layer::prepareGeometryCompositionState() {
- const auto& drawingState{getDrawingState()};
- auto* snapshot = editLayerSnapshot();
-
- // Please keep in sync with LayerSnapshotBuilder
- snapshot->geomBufferSize = getBufferSize(drawingState);
- snapshot->geomContentCrop = getBufferCrop();
- snapshot->geomCrop = getCrop(drawingState);
- snapshot->geomBufferTransform = getBufferTransform();
- snapshot->geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse();
- snapshot->geomUsesSourceCrop = usesSourceCrop();
- snapshot->isSecure = isSecure();
-
- snapshot->metadata.clear();
- const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
- for (const auto& [key, mandatory] : supportedMetadata) {
- const auto& genericLayerMetadataCompatibilityMap =
- mFlinger->getGenericLayerMetadataKeyMap();
- auto compatIter = genericLayerMetadataCompatibilityMap.find(key);
- if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) {
- continue;
- }
- const uint32_t id = compatIter->second;
-
- auto it = drawingState.metadata.mMap.find(id);
- if (it == std::end(drawingState.metadata.mMap)) {
- continue;
- }
-
- snapshot->metadata.emplace(key,
- compositionengine::GenericLayerMetadataEntry{mandatory,
- it->second});
- }
-}
-
-void Layer::preparePerFrameCompositionState() {
- const auto& drawingState{getDrawingState()};
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
-
- snapshot->forceClientComposition = false;
-
- snapshot->isColorspaceAgnostic = isColorSpaceAgnostic();
- snapshot->dataspace = getDataSpace();
- snapshot->colorTransform = getColorTransform();
- snapshot->colorTransformIsIdentity = !hasColorTransform();
- snapshot->surfaceDamage = surfaceDamageRegion;
- snapshot->hasProtectedContent = isProtected();
- snapshot->dimmingEnabled = isDimmingEnabled();
- snapshot->currentHdrSdrRatio = getCurrentHdrSdrRatio();
- snapshot->desiredHdrSdrRatio = getDesiredHdrSdrRatio();
- snapshot->cachingHint = getCachingHint();
-
- const bool usesRoundedCorners = hasRoundedCorners();
-
- snapshot->isOpaque = isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
-
- // Force client composition for special cases known only to the front-end.
- // Rounded corners no longer force client composition, since we may use a
- // hole punch so that the layer will appear to have rounded corners.
- if (drawShadows() || snapshot->stretchEffect.hasEffect()) {
- snapshot->forceClientComposition = true;
- }
- // If there are no visible region changes, we still need to update blur parameters.
- snapshot->blurRegions = getBlurRegions();
- snapshot->backgroundBlurRadius = getBackgroundBlurRadius();
-
- // Layer framerate is used in caching decisions.
- // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in
- // LayerFECompositionState where it would be visible to Flattener.
- snapshot->fps = mFlinger->getLayerFramerate(systemTime(), getSequence());
-
- if (hasBufferOrSidebandStream()) {
- preparePerFrameBufferCompositionState();
- } else {
- preparePerFrameEffectsCompositionState();
- }
-}
-
-void Layer::preparePerFrameBufferCompositionState() {
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
- // Sideband layers
- if (snapshot->sidebandStream.get() && !snapshot->sidebandStreamHasFrame) {
- snapshot->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::SIDEBAND;
- return;
- } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) {
- snapshot->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
- } else if ((mDrawingState.flags & layer_state_t::eLayerIsRefreshRateIndicator) != 0) {
- snapshot->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::REFRESH_RATE_INDICATOR;
- } else {
- // Normal buffer layers
- snapshot->hdrMetadata = mBufferInfo.mHdrMetadata;
- snapshot->compositionType = mPotentialCursor
- ? aidl::android::hardware::graphics::composer3::Composition::CURSOR
- : aidl::android::hardware::graphics::composer3::Composition::DEVICE;
- }
-
- snapshot->buffer = getBuffer();
- snapshot->acquireFence = mBufferInfo.mFence;
- snapshot->frameNumber = mBufferInfo.mFrameNumber;
- snapshot->sidebandStreamHasFrame = false;
-}
-
-void Layer::preparePerFrameEffectsCompositionState() {
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
- snapshot->color = getColor();
- snapshot->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
-}
-
-void Layer::prepareCursorCompositionState() {
- const State& drawingState{getDrawingState()};
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
-
- // Apply the layer's transform, followed by the display's global transform
- // Here we're guaranteed that the layer's transform preserves rects
- Rect win = getCroppedBufferSize(drawingState);
- // Subtract the transparent region and snap to the bounds
- Rect bounds = reduce(win, getActiveTransparentRegion(drawingState));
- Rect frame(getTransform().transform(bounds));
-
- snapshot->cursorFrame = frame;
-}
-
const char* Layer::getDebugName() const {
return mName.c_str();
}
@@ -701,45 +352,18 @@
}
// ----------------------------------------------------------------------------
-// local state
-// ----------------------------------------------------------------------------
-
-bool Layer::isSecure() const {
- const State& s(mDrawingState);
- if (s.flags & layer_state_t::eLayerSecure) {
- return true;
- }
-
- const auto p = mDrawingParent.promote();
- return (p != nullptr) ? p->isSecure() : false;
-}
-
-// ----------------------------------------------------------------------------
// transaction
// ----------------------------------------------------------------------------
uint32_t Layer::doTransaction(uint32_t flags) {
SFTRACE_CALL();
- // TODO: This is unfortunate.
- mDrawingStateModified = mDrawingState.modified;
- mDrawingState.modified = false;
-
const State& s(getDrawingState());
- if (updateGeometry()) {
- // invalidate and recompute the visible regions if needed
- flags |= Layer::eVisibleRegion;
- }
-
if (s.sequence != mLastCommittedTxSequence) {
// invalidate and recompute the visible regions if needed
mLastCommittedTxSequence = s.sequence;
flags |= eVisibleRegion;
- this->contentDirty = true;
-
- // we may use linear filtering, if the matrix scales us
- mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering();
}
if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) {
@@ -775,208 +399,11 @@
mTransactionFlags |= mask;
}
-bool Layer::setLayer(int32_t z) {
- if (mDrawingState.z == z && !usingRelativeZ(LayerVector::StateSet::Current)) return false;
- mDrawingState.sequence++;
- mDrawingState.z = z;
- mDrawingState.modified = true;
-
- mFlinger->mSomeChildrenChanged = true;
-
- // Discard all relative layering.
- if (mDrawingState.zOrderRelativeOf != nullptr) {
- sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote();
- if (strongRelative != nullptr) {
- strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
- }
- setZOrderRelativeOf(nullptr);
- }
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-void Layer::removeZOrderRelative(const wp<Layer>& relative) {
- mDrawingState.zOrderRelatives.remove(relative);
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-}
-
-void Layer::addZOrderRelative(const wp<Layer>& relative) {
- mDrawingState.zOrderRelatives.add(relative);
- mDrawingState.modified = true;
- mDrawingState.sequence++;
- setTransactionFlags(eTransactionNeeded);
-}
-
-void Layer::setZOrderRelativeOf(const wp<Layer>& relativeOf) {
- mDrawingState.zOrderRelativeOf = relativeOf;
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- mDrawingState.isRelativeOf = relativeOf != nullptr;
-
- setTransactionFlags(eTransactionNeeded);
-}
-
-bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
- sp<Layer> relative = LayerHandle::getLayer(relativeToHandle);
- if (relative == nullptr) {
- return false;
- }
-
- if (mDrawingState.z == relativeZ && usingRelativeZ(LayerVector::StateSet::Current) &&
- mDrawingState.zOrderRelativeOf == relative) {
- return false;
- }
-
- if (CC_UNLIKELY(relative->usingRelativeZ(LayerVector::StateSet::Drawing)) &&
- (relative->mDrawingState.zOrderRelativeOf == this)) {
- ALOGE("Detected relative layer loop between %s and %s",
- mName.c_str(), relative->mName.c_str());
- ALOGE("Ignoring new call to set relative layer");
- return false;
- }
-
- mFlinger->mSomeChildrenChanged = true;
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- mDrawingState.z = relativeZ;
-
- auto oldZOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
- if (oldZOrderRelativeOf != nullptr) {
- oldZOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this));
- }
- setZOrderRelativeOf(relative);
- relative->addZOrderRelative(wp<Layer>::fromExisting(this));
-
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
-bool Layer::setTrustedOverlay(bool isTrustedOverlay) {
- if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false;
- mDrawingState.isTrustedOverlay = isTrustedOverlay;
- mDrawingState.modified = true;
- mFlinger->mUpdateInputInfo = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::isTrustedOverlay() const {
- if (getDrawingState().isTrustedOverlay) {
- return true;
- }
- const auto& p = mDrawingParent.promote();
- return (p != nullptr) && p->isTrustedOverlay();
-}
-
-bool Layer::setAlpha(float alpha) {
- if (mDrawingState.color.a == alpha) return false;
- mDrawingState.sequence++;
- mDrawingState.color.a = alpha;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setCornerRadius(float cornerRadius) {
- if (mDrawingState.cornerRadius == cornerRadius) return false;
-
- mDrawingState.sequence++;
- mDrawingState.cornerRadius = cornerRadius;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) {
- if (mDrawingState.backgroundBlurRadius == backgroundBlurRadius) return false;
- // If we start or stop drawing blur then the layer's visibility state may change so increment
- // the magic sequence number.
- if (mDrawingState.backgroundBlurRadius == 0 || backgroundBlurRadius == 0) {
- mDrawingState.sequence++;
- }
- mDrawingState.backgroundBlurRadius = backgroundBlurRadius;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setTransparentRegionHint(const Region& transparent) {
- mDrawingState.sequence++;
- mDrawingState.transparentRegionHint = transparent;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
- // If we start or stop drawing blur then the layer's visibility state may change so increment
- // the magic sequence number.
- if (mDrawingState.blurRegions.size() == 0 || blurRegions.size() == 0) {
- mDrawingState.sequence++;
- }
- mDrawingState.blurRegions = blurRegions;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setFlags(uint32_t flags, uint32_t mask) {
- const uint32_t newFlags = (mDrawingState.flags & ~mask) | (flags & mask);
- if (mDrawingState.flags == newFlags) return false;
- mDrawingState.sequence++;
- mDrawingState.flags = newFlags;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
bool Layer::setCrop(const Rect& crop) {
if (mDrawingState.crop == crop) return false;
mDrawingState.sequence++;
mDrawingState.crop = crop;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setMetadata(const LayerMetadata& data) {
- if (!mDrawingState.metadata.merge(data, true /* eraseEmpty */)) return false;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setLayerStack(ui::LayerStack layerStack) {
- if (mDrawingState.layerStack == layerStack) return false;
- mDrawingState.sequence++;
- mDrawingState.layerStack = layerStack;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setColorSpaceAgnostic(const bool agnostic) {
- if (mDrawingState.colorSpaceAgnostic == agnostic) {
- return false;
- }
- mDrawingState.sequence++;
- mDrawingState.colorSpaceAgnostic = agnostic;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setDimmingEnabled(const bool dimmingEnabled) {
- if (mDrawingState.dimmingEnabled == dimmingEnabled) return false;
-
- mDrawingState.sequence++;
- mDrawingState.dimmingEnabled = dimmingEnabled;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -985,52 +412,6 @@
return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
};
-ui::LayerStack Layer::getLayerStack(LayerVector::StateSet state) const {
- bool useDrawing = state == LayerVector::StateSet::Drawing;
- const auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
- if (parent) {
- return parent->getLayerStack();
- }
- return getDrawingState().layerStack;
-}
-
-bool Layer::setShadowRadius(float shadowRadius) {
- if (mDrawingState.shadowRadius == shadowRadius) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.shadowRadius = shadowRadius;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint) {
- if (mDrawingState.fixedTransformHint == fixedTransformHint) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.fixedTransformHint = fixedTransformHint;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setStretchEffect(const StretchEffect& effect) {
- StretchEffect temp = effect;
- temp.sanitize();
- if (mDrawingState.stretchEffect == temp) {
- return false;
- }
- mDrawingState.sequence++;
- mDrawingState.stretchEffect = temp;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info,
nsecs_t postTime, gui::GameMode gameMode) {
mDrawingState.postTime = postTime;
@@ -1059,7 +440,6 @@
gui::GameMode gameMode) {
mDrawingState.frameTimelineInfo = info;
mDrawingState.postTime = postTime;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
if (const auto& bufferSurfaceFrameTX = mDrawingState.bufferSurfaceFrameTX;
@@ -1181,40 +561,6 @@
return getDrawingState().frameRateForLayerTree;
}
-bool Layer::isHiddenByPolicy() const {
- const State& s(mDrawingState);
- const auto& parent = mDrawingParent.promote();
- if (parent != nullptr && parent->isHiddenByPolicy()) {
- return true;
- }
- if (usingRelativeZ(LayerVector::StateSet::Drawing)) {
- auto zOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
- if (zOrderRelativeOf != nullptr) {
- if (zOrderRelativeOf->isHiddenByPolicy()) {
- return true;
- }
- }
- }
- if (CC_UNLIKELY(!isTransformValid())) {
- ALOGW("Hide layer %s because it has invalid transformation.", getDebugName());
- return true;
- }
- return s.flags & layer_state_t::eLayerHidden;
-}
-
-uint32_t Layer::getEffectiveUsage(uint32_t usage) const {
- // TODO: should we do something special if mSecure is set?
- if (mProtectedByApp) {
- // need a hardware-protected path to external video sink
- usage |= GraphicBuffer::USAGE_PROTECTED;
- }
- if (mPotentialCursor) {
- usage |= GraphicBuffer::USAGE_CURSOR;
- }
- usage |= GraphicBuffer::USAGE_HW_COMPOSER;
- return usage;
-}
-
// ----------------------------------------------------------------------------
// debugging
// ----------------------------------------------------------------------------
@@ -1293,248 +639,12 @@
mFrameTracker.getStats(outStats);
}
-void Layer::dumpOffscreenDebugInfo(std::string& result) const {
- std::string hasBuffer = hasBufferOrSidebandStream() ? " (contains buffer)" : "";
- StringAppendF(&result, "Layer %s%s pid:%d uid:%d%s\n", getName().c_str(), hasBuffer.c_str(),
- mOwnerPid, mOwnerUid, isHandleAlive() ? " handleAlive" : "");
-}
-
void Layer::onDisconnect() {
const int32_t layerId = getSequence();
mFlinger->mTimeStats->onDestroy(layerId);
mFlinger->mFrameTracer->onDestroy(layerId);
}
-void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
- for (const sp<Layer>& child : mDrawingChildren) {
- child->mDrawingParent = newParent;
- const float parentShadowRadius =
- newParent->canDrawShadows() ? 0.f : newParent->mEffectiveShadowRadius;
- child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
- parentShadowRadius);
- }
-}
-
-bool Layer::setColorTransform(const mat4& matrix) {
- static const mat4 identityMatrix = mat4();
-
- if (mDrawingState.colorTransform == matrix) {
- return false;
- }
- ++mDrawingState.sequence;
- mDrawingState.colorTransform = matrix;
- mDrawingState.hasColorTransform = matrix != identityMatrix;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-mat4 Layer::getColorTransform() const {
- mat4 colorTransform = mat4(getDrawingState().colorTransform);
- if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
- colorTransform = parent->getColorTransform() * colorTransform;
- }
- return colorTransform;
-}
-
-bool Layer::hasColorTransform() const {
- bool hasColorTransform = getDrawingState().hasColorTransform;
- if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
- hasColorTransform = hasColorTransform || parent->hasColorTransform();
- }
- return hasColorTransform;
-}
-
-bool Layer::isLegacyDataSpace() const {
- // return true when no higher bits are set
- return !(getDataSpace() &
- (ui::Dataspace::STANDARD_MASK | ui::Dataspace::TRANSFER_MASK |
- ui::Dataspace::RANGE_MASK));
-}
-
-void Layer::setParent(const sp<Layer>& layer) {
- mCurrentParent = layer;
-}
-
-int32_t Layer::getZ(LayerVector::StateSet) const {
- return mDrawingState.z;
-}
-
-bool Layer::usingRelativeZ(LayerVector::StateSet stateSet) const {
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const State& state = useDrawing ? mDrawingState : mDrawingState;
- return state.isRelativeOf;
-}
-
-__attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::makeTraversalList(
- LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers) {
- LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
- "makeTraversalList received invalid stateSet");
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
- const State& state = useDrawing ? mDrawingState : mDrawingState;
-
- if (state.zOrderRelatives.size() == 0) {
- *outSkipRelativeZUsers = true;
- return children;
- }
-
- LayerVector traverse(stateSet);
- for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
- sp<Layer> strongRelative = weakRelative.promote();
- if (strongRelative != nullptr) {
- traverse.add(strongRelative);
- }
- }
-
- for (const sp<Layer>& child : children) {
- if (child->usingRelativeZ(stateSet)) {
- continue;
- }
- traverse.add(child);
- }
-
- return traverse;
-}
-
-ui::Transform Layer::getTransform() const {
- return mEffectiveTransform;
-}
-
-bool Layer::isTransformValid() const {
- float transformDet = getTransform().det();
- return transformDet != 0 && !isinf(transformDet) && !isnan(transformDet);
-}
-
-half Layer::getAlpha() const {
- const auto& p = mDrawingParent.promote();
-
- half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
- return parentAlpha * getDrawingState().color.a;
-}
-
-ui::Transform::RotationFlags Layer::getFixedTransformHint() const {
- ui::Transform::RotationFlags fixedTransformHint = mDrawingState.fixedTransformHint;
- if (fixedTransformHint != ui::Transform::ROT_INVALID) {
- return fixedTransformHint;
- }
- const auto& p = mCurrentParent.promote();
- if (!p) return fixedTransformHint;
- return p->getFixedTransformHint();
-}
-
-half4 Layer::getColor() const {
- const half4 color(getDrawingState().color);
- return half4(color.r, color.g, color.b, getAlpha());
-}
-
-int32_t Layer::getBackgroundBlurRadius() const {
- if (getDrawingState().backgroundBlurRadius == 0) {
- return 0;
- }
-
- const auto& p = mDrawingParent.promote();
- half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
- return parentAlpha * getDrawingState().backgroundBlurRadius;
-}
-
-const std::vector<BlurRegion> Layer::getBlurRegions() const {
- auto regionsCopy(getDrawingState().blurRegions);
- float layerAlpha = getAlpha();
- for (auto& region : regionsCopy) {
- region.alpha = region.alpha * layerAlpha;
- }
- return regionsCopy;
-}
-
-RoundedCornerState Layer::getRoundedCornerState() const {
- // Today's DPUs cannot do rounded corners. If RenderEngine cannot render
- // protected content, remove rounded corners from protected content so it
- // can be rendered by the DPU.
- if (isProtected() && !mFlinger->getRenderEngine().supportsProtectedContent()) {
- return {};
- }
-
- // Get parent settings
- RoundedCornerState parentSettings;
- const auto& parent = mDrawingParent.promote();
- if (parent != nullptr) {
- parentSettings = parent->getRoundedCornerState();
- if (parentSettings.hasRoundedCorners()) {
- ui::Transform t = getActiveTransform(getDrawingState());
- t = t.inverse();
- parentSettings.cropRect = t.transform(parentSettings.cropRect);
- parentSettings.radius.x *= t.getScaleX();
- parentSettings.radius.y *= t.getScaleY();
- }
- }
-
- // Get layer settings
- Rect layerCropRect = getCroppedBufferSize(getDrawingState());
- const vec2 radius(getDrawingState().cornerRadius, getDrawingState().cornerRadius);
- RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
- const bool layerSettingsValid = layerSettings.hasRoundedCorners() && layerCropRect.isValid();
-
- if (layerSettingsValid && parentSettings.hasRoundedCorners()) {
- // If the parent and the layer have rounded corner settings, use the parent settings if the
- // parent crop is entirely inside the layer crop.
- // This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
- if (parentSettings.cropRect.left > layerCropRect.left &&
- parentSettings.cropRect.top > layerCropRect.top &&
- parentSettings.cropRect.right < layerCropRect.right &&
- parentSettings.cropRect.bottom < layerCropRect.bottom) {
- return parentSettings;
- } else {
- return layerSettings;
- }
- } else if (layerSettingsValid) {
- return layerSettings;
- } else if (parentSettings.hasRoundedCorners()) {
- return parentSettings;
- }
- return {};
-}
-
-bool Layer::findInHierarchy(const sp<Layer>& l) {
- if (l == this) {
- return true;
- }
- for (auto& child : mDrawingChildren) {
- if (child->findInHierarchy(l)) {
- return true;
- }
- }
- return false;
-}
-
-void Layer::setInputInfo(const WindowInfo& info) {
- mDrawingState.inputInfo = info;
- mDrawingState.touchableRegionCrop =
- LayerHandle::getLayer(info.touchableRegionCropHandle.promote());
- mDrawingState.modified = true;
- mFlinger->mUpdateInputInfo = true;
- setTransactionFlags(eTransactionNeeded);
-}
-
-perfetto::protos::LayerProto* Layer::writeToProto(perfetto::protos::LayersProto& layersProto,
- uint32_t traceFlags) {
- perfetto::protos::LayerProto* layerProto = layersProto.add_layers();
- writeToProtoDrawingState(layerProto);
- writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
-
- if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
- ui::LayerStack layerStack =
- (mSnapshot) ? mSnapshot->outputFilter.layerStack : ui::INVALID_LAYER_STACK;
- writeCompositionStateToProto(layerProto, layerStack);
- }
-
- for (const sp<Layer>& layer : mDrawingChildren) {
- layer->writeToProto(layersProto, traceFlags);
- }
-
- return layerProto;
-}
-
void Layer::writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto,
ui::LayerStack layerStack) {
ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread.
@@ -1550,352 +660,6 @@
}
}
-void Layer::writeToProtoDrawingState(perfetto::protos::LayerProto* layerInfo) {
- const ui::Transform transform = getTransform();
- auto buffer = getExternalTexture();
- if (buffer != nullptr) {
- LayerProtoHelper::writeToProto(*buffer,
- [&]() { return layerInfo->mutable_active_buffer(); });
- LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()),
- layerInfo->mutable_buffer_transform());
- }
- layerInfo->set_invalidate(contentDirty);
- layerInfo->set_is_protected(isProtected());
- layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
- layerInfo->set_queued_frames(getQueuedFrameCount());
- layerInfo->set_curr_frame(mCurrentFrameNumber);
- layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
- layerInfo->set_corner_radius(
- (getRoundedCornerState().radius.x + getRoundedCornerState().radius.y) / 2.0);
- layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
- layerInfo->set_is_trusted_overlay(isTrustedOverlay());
- LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform());
- LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
- [&]() { return layerInfo->mutable_position(); });
- LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
- LayerProtoHelper::writeToProto(surfaceDamageRegion,
- [&]() { return layerInfo->mutable_damage_region(); });
-
- if (hasColorTransform()) {
- LayerProtoHelper::writeToProto(getColorTransform(), layerInfo->mutable_color_transform());
- }
-
- LayerProtoHelper::writeToProto(mSourceBounds,
- [&]() { return layerInfo->mutable_source_bounds(); });
- LayerProtoHelper::writeToProto(mScreenBounds,
- [&]() { return layerInfo->mutable_screen_bounds(); });
- LayerProtoHelper::writeToProto(getRoundedCornerState().cropRect,
- [&]() { return layerInfo->mutable_corner_radius_crop(); });
- layerInfo->set_shadow_radius(mEffectiveShadowRadius);
-}
-
-void Layer::writeToProtoCommonState(perfetto::protos::LayerProto* layerInfo,
- LayerVector::StateSet stateSet, uint32_t traceFlags) {
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
- const State& state = useDrawing ? mDrawingState : mDrawingState;
-
- ui::Transform requestedTransform = state.transform;
-
- layerInfo->set_id(sequence);
- layerInfo->set_name(getName().c_str());
- layerInfo->set_type(getType());
-
- for (const auto& child : children) {
- layerInfo->add_children(child->sequence);
- }
-
- for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
- sp<Layer> strongRelative = weakRelative.promote();
- if (strongRelative != nullptr) {
- layerInfo->add_relatives(strongRelative->sequence);
- }
- }
-
- LayerProtoHelper::writeToProto(state.transparentRegionHint,
- [&]() { return layerInfo->mutable_transparent_region(); });
-
- layerInfo->set_layer_stack(getLayerStack().id);
- layerInfo->set_z(state.z);
-
- LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
- return layerInfo->mutable_requested_position();
- });
-
- LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); });
-
- layerInfo->set_is_opaque(isOpaque(state));
-
- layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
- LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
- LayerProtoHelper::writeToProto(state.color,
- [&]() { return layerInfo->mutable_requested_color(); });
- layerInfo->set_flags(state.flags);
-
- LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
- layerInfo->mutable_requested_transform());
-
- auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
- if (parent != nullptr) {
- layerInfo->set_parent(parent->sequence);
- }
-
- auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
- if (zOrderRelativeOf != nullptr) {
- layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
- }
-
- layerInfo->set_is_relative_of(state.isRelativeOf);
-
- layerInfo->set_owner_uid(mOwnerUid);
-
- if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
- WindowInfo info;
- if (useDrawing) {
- info = fillInputInfo(
- InputDisplayArgs{.transform = &kIdentityTransform, .isSecure = true});
- } else {
- info = state.inputInfo;
- }
-
- LayerProtoHelper::writeToProto(info, state.touchableRegionCrop,
- [&]() { return layerInfo->mutable_input_window_info(); });
- }
-
- if (traceFlags & LayerTracing::TRACE_EXTRA) {
- auto protoMap = layerInfo->mutable_metadata();
- for (const auto& entry : state.metadata.mMap) {
- (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
- }
- }
-
- LayerProtoHelper::writeToProto(state.destinationFrame,
- [&]() { return layerInfo->mutable_destination_frame(); });
-}
-
-// Applies the given transform to the region, while protecting against overflows caused by any
-// offsets. If applying the offset in the transform to any of the Rects in the region would result
-// in an overflow, they are not added to the output Region.
-static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r,
- const std::string& debugWindowName) {
- // Round the translation using the same rounding strategy used by ui::Transform.
- const auto tx = static_cast<int32_t>(t.tx() + 0.5);
- const auto ty = static_cast<int32_t>(t.ty() + 0.5);
-
- ui::Transform transformWithoutOffset = t;
- transformWithoutOffset.set(0.f, 0.f);
-
- const Region transformed = transformWithoutOffset.transform(r);
-
- // Apply the translation to each of the Rects in the region while discarding any that overflow.
- Region ret;
- for (const auto& rect : transformed) {
- Rect newRect;
- if (__builtin_add_overflow(rect.left, tx, &newRect.left) ||
- __builtin_add_overflow(rect.top, ty, &newRect.top) ||
- __builtin_add_overflow(rect.right, tx, &newRect.right) ||
- __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) {
- ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.",
- debugWindowName.c_str());
- continue;
- }
- ret.orSelf(newRect);
- }
- return ret;
-}
-
-void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
- auto [inputBounds, inputBoundsValid] = getInputBounds(/*fillParentBounds=*/false);
- if (!inputBoundsValid) {
- info.touchableRegion.clear();
- }
-
- info.frame = getInputBoundsInDisplaySpace(inputBounds, screenToDisplay);
-
- ui::Transform inputToLayer;
- inputToLayer.set(inputBounds.left, inputBounds.top);
- const ui::Transform layerToScreen = getInputTransform();
- const ui::Transform inputToDisplay = screenToDisplay * layerToScreen * inputToLayer;
-
- // InputDispatcher expects a display-to-input transform.
- info.transform = inputToDisplay.inverse();
-
- // The touchable region is specified in the input coordinate space. Change it to display space.
- info.touchableRegion =
- transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName);
-}
-
-void Layer::fillTouchOcclusionMode(WindowInfo& info) {
- sp<Layer> p = sp<Layer>::fromExisting(this);
- while (p != nullptr && !p->hasInputInfo()) {
- p = p->mDrawingParent.promote();
- }
- if (p != nullptr) {
- info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode;
- }
-}
-
-gui::DropInputMode Layer::getDropInputMode() const {
- gui::DropInputMode mode = mDrawingState.dropInputMode;
- if (mode == gui::DropInputMode::ALL) {
- return mode;
- }
- sp<Layer> parent = mDrawingParent.promote();
- if (parent) {
- gui::DropInputMode parentMode = parent->getDropInputMode();
- if (parentMode != gui::DropInputMode::NONE) {
- return parentMode;
- }
- }
- return mode;
-}
-
-void Layer::handleDropInputMode(gui::WindowInfo& info) const {
- if (mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
- return;
- }
-
- // Check if we need to drop input unconditionally
- gui::DropInputMode dropInputMode = getDropInputMode();
- if (dropInputMode == gui::DropInputMode::ALL) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
- ALOGV("Dropping input for %s as requested by policy.", getDebugName());
- return;
- }
-
- // Check if we need to check if the window is obscured by parent
- if (dropInputMode != gui::DropInputMode::OBSCURED) {
- return;
- }
-
- // Check if the parent has set an alpha on the layer
- sp<Layer> parent = mDrawingParent.promote();
- if (parent && parent->getAlpha() != 1.0_hf) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
- ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(),
- static_cast<float>(getAlpha()));
- }
-
- // Check if the parent has cropped the buffer
- Rect bufferSize = getCroppedBufferSize(getDrawingState());
- if (!bufferSize.isValid()) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED;
- return;
- }
-
- // Screenbounds are the layer bounds cropped by parents, transformed to screenspace.
- // To check if the layer has been cropped, we take the buffer bounds, apply the local
- // layer crop and apply the same set of transforms to move to screenspace. If the bounds
- // match then the layer has not been cropped by its parents.
- Rect bufferInScreenSpace(getTransform().transform(bufferSize));
- bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds};
-
- if (croppedByParent) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
- ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent",
- getDebugName());
- } else {
- // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop
- // input if the window is obscured. This check should be done in surfaceflinger but the
- // logic currently resides in inputflinger. So pass the if_obscured check to input to only
- // drop input events if the window is obscured.
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED;
- }
-}
-
-WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) {
- if (!hasInputInfo()) {
- mDrawingState.inputInfo.name = getName();
- mDrawingState.inputInfo.ownerUid = gui::Uid{mOwnerUid};
- mDrawingState.inputInfo.ownerPid = gui::Pid{mOwnerPid};
- mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NO_INPUT_CHANNEL;
- mDrawingState.inputInfo.displayId = toLogicalDisplayId(getLayerStack());
- }
-
- const ui::Transform& displayTransform =
- displayArgs.transform != nullptr ? *displayArgs.transform : kIdentityTransform;
-
- WindowInfo info = mDrawingState.inputInfo;
- info.id = sequence;
- info.displayId = toLogicalDisplayId(getLayerStack());
-
- fillInputFrameInfo(info, displayTransform);
-
- if (displayArgs.transform == nullptr) {
- // Do not let the window receive touches if it is not associated with a valid display
- // transform. We still allow the window to receive keys and prevent ANRs.
- info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE;
- }
-
- info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !isVisibleForInput());
-
- info.alpha = getAlpha();
- fillTouchOcclusionMode(info);
- handleDropInputMode(info);
-
- // If the window will be blacked out on a display because the display does not have the secure
- // flag and the layer has the secure flag set, then drop input.
- if (!displayArgs.isSecure && isSecure()) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
- }
-
- sp<Layer> cropLayer = mDrawingState.touchableRegionCrop.promote();
- if (info.replaceTouchableRegionWithCrop) {
- Rect inputBoundsInDisplaySpace;
- if (!cropLayer) {
- FloatRect inputBounds = getInputBounds(/*fillParentBounds=*/true).first;
- inputBoundsInDisplaySpace = getInputBoundsInDisplaySpace(inputBounds, displayTransform);
- } else {
- FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first;
- inputBoundsInDisplaySpace =
- cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform);
- }
- info.touchableRegion = Region(inputBoundsInDisplaySpace);
- } else if (cropLayer != nullptr) {
- FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first;
- Rect inputBoundsInDisplaySpace =
- cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform);
- info.touchableRegion = info.touchableRegion.intersect(inputBoundsInDisplaySpace);
- }
-
- // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
- // if it was set by WM for a known system overlay
- if (isTrustedOverlay()) {
- info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY;
- }
-
- Rect bufferSize = getBufferSize(getDrawingState());
- info.contentSize = Size(bufferSize.width(), bufferSize.height());
-
- return info;
-}
-
-Rect Layer::getInputBoundsInDisplaySpace(const FloatRect& inputBounds,
- const ui::Transform& screenToDisplay) {
- // InputDispatcher works in the display device's coordinate space. Here, we calculate the
- // frame and transform used for the layer, which determines the bounds and the coordinate space
- // within which the layer will receive input.
-
- // Coordinate space definitions:
- // - display: The display device's coordinate space. Correlates to pixels on the display.
- // - screen: The post-rotation coordinate space for the display, a.k.a. logical display space.
- // - layer: The coordinate space of this layer.
- // - input: The coordinate space in which this layer will receive input events. This could be
- // different than layer space if a surfaceInset is used, which changes the origin
- // of the input space.
-
- // Crop the input bounds to ensure it is within the parent's bounds.
- const FloatRect croppedInputBounds = mBounds.intersect(inputBounds);
- const ui::Transform layerToScreen = getInputTransform();
- const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
- return Rect{layerToDisplay.transform(croppedInputBounds)};
-}
-
-bool Layer::hasInputInfo() const {
- return mDrawingState.inputInfo.token != nullptr ||
- mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);
-}
-
compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
const DisplayDevice* display) const {
if (!display) return nullptr;
@@ -1930,24 +694,6 @@
return outputLayer ? outputLayer->getState().visibleRegion : Region();
}
-bool Layer::isInternalDisplayOverlay() const {
- const State& s(mDrawingState);
- if (s.flags & layer_state_t::eLayerSkipScreenshot) {
- return true;
- }
-
- sp<Layer> parent = mDrawingParent.promote();
- return parent && parent->isInternalDisplayOverlay();
-}
-
-bool Layer::setDropInputMode(gui::DropInputMode mode) {
- if (mDrawingState.dropInputMode == mode) {
- return false;
- }
- mDrawingState.dropInputMode = mode;
- return true;
-}
-
void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, uint64_t framenumber,
const sp<Fence>& releaseFence) {
@@ -2106,17 +852,9 @@
mDrawingState.callbackHandles = {};
}
-bool Layer::willPresentCurrentTransaction() const {
- // Returns true if the most recent Transaction applied to CurrentState will be presented.
- return (getSidebandStreamChanged() || getAutoRefresh() ||
- (mDrawingState.modified &&
- (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr)));
-}
-
bool Layer::setTransform(uint32_t transform) {
if (mDrawingState.bufferTransform == transform) return false;
mDrawingState.bufferTransform = transform;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2125,7 +863,6 @@
if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false;
mDrawingState.sequence++;
mDrawingState.transformToDisplayInverse = transformToDisplayInverse;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2136,100 +873,10 @@
mDrawingState.sequence++;
mDrawingState.bufferCrop = bufferCrop;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
-bool Layer::setDestinationFrame(const Rect& destinationFrame) {
- if (mDrawingState.destinationFrame == destinationFrame) return false;
-
- mDrawingState.sequence++;
- mDrawingState.destinationFrame = destinationFrame;
-
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-// Translate destination frame into scale and position. If a destination frame is not set, use the
-// provided scale and position
-bool Layer::updateGeometry() {
- if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) ||
- mDrawingState.destinationFrame.isEmpty()) {
- // If destination frame is not set, use the requested transform set via
- // Layer::setPosition and Layer::setMatrix.
- return assignTransform(&mDrawingState.transform, mRequestedTransform);
- }
-
- Rect destRect = mDrawingState.destinationFrame;
- int32_t destW = destRect.width();
- int32_t destH = destRect.height();
- if (destRect.left < 0) {
- destRect.left = 0;
- destRect.right = destW;
- }
- if (destRect.top < 0) {
- destRect.top = 0;
- destRect.bottom = destH;
- }
-
- if (!mDrawingState.buffer) {
- ui::Transform t;
- t.set(destRect.left, destRect.top);
- return assignTransform(&mDrawingState.transform, t);
- }
-
- uint32_t bufferWidth = mDrawingState.buffer->getWidth();
- uint32_t bufferHeight = mDrawingState.buffer->getHeight();
- // Undo any transformations on the buffer.
- if (mDrawingState.bufferTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- uint32_t invTransform = SurfaceFlinger::getActiveDisplayRotationFlags();
- if (mDrawingState.transformToDisplayInverse) {
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- }
-
- float sx = destW / static_cast<float>(bufferWidth);
- float sy = destH / static_cast<float>(bufferHeight);
- ui::Transform t;
- t.set(sx, 0, 0, sy);
- t.set(destRect.left, destRect.top);
- return assignTransform(&mDrawingState.transform, t);
-}
-
-bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
- if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy &&
- mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) {
- return false;
- }
-
- mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
-bool Layer::setPosition(float x, float y) {
- if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) {
- return false;
- }
-
- mRequestedTransform.set(x, y);
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
void Layer::releasePreviousBuffer() {
mReleasePreviousBuffer = true;
if (!mBufferInfo.mBuffer ||
@@ -2293,7 +940,6 @@
mDrawingState.isAutoTimestamp = isAutoTimestamp;
mDrawingState.latchedVsyncId = info.vsyncId;
mDrawingState.useVsyncIdForRefreshRateSelection = info.useForRefreshRateSelection;
- mDrawingState.modified = true;
if (!buffer) {
resetDrawingStateBufferInfo();
setTransactionFlags(eTransactionNeeded);
@@ -2441,7 +1087,6 @@
bool Layer::setDataspace(ui::Dataspace dataspace) {
if (mDrawingState.dataspace == dataspace) return false;
mDrawingState.dataspace = dataspace;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2452,7 +1097,6 @@
return false;
mDrawingState.currentHdrSdrRatio = currentBufferRatio;
mDrawingState.desiredHdrSdrRatio = desiredRatio;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2460,40 +1104,6 @@
bool Layer::setDesiredHdrHeadroom(float desiredRatio) {
if (mDrawingState.desiredHdrSdrRatio == desiredRatio) return false;
mDrawingState.desiredHdrSdrRatio = desiredRatio;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setCachingHint(gui::CachingHint cachingHint) {
- if (mDrawingState.cachingHint == cachingHint) return false;
- mDrawingState.cachingHint = cachingHint;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
- if (mDrawingState.hdrMetadata == hdrMetadata) return false;
- mDrawingState.hdrMetadata = hdrMetadata;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setSurfaceDamageRegion(const Region& surfaceDamage) {
- if (mDrawingState.surfaceDamageRegion.hasSameRects(surfaceDamage)) return false;
- mDrawingState.surfaceDamageRegion = surfaceDamage;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- setIsSmallDirty(surfaceDamage, getTransform());
- return true;
-}
-
-bool Layer::setApi(int32_t api) {
- if (mDrawingState.api == api) return false;
- mDrawingState.api = api;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2509,7 +1119,6 @@
}
mDrawingState.sidebandStream = sidebandStream;
- mDrawingState.modified = true;
if (sidebandStream != nullptr && mDrawingState.buffer != nullptr) {
releasePreviousBuffer();
resetDrawingStateBufferInfo();
@@ -2606,14 +1215,6 @@
return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight));
}
-FloatRect Layer::computeSourceBounds(const FloatRect& parentBounds) const {
- if (mBufferInfo.mBuffer == nullptr) {
- return parentBounds;
- }
-
- return getBufferSize(getDrawingState()).toFloatRect();
-}
-
bool Layer::fenceHasSignaled() const {
if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
return true;
@@ -2635,37 +1236,21 @@
}
}
-void Layer::setAutoRefresh(bool autoRefresh) {
- mDrawingState.autoRefresh = autoRefresh;
-}
-
bool Layer::latchSidebandStream(bool& recomputeVisibleRegions) {
- // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
- auto* snapshot = editLayerSnapshot();
- snapshot->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
-
if (mSidebandStreamChanged.exchange(false)) {
const State& s(getDrawingState());
// mSidebandStreamChanged was true
mSidebandStream = s.sidebandStream;
- snapshot->sidebandStream = mSidebandStream;
if (mSidebandStream != nullptr) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
recomputeVisibleRegions = true;
-
return true;
}
return false;
}
-bool Layer::hasFrameUpdate() const {
- const State& c(getDrawingState());
- return (mDrawingStateModified || mDrawingState.modified) &&
- (c.buffer != nullptr || c.bgColorLayer != nullptr);
-}
-
void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) {
const State& s(getDrawingState());
@@ -2712,8 +1297,6 @@
mFlinger->getTransactionCallbackInvoker()
.addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
mDrawingState.callbackHandles = remainingHandles;
-
- mDrawingStateModified = false;
}
void Layer::gatherBufferInfo() {
@@ -2737,7 +1320,6 @@
mBufferInfo.mFrameLatencyNeeded = true;
mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime;
mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
- mBufferInfo.mFence = mDrawingState.acquireFence;
mBufferInfo.mTransform = mDrawingState.bufferTransform;
auto lastDataspace = mBufferInfo.mDataspace;
mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace);
@@ -2785,10 +1367,6 @@
mFlinger->mHdrLayerInfoChanged = true;
}
mBufferInfo.mCrop = computeBufferCrop(mDrawingState);
- mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
- mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion;
- mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata;
- mBufferInfo.mApi = mDrawingState.api;
mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse;
}
@@ -2813,294 +1391,6 @@
SFTRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
}
-/*
- * We don't want to send the layer's transform to input, but rather the
- * parent's transform. This is because Layer's transform is
- * information about how the buffer is placed on screen. The parent's
- * transform makes more sense to send since it's information about how the
- * layer is placed on screen. This transform is used by input to determine
- * how to go from screen space back to window space.
- */
-ui::Transform Layer::getInputTransform() const {
- if (!hasBufferOrSidebandStream()) {
- return getTransform();
- }
- sp<Layer> parent = mDrawingParent.promote();
- if (parent == nullptr) {
- return ui::Transform();
- }
-
- return parent->getTransform();
-}
-
-/**
- * Returns the bounds used to fill the input frame and the touchable region.
- *
- * Similar to getInputTransform, we need to update the bounds to include the transform.
- * This is because bounds don't include the buffer transform, where the input assumes
- * that's already included.
- */
-std::pair<FloatRect, bool> Layer::getInputBounds(bool fillParentBounds) const {
- Rect croppedBufferSize = getCroppedBufferSize(getDrawingState());
- FloatRect inputBounds = croppedBufferSize.toFloatRect();
- if (hasBufferOrSidebandStream() && croppedBufferSize.isValid() &&
- mDrawingState.transform.getType() != ui::Transform::IDENTITY) {
- inputBounds = mDrawingState.transform.transform(inputBounds);
- }
-
- bool inputBoundsValid = croppedBufferSize.isValid();
- if (!inputBoundsValid) {
- /**
- * Input bounds are based on the layer crop or buffer size. But if we are using
- * the layer bounds as the input bounds (replaceTouchableRegionWithCrop flag) then
- * we can use the parent bounds as the input bounds if the layer does not have buffer
- * or a crop. We want to unify this logic but because of compat reasons we cannot always
- * use the parent bounds. A layer without a buffer can get input. So when a window is
- * initially added, its touchable region can fill its parent layer bounds and that can
- * have negative consequences.
- */
- inputBounds = fillParentBounds ? mBounds : FloatRect{};
- }
-
- // Clamp surface inset to the input bounds.
- const float inset = static_cast<float>(mDrawingState.inputInfo.surfaceInset);
- const float xSurfaceInset = std::clamp(inset, 0.f, inputBounds.getWidth() / 2.f);
- const float ySurfaceInset = std::clamp(inset, 0.f, inputBounds.getHeight() / 2.f);
-
- // Apply the insets to the input bounds.
- inputBounds.left += xSurfaceInset;
- inputBounds.top += ySurfaceInset;
- inputBounds.right -= xSurfaceInset;
- inputBounds.bottom -= ySurfaceInset;
-
- return {inputBounds, inputBoundsValid};
-}
-
-bool Layer::isSimpleBufferUpdate(const layer_state_t& s) const {
- const uint64_t requiredFlags = layer_state_t::eBufferChanged;
-
- const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
- layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
- layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
- layer_state_t::eLayerStackChanged | layer_state_t::eReparent |
- (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed()
- ? 0
- : layer_state_t::eAutoRefreshChanged);
-
- if ((s.what & requiredFlags) != requiredFlags) {
- SFTRACE_FORMAT_INSTANT("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
- (s.what | requiredFlags) & ~s.what);
- return false;
- }
-
- if (s.what & deniedFlags) {
- SFTRACE_FORMAT_INSTANT("%s: false [has denied flags 0x%" PRIx64 "]", __func__,
- s.what & deniedFlags);
- return false;
- }
-
- if (s.what & layer_state_t::ePositionChanged) {
- if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) {
- SFTRACE_FORMAT_INSTANT("%s: false [ePositionChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eAlphaChanged) {
- if (mDrawingState.color.a != s.color.a) {
- SFTRACE_FORMAT_INSTANT("%s: false [eAlphaChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eColorTransformChanged) {
- if (mDrawingState.colorTransform != s.colorTransform) {
- SFTRACE_FORMAT_INSTANT("%s: false [eColorTransformChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBackgroundColorChanged) {
- if (mDrawingState.bgColorLayer || s.bgColor.a != 0) {
- SFTRACE_FORMAT_INSTANT("%s: false [eBackgroundColorChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eMatrixChanged) {
- if (mRequestedTransform.dsdx() != s.matrix.dsdx ||
- mRequestedTransform.dtdy() != s.matrix.dtdy ||
- mRequestedTransform.dtdx() != s.matrix.dtdx ||
- mRequestedTransform.dsdy() != s.matrix.dsdy) {
- SFTRACE_FORMAT_INSTANT("%s: false [eMatrixChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eCornerRadiusChanged) {
- if (mDrawingState.cornerRadius != s.cornerRadius) {
- SFTRACE_FORMAT_INSTANT("%s: false [eCornerRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) {
- if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) {
- SFTRACE_FORMAT_INSTANT("%s: false [eBackgroundBlurRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBufferTransformChanged) {
- if (mDrawingState.bufferTransform != s.bufferTransform) {
- SFTRACE_FORMAT_INSTANT("%s: false [eBufferTransformChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eTransformToDisplayInverseChanged) {
- if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) {
- SFTRACE_FORMAT_INSTANT("%s: false [eTransformToDisplayInverseChanged changed]",
- __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eCropChanged) {
- if (mDrawingState.crop != s.crop) {
- SFTRACE_FORMAT_INSTANT("%s: false [eCropChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDataspaceChanged) {
- if (mDrawingState.dataspace != s.dataspace) {
- SFTRACE_FORMAT_INSTANT("%s: false [eDataspaceChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eHdrMetadataChanged) {
- if (mDrawingState.hdrMetadata != s.hdrMetadata) {
- SFTRACE_FORMAT_INSTANT("%s: false [eHdrMetadataChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eSidebandStreamChanged) {
- if (mDrawingState.sidebandStream != s.sidebandStream) {
- SFTRACE_FORMAT_INSTANT("%s: false [eSidebandStreamChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eColorSpaceAgnosticChanged) {
- if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) {
- SFTRACE_FORMAT_INSTANT("%s: false [eColorSpaceAgnosticChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eShadowRadiusChanged) {
- if (mDrawingState.shadowRadius != s.shadowRadius) {
- SFTRACE_FORMAT_INSTANT("%s: false [eShadowRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eFixedTransformHintChanged) {
- if (mDrawingState.fixedTransformHint != s.fixedTransformHint) {
- SFTRACE_FORMAT_INSTANT("%s: false [eFixedTransformHintChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eTrustedOverlayChanged) {
- if (mDrawingState.isTrustedOverlay != (s.trustedOverlay == gui::TrustedOverlay::ENABLED)) {
- SFTRACE_FORMAT_INSTANT("%s: false [eTrustedOverlayChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eStretchChanged) {
- StretchEffect temp = s.stretchEffect;
- temp.sanitize();
- if (mDrawingState.stretchEffect != temp) {
- SFTRACE_FORMAT_INSTANT("%s: false [eStretchChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBufferCropChanged) {
- if (mDrawingState.bufferCrop != s.bufferCrop) {
- SFTRACE_FORMAT_INSTANT("%s: false [eBufferCropChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDestinationFrameChanged) {
- if (mDrawingState.destinationFrame != s.destinationFrame) {
- SFTRACE_FORMAT_INSTANT("%s: false [eDestinationFrameChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDimmingEnabledChanged) {
- if (mDrawingState.dimmingEnabled != s.dimmingEnabled) {
- SFTRACE_FORMAT_INSTANT("%s: false [eDimmingEnabledChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eExtendedRangeBrightnessChanged) {
- if (mDrawingState.currentHdrSdrRatio != s.currentHdrSdrRatio ||
- mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) {
- SFTRACE_FORMAT_INSTANT("%s: false [eExtendedRangeBrightnessChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDesiredHdrHeadroomChanged) {
- if (mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) {
- SFTRACE_FORMAT_INSTANT("%s: false [eDesiredHdrHeadroomChanged changed]", __func__);
- return false;
- }
- }
-
- return true;
-}
-
-sp<LayerFE> Layer::getCompositionEngineLayerFE() const {
- // There's no need to get a CE Layer if the layer isn't going to draw anything.
- return hasSomethingToDraw() ? mLegacyLayerFE : nullptr;
-}
-
-const LayerSnapshot* Layer::getLayerSnapshot() const {
- return mSnapshot.get();
-}
-
-LayerSnapshot* Layer::editLayerSnapshot() {
- return mSnapshot.get();
-}
-
-std::unique_ptr<frontend::LayerSnapshot> Layer::stealLayerSnapshot() {
- return std::move(mSnapshot);
-}
-
-void Layer::updateLayerSnapshot(std::unique_ptr<frontend::LayerSnapshot> snapshot) {
- mSnapshot = std::move(snapshot);
-}
-
-const compositionengine::LayerFECompositionState* Layer::getCompositionState() const {
- return mSnapshot.get();
-}
-
-sp<LayerFE> Layer::copyCompositionEngineLayerFE() const {
- auto result = mFlinger->getFactory().createLayerFE(mName, this);
- result->mSnapshot = std::make_unique<LayerSnapshot>(*mSnapshot);
- return result;
-}
-
sp<LayerFE> Layer::getCompositionEngineLayerFE(
const frontend::LayerHierarchy::TraversalPath& path) {
for (auto& [p, layerFE] : mLayerFEs) {
@@ -3113,55 +1403,6 @@
return layerFE;
}
-void Layer::useSurfaceDamage() {
- if (mFlinger->mForceFullDamage) {
- surfaceDamageRegion = Region::INVALID_REGION;
- } else {
- surfaceDamageRegion = mBufferInfo.mSurfaceDamage;
- }
-}
-
-void Layer::useEmptyDamage() {
- surfaceDamageRegion.clear();
-}
-
-bool Layer::isOpaque(const Layer::State& s) const {
- // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
- // layer's opaque flag.
- if (!hasSomethingToDraw()) {
- return false;
- }
-
- // if the layer has the opaque flag, then we're always opaque
- if ((s.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque) {
- return true;
- }
-
- // If the buffer has no alpha channel, then we are opaque
- if (hasBufferOrSidebandStream() && LayerSnapshot::isOpaqueFormat(getPixelFormat())) {
- return true;
- }
-
- // Lastly consider the layer opaque if drawing a color with alpha == 1.0
- return fillsColor() && getAlpha() == 1.0_hf;
-}
-
-bool Layer::canReceiveInput() const {
- return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f);
-}
-
-bool Layer::isVisible() const {
- if (!hasSomethingToDraw()) {
- return false;
- }
-
- if (isHiddenByPolicy()) {
- return false;
- }
-
- return getAlpha() > 0.0f || hasBlur();
-}
-
void Layer::onCompositionPresented(const DisplayDevice* display,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
@@ -3254,11 +1495,6 @@
return !mDrawingState.buffer && mBufferInfo.mBuffer;
}
-bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
- const bool bgColorOnly = mDrawingState.bgColorLayer != nullptr;
- return latchBufferImpl(recomputeVisibleRegions, latchTime, bgColorOnly);
-}
-
bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly) {
SFTRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
getDrawingState().frameNumber);
@@ -3280,7 +1516,6 @@
// Capture the old state of the layer for comparisons later
BufferInfo oldBufferInfo = mBufferInfo;
- const bool oldOpacity = isOpaque(mDrawingState);
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mDrawingState.frameNumber;
gatherBufferInfo();
@@ -3305,7 +1540,6 @@
if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
(mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
- (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
(mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
recomputeVisibleRegions = true;
}
@@ -3318,35 +1552,14 @@
recomputeVisibleRegions = true;
}
}
-
- if (oldOpacity != isOpaque(mDrawingState)) {
- recomputeVisibleRegions = true;
- }
-
return true;
}
-bool Layer::hasReadyFrame() const {
- return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
-}
-
bool Layer::isProtected() const {
return (mBufferInfo.mBuffer != nullptr) &&
(mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
-void Layer::latchAndReleaseBuffer() {
- if (hasReadyFrame()) {
- bool ignored = false;
- latchBuffer(ignored, systemTime());
- }
- releasePendingBuffer(systemTime());
-}
-
-PixelFormat Layer::getPixelFormat() const {
- return mBufferInfo.mPixelFormat;
-}
-
bool Layer::getTransformToDisplayInverse() const {
return mBufferInfo.mTransformToDisplayInverse;
}
@@ -3370,18 +1583,6 @@
return mBufferInfo.mTransform;
}
-ui::Dataspace Layer::getDataSpace() const {
- return hasBufferOrSidebandStream() ? mBufferInfo.mDataspace : mDrawingState.dataspace;
-}
-
-bool Layer::isFrontBuffered() const {
- if (mBufferInfo.mBuffer == nullptr) {
- return false;
- }
-
- return mBufferInfo.mBuffer->getUsage() & AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
-}
-
ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) {
ui::Dataspace updatedDataspace = dataspace;
// translate legacy dataspaces to modern dataspaces
@@ -3417,84 +1618,6 @@
return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
}
-const std::shared_ptr<renderengine::ExternalTexture>& Layer::getExternalTexture() const {
- return mBufferInfo.mBuffer;
-}
-
-bool Layer::setColor(const half3& color) {
- if (mDrawingState.color.rgb == color) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.color.rgb = color;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::fillsColor() const {
- return !hasBufferOrSidebandStream() && mDrawingState.color.r >= 0.0_hf &&
- mDrawingState.color.g >= 0.0_hf && mDrawingState.color.b >= 0.0_hf;
-}
-
-bool Layer::hasBlur() const {
- return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0;
-}
-
-void Layer::updateSnapshot(bool updateGeometry) {
- if (!getCompositionEngineLayerFE()) {
- return;
- }
-
- auto* snapshot = editLayerSnapshot();
- if (updateGeometry) {
- prepareBasicGeometryCompositionState();
- prepareGeometryCompositionState();
- snapshot->roundedCorner = getRoundedCornerState();
- snapshot->transformedBounds = mScreenBounds;
- if (mEffectiveShadowRadius > 0.f) {
- snapshot->shadowSettings = mFlinger->mDrawingState.globalShadowSettings;
-
- // Note: this preserves existing behavior of shadowing the entire layer and not cropping
- // it if transparent regions are present. This may not be necessary since shadows are
- // typically cast by layers without transparent regions.
- snapshot->shadowSettings.boundaries = mBounds;
-
- const float casterAlpha = snapshot->alpha;
- const bool casterIsOpaque =
- ((mBufferInfo.mBuffer != nullptr) && isOpaque(mDrawingState));
-
- // If the casting layer is translucent, we need to fill in the shadow underneath the
- // layer. Otherwise the generated shadow will only be shown around the casting layer.
- snapshot->shadowSettings.casterIsTranslucent = !casterIsOpaque || (casterAlpha < 1.0f);
- snapshot->shadowSettings.ambientColor *= casterAlpha;
- snapshot->shadowSettings.spotColor *= casterAlpha;
- }
- snapshot->shadowSettings.length = mEffectiveShadowRadius;
- }
- snapshot->contentOpaque = isOpaque(mDrawingState);
- snapshot->layerOpaqueFlagSet =
- (mDrawingState.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
- sp<Layer> p = mDrawingParent.promote();
- if (p != nullptr) {
- snapshot->parentTransform = p->getTransform();
- } else {
- snapshot->parentTransform.reset();
- }
- snapshot->bufferSize = getBufferSize(mDrawingState);
- snapshot->externalTexture = mBufferInfo.mBuffer;
- snapshot->hasReadyFrame = hasReadyFrame();
- preparePerFrameCompositionState();
-}
-
-void Layer::updateChildrenSnapshots(bool updateGeometry) {
- for (const sp<Layer>& child : mDrawingChildren) {
- child->updateSnapshot(updateGeometry);
- child->updateChildrenSnapshots(updateGeometry);
- }
-}
-
bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds,
TrustedPresentationListener const& listener) {
bool hadTrustedPresentationListener = hasTrustedPresentationListener();
@@ -3527,35 +1650,32 @@
mLastLatchTime = latchTime;
}
-void Layer::setIsSmallDirty(const Region& damageRegion,
- const ui::Transform& layerToDisplayTransform) {
- mSmallDirty = false;
+void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) {
if (!mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) {
+ snapshot->isSmallDirty = false;
return;
}
if (mWindowType != WindowInfo::Type::APPLICATION &&
mWindowType != WindowInfo::Type::BASE_APPLICATION) {
+ snapshot->isSmallDirty = false;
return;
}
- Rect bounds = damageRegion.getBounds();
+ Rect bounds = snapshot->surfaceDamage.getBounds();
if (!bounds.isValid()) {
+ snapshot->isSmallDirty = false;
return;
}
// Transform to screen space.
- bounds = layerToDisplayTransform.transform(bounds);
+ bounds = snapshot->localTransform.transform(bounds);
// If the damage region is a small dirty, this could give the hint for the layer history that
// it could suppress the heuristic rate when calculating.
- mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId,
- bounds.getWidth() * bounds.getHeight());
-}
-
-void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) {
- setIsSmallDirty(snapshot->surfaceDamage, snapshot->localTransform);
- snapshot->isSmallDirty = mSmallDirty;
+ snapshot->isSmallDirty =
+ mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId,
+ bounds.getWidth() * bounds.getHeight());
}
} // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1e4f2dc..9caa20c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -43,9 +43,7 @@
#include <scheduler/Fps.h>
#include <scheduler/Seamlessness.h>
-#include <chrono>
#include <cstdint>
-#include <list>
#include <optional>
#include <vector>
@@ -56,7 +54,6 @@
#include "LayerVector.h"
#include "Scheduler/LayerInfo.h"
#include "SurfaceFlinger.h"
-#include "Tracing/LayerTracing.h"
#include "TransactionCallbackInvoker.h"
using namespace android::surfaceflinger;
@@ -97,42 +94,15 @@
eInputInfoChanged = 0x00000004
};
- struct Geometry {
- uint32_t w;
- uint32_t h;
- ui::Transform transform;
-
- inline bool operator==(const Geometry& rhs) const {
- return (w == rhs.w && h == rhs.h) && (transform.tx() == rhs.transform.tx()) &&
- (transform.ty() == rhs.transform.ty());
- }
- inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); }
- };
-
using FrameRate = scheduler::LayerInfo::FrameRate;
using FrameRateCompatibility = scheduler::FrameRateCompatibility;
using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy;
struct State {
- int32_t z;
- ui::LayerStack layerStack;
- uint32_t flags;
int32_t sequence; // changes when visible regions can change
- bool modified;
// Crop is expressed in layer space coordinate.
Rect crop;
LayerMetadata metadata;
- // If non-null, a Surface this Surface's Z-order is interpreted relative to.
- wp<Layer> zOrderRelativeOf;
- bool isRelativeOf{false};
-
- // A list of surfaces whose Z-order is interpreted relative to ours.
- SortedVector<wp<Layer>> zOrderRelatives;
- half4 color;
- float cornerRadius;
- int backgroundBlurRadius;
- gui::WindowInfo inputInfo;
- wp<Layer> touchableRegionCrop;
ui::Dataspace dataspace;
@@ -154,52 +124,18 @@
std::shared_ptr<renderengine::ExternalTexture> buffer;
sp<Fence> acquireFence;
std::shared_ptr<FenceTime> acquireFenceTime;
- HdrMetadata hdrMetadata;
- Region surfaceDamageRegion;
- int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
- bool hasColorTransform;
- // pointer to background color layer that, if set, appears below the buffer state layer
- // and the buffer state layer's children. Z order will be set to
- // INT_MIN
- sp<Layer> bgColorLayer;
// The deque of callback handles for this frame. The back of the deque contains the most
// recent callback handle.
std::deque<sp<CallbackHandle>> callbackHandles;
- bool colorSpaceAgnostic;
nsecs_t desiredPresentTime = 0;
bool isAutoTimestamp = true;
- // Length of the cast shadow. If the radius is > 0, a shadow of length shadowRadius will
- // be rendered around the layer.
- float shadowRadius;
-
- // Layer regions that are made of custom materials, like frosted glass
- std::vector<BlurRegion> blurRegions;
-
- // Priority of the layer assigned by Window Manager.
- int32_t frameRateSelectionPriority;
-
- // Default frame rate compatibility used to set the layer refresh rate votetype.
- FrameRateCompatibility defaultFrameRateCompatibility;
- FrameRate frameRate;
-
// The combined frame rate of parents / children of this layer
FrameRate frameRateForLayerTree;
- FrameRateSelectionStrategy frameRateSelectionStrategy;
-
- // Set by window manager indicating the layer and all its children are
- // in a different orientation than the display. The hint suggests that
- // the graphic producers should receive a transform hint as if the
- // display was in this orientation. When the display changes to match
- // the layer orientation, the graphic producer may not need to allocate
- // a buffer of a different size. ui::Transform::ROT_INVALID means the
- // a fixed transform hint is not set.
- ui::Transform::RotationFlags fixedTransformHint;
-
// The vsync info that was used to start the transaction
FrameTimelineInfo frameTimelineInfo;
@@ -219,21 +155,12 @@
// An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to
// trigger a warning if the number of SurfaceFrames crosses the threshold.
static constexpr uint32_t kStateSurfaceFramesThreshold = 25;
-
- // Stretch effect to apply to this layer
- StretchEffect stretchEffect;
-
- // Whether or not this layer is a trusted overlay for input
- bool isTrustedOverlay;
Rect bufferCrop;
Rect destinationFrame;
sp<IBinder> releaseBufferEndpoint;
- gui::DropInputMode dropInputMode;
bool autoRefresh = false;
- bool dimmingEnabled = true;
float currentHdrSdrRatio = 1.f;
float desiredHdrSdrRatio = -1.f;
- gui::CachingHint cachingHint = gui::CachingHint::Enabled;
int64_t latchedVsyncId = 0;
bool useVsyncIdForRefreshRateSelection = false;
};
@@ -245,15 +172,7 @@
static void miniDumpHeader(std::string& result);
// Provide unique string for each class type in the Layer hierarchy
- virtual const char* getType() const { return "Layer"; }
-
- // true if this layer is visible, false otherwise
- virtual bool isVisible() const;
-
- // Set a 2x2 transformation matrix on the layer. This transform
- // will be applied after parent transforms, but before any final
- // producer specified transform.
- bool setMatrix(const layer_state_t::matrix22_t& matrix);
+ const char* getType() const { return "Layer"; }
// This second set of geometry attributes are controlled by
// setGeometryAppliesWithResize, and their default mode is to be
@@ -261,49 +180,9 @@
// while a resize is pending, then update of these attributes will
// be delayed until the resize completes.
- // setPosition operates in parent buffer space (pre parent-transform) or display
- // space for top-level layers.
- bool setPosition(float x, float y);
// Buffer space
bool setCrop(const Rect& crop);
- // TODO(b/38182121): Could we eliminate the various latching modes by
- // using the layer hierarchy?
- // -----------------------------------------------------------------------
- virtual bool setLayer(int32_t z);
- virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
-
- virtual bool setAlpha(float alpha);
- bool setColor(const half3& /*color*/);
-
- // Set rounded corner radius for this layer and its children.
- //
- // We only support 1 radius per layer in the hierarchy, where parent layers have precedence.
- // The shape of the rounded corner rectangle is specified by the crop rectangle of the layer
- // from which we inferred the rounded corner radius.
- virtual bool setCornerRadius(float cornerRadius);
- // When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which
- // is specified in pixels.
- virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
- virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions);
- bool setTransparentRegionHint(const Region& transparent);
- virtual bool setTrustedOverlay(bool);
- virtual bool setFlags(uint32_t flags, uint32_t mask);
- virtual bool setLayerStack(ui::LayerStack);
- virtual ui::LayerStack getLayerStack(
- LayerVector::StateSet state = LayerVector::StateSet::Drawing) const;
-
- virtual bool setMetadata(const LayerMetadata& data);
- virtual void setChildrenDrawingParent(const sp<Layer>&);
- virtual bool setColorTransform(const mat4& matrix);
- virtual mat4 getColorTransform() const;
- virtual bool hasColorTransform() const;
- virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
- virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; }
- float getDesiredHdrSdrRatio() const { return getDrawingState().desiredHdrSdrRatio; }
- float getCurrentHdrSdrRatio() const { return getDrawingState().currentHdrSdrRatio; }
- gui::CachingHint getCachingHint() const { return getDrawingState().cachingHint; }
-
bool setTransform(uint32_t /*transform*/);
bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/);
bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
@@ -314,111 +193,34 @@
bool setDataspace(ui::Dataspace /*dataspace*/);
bool setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio);
bool setDesiredHdrHeadroom(float desiredRatio);
- bool setCachingHint(gui::CachingHint cachingHint);
- bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/);
- bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/);
- bool setApi(int32_t /*api*/);
bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/,
const FrameTimelineInfo& /* info*/, nsecs_t /* postTime */,
gui::GameMode gameMode);
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& /*handles*/,
bool willPresent);
- virtual bool setColorSpaceAgnostic(const bool agnostic);
- virtual bool setDimmingEnabled(const bool dimmingEnabled);
- virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
- void setAutoRefresh(bool /* autoRefresh */);
- bool setDropInputMode(gui::DropInputMode);
- ui::Dataspace getDataSpace() const;
-
- virtual bool isFrontBuffered() const;
-
- virtual sp<LayerFE> getCompositionEngineLayerFE() const;
- virtual sp<LayerFE> copyCompositionEngineLayerFE() const;
sp<LayerFE> getCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
sp<LayerFE> getOrCreateCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
- const frontend::LayerSnapshot* getLayerSnapshot() const;
- frontend::LayerSnapshot* editLayerSnapshot();
- std::unique_ptr<frontend::LayerSnapshot> stealLayerSnapshot();
- void updateLayerSnapshot(std::unique_ptr<frontend::LayerSnapshot> snapshot);
-
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
- void useSurfaceDamage();
- void useEmptyDamage();
Region getVisibleRegion(const DisplayDevice*) const;
void updateLastLatchTime(nsecs_t latchtime);
/*
- * isOpaque - true if this surface is opaque
- *
- * This takes into account the buffer format (i.e. whether or not the
- * pixel format includes an alpha channel) and the "opaque" flag set
- * on the layer. It does not examine the current plane alpha value.
- */
- bool isOpaque(const Layer::State&) const;
-
- /*
- * Returns whether this layer can receive input.
- */
- bool canReceiveInput() const;
-
- /*
- * Whether or not the layer should be considered visible for input calculations.
- */
- virtual bool isVisibleForInput() const {
- // For compatibility reasons we let layers which can receive input
- // receive input before they have actually submitted a buffer. Because
- // of this we use canReceiveInput instead of isVisible to check the
- // policy-visibility, ignoring the buffer state. However for layers with
- // hasInputInfo()==false we can use the real visibility state.
- // We are just using these layers for occlusion detection in
- // InputDispatcher, and obviously if they aren't visible they can't occlude
- // anything.
- return hasInputInfo() ? canReceiveInput() : isVisible();
- }
-
- /*
* isProtected - true if the layer may contain protected contents in the
* GRALLOC_USAGE_PROTECTED sense.
*/
bool isProtected() const;
-
- /*
- * isFixedSize - true if content has a fixed size
- */
- virtual bool isFixedSize() const { return true; }
-
/*
* usesSourceCrop - true if content should use a source crop
*/
bool usesSourceCrop() const { return hasBufferOrSidebandStream(); }
- // Most layers aren't created from the main thread, and therefore need to
- // grab the SF state lock to access HWC, but ContainerLayer does, so we need
- // to avoid grabbing the lock again to avoid deadlock
- virtual bool isCreatedFromMainThread() const { return false; }
-
- ui::Transform getActiveTransform(const Layer::State& s) const { return s.transform; }
- Region getActiveTransparentRegion(const Layer::State& s) const {
- return s.transparentRegionHint;
- }
Rect getCrop(const Layer::State& s) const { return s.crop; }
bool needsFiltering(const DisplayDevice*) const;
- // True if this layer requires filtering
- // This method is distinct from needsFiltering() in how the filter
- // requirement is computed. needsFiltering() compares displayFrame and crop,
- // where as this method transforms the displayFrame to layer-stack space
- // first. This method should be used if there is no physical display to
- // project onto when taking screenshots, as the filtering requirements are
- // different.
- // If the parent transform needs to be undone when capturing the layer, then
- // the inverse parent transform is also required.
- bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const;
-
// from graphics API
static ui::Dataspace translateDataspace(ui::Dataspace dataspace);
uint64_t mPreviousFrameNumber = 0;
@@ -437,8 +239,6 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/);
-
bool latchBufferImpl(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
bool bgColorOnly);
@@ -449,14 +249,6 @@
bool willReleaseBufferOnLatch() const;
/*
- * Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
- * This is used if the buffer is just latched and releases to free up the buffer
- * and will not be shown on screen.
- * Should only be called on the main thread.
- */
- void latchAndReleaseBuffer();
-
- /*
* returns the rectangle that crops the content of the layer and scales it
* to the layer's size.
*/
@@ -468,15 +260,6 @@
uint32_t getBufferTransform() const;
sp<GraphicBuffer> getBuffer() const;
- const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const;
-
- /*
- * Returns if a frame is ready
- */
- bool hasReadyFrame() const;
-
- virtual int32_t getQueuedFrameCount() const { return 0; }
-
/**
* Returns active buffer size in the correct orientation. Buffer size is determined by undoing
* any buffer transformations. Returns Rect::INVALID_RECT if the layer has no buffer or the
@@ -484,33 +267,10 @@
*/
Rect getBufferSize(const Layer::State&) const;
- /**
- * Returns the source bounds. If the bounds are not defined, it is inferred from the
- * buffer size. Failing that, the bounds are determined from the passed in parent bounds.
- * For the root layer, this is the display viewport size.
- */
- FloatRect computeSourceBounds(const FloatRect& parentBounds) const;
- virtual FrameRate getFrameRateForLayerTree() const;
+ FrameRate getFrameRateForLayerTree() const;
bool getTransformToDisplayInverse() const;
- // Returns how rounded corners should be drawn for this layer.
- // A layer can override its parent's rounded corner settings if the parent's rounded
- // corner crop does not intersect with its own rounded corner crop.
- virtual frontend::RoundedCornerState getRoundedCornerState() const;
-
- bool hasRoundedCorners() const { return getRoundedCornerState().hasRoundedCorners(); }
-
- PixelFormat getPixelFormat() const;
- /**
- * Return whether this layer needs an input info. We generate InputWindowHandles for all
- * non-cursor buffered layers regardless of whether they have an InputChannel. This is to enable
- * the InputDispatcher to do PID based occlusion detection.
- */
- bool needsInputInfo() const {
- return (hasInputInfo() || hasBufferOrSidebandStream()) && !mPotentialCursor;
- }
-
// Implements RefBase.
void onFirstRef() override;
@@ -521,17 +281,11 @@
uint32_t mTransform{0};
ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
Rect mCrop;
- uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
- Region mSurfaceDamage;
- HdrMetadata mHdrMetadata;
- int mApi;
PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
bool mTransformToDisplayInverse{false};
-
std::shared_ptr<renderengine::ExternalTexture> mBuffer;
uint64_t mFrameNumber;
sp<IBinder> mReleaseBufferEndpoint;
-
bool mFrameLatencyNeeded{false};
float mDesiredHdrSdrRatio = -1.f;
};
@@ -539,8 +293,6 @@
BufferInfo mBufferInfo;
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseChannel;
- // implements compositionengine::LayerFE
- const compositionengine::LayerFECompositionState* getCompositionState() const;
bool fenceHasSignaled() const;
void onPreComposition(nsecs_t refreshStartTime);
void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack,
@@ -561,15 +313,6 @@
const char* getDebugName() const;
- bool setShadowRadius(float shadowRadius);
-
- // Before color management is introduced, contents on Android have to be
- // desaturated in order to match what they appears like visually.
- // With color management, these contents will appear desaturated, thus
- // needed to be saturated so that they match what they are designed for
- // visually.
- bool isLegacyDataSpace() const;
-
uint32_t getTransactionFlags() const { return mTransactionFlags; }
static bool computeTrustedPresentationState(const FloatRect& bounds,
@@ -592,14 +335,6 @@
// Clears and returns the masked bits.
uint32_t clearTransactionFlags(uint32_t mask);
- FloatRect getBounds(const Region& activeTransparentRegion) const;
- FloatRect getBounds() const;
- Rect getInputBoundsInDisplaySpace(const FloatRect& insetBounds,
- const ui::Transform& displayTransform);
-
- // Compute bounds for the layer and cache the results.
- void computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float shadowRadius);
-
int32_t getSequence() const { return sequence; }
// For tracing.
@@ -610,90 +345,35 @@
// only used within a single layer.
uint64_t getCurrentBufferId() const { return getBuffer() ? getBuffer()->getId() : 0; }
- /*
- * isSecure - true if this surface is secure, that is if it prevents
- * screenshots or VNC servers. A surface can be set to be secure by the
- * application, being secure doesn't mean the surface has DRM contents.
- */
- bool isSecure() const;
-
- /*
- * isHiddenByPolicy - true if this layer has been forced invisible.
- * just because this is false, doesn't mean isVisible() is true.
- * For example if this layer has no active buffer, it may not be hidden by
- * policy, but it still can not be visible.
- */
- bool isHiddenByPolicy() const;
-
- // True if the layer should be skipped in screenshots, screen recordings,
- // and mirroring to external or virtual displays.
- bool isInternalDisplayOverlay() const;
-
- ui::LayerFilter getOutputFilter() const {
- return {getLayerStack(), isInternalDisplayOverlay()};
- }
-
- perfetto::protos::LayerProto* writeToProto(perfetto::protos::LayersProto& layersProto,
- uint32_t traceFlags);
void writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto,
ui::LayerStack layerStack);
- // Write states that are modified by the main thread. This includes drawing
- // state as well as buffer data. This should be called in the main or tracing
- // thread.
- void writeToProtoDrawingState(perfetto::protos::LayerProto* layerInfo);
- // Write drawing or current state. If writing current state, the caller should hold the
- // external mStateLock. If writing drawing state, this function should be called on the
- // main or tracing thread.
- void writeToProtoCommonState(perfetto::protos::LayerProto* layerInfo, LayerVector::StateSet,
- uint32_t traceFlags = LayerTracing::TRACE_ALL);
-
gui::WindowInfo::Type getWindowType() const { return mWindowType; }
/*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
- virtual uint32_t doTransaction(uint32_t transactionFlags);
-
- /*
- * Remove relative z for the layer if its relative parent is not part of the
- * provided layer tree.
- */
- void removeRelativeZ(const std::vector<Layer*>& layersInTree);
+ uint32_t doTransaction(uint32_t transactionFlags);
inline const State& getDrawingState() const { return mDrawingState; }
inline State& getDrawingState() { return mDrawingState; }
void miniDump(std::string& result, const frontend::LayerSnapshot&, const DisplayDevice&) const;
void dumpFrameStats(std::string& result) const;
- void dumpOffscreenDebugInfo(std::string& result) const;
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
void onDisconnect();
ui::Transform getTransform() const;
- bool isTransformValid() const;
- // Returns the Alpha of the Surface, accounting for the Alpha
- // of parent Surfaces in the hierarchy (alpha's will be multiplied
- // down the hierarchy).
- half getAlpha() const;
half4 getColor() const;
int32_t getBackgroundBlurRadius() const;
bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
- // Returns the transform hint set by Window Manager on the layer or one of its parents.
- // This traverses the current state because the data is needed when creating
- // the layer(off drawing thread) and the hint should be available before the producer
- // is ready to acquire a buffer.
- ui::Transform::RotationFlags getFixedTransformHint() const;
-
bool isHandleAlive() const { return mHandleAlive; }
bool onHandleDestroyed() { return mHandleAlive = false; }
- Rect getScreenBounds(bool reduceTransparentRegion = true) const;
- int32_t getZ(LayerVector::StateSet) const;
/**
* Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
@@ -703,7 +383,7 @@
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
- virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
+ void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime,
gui::GameMode gameMode);
void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
@@ -732,31 +412,14 @@
// this to be called once.
sp<IBinder> getHandle();
const std::string& getName() const { return mName; }
- bool getPremultipledAlpha() const;
void setInputInfo(const gui::WindowInfo& info);
- struct InputDisplayArgs {
- const ui::Transform* transform = nullptr;
- bool isSecure = false;
- };
- gui::WindowInfo fillInputInfo(const InputDisplayArgs& displayArgs);
-
- /**
- * Returns whether this layer has an explicitly set input-info.
- */
- bool hasInputInfo() const;
-
virtual uid_t getOwnerUid() const { return mOwnerUid; }
pid_t getOwnerPid() { return mOwnerPid; }
int32_t getOwnerAppId() { return mOwnerAppId; }
- mutable bool contentDirty{false};
- Region surfaceDamageRegion;
-
- // True when the surfaceDamageRegion is recognized as a small area update.
- bool mSmallDirty{false};
// Used to check if mUsedVsyncIdForRefreshRateSelection should be expired when it stop updating.
nsecs_t mMaxTimeForUseVsyncId = 0;
// True when DrawState.useVsyncIdForRefreshRateSelection previously set to true during updating
@@ -770,35 +433,11 @@
bool mPendingHWCDestroy{false};
- bool backpressureEnabled() const {
- return mDrawingState.flags & layer_state_t::eEnableBackpressure;
- }
-
- bool setStretchEffect(const StretchEffect& effect);
-
bool setBufferCrop(const Rect& /* bufferCrop */);
- bool setDestinationFrame(const Rect& /* destinationFrame */);
// See mPendingBufferTransactions
void decrementPendingBufferCount();
std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBufferTransactions; }
std::string getPendingBufferCounterName() { return mBlastTransactionName; }
- bool updateGeometry();
-
- bool isSimpleBufferUpdate(const layer_state_t& s) const;
-
- static bool isOpaqueFormat(PixelFormat format);
-
- // Updates the LayerSnapshot. This must be called prior to sending layer data to
- // CompositionEngine or RenderEngine (i.e. before calling CompositionEngine::present or
- // LayerFE::prepareClientComposition).
- //
- // TODO(b/238781169) Remove direct calls to RenderEngine::drawLayers that don't go through
- // CompositionEngine to create a single path for composing layers.
- void updateSnapshot(bool updateGeometry);
- void updateChildrenSnapshots(bool updateGeometry);
-
- bool willPresentCurrentTransaction() const;
-
void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, uint64_t framenumber,
const sp<Fence>& releaseFence);
@@ -844,7 +483,6 @@
const sp<SurfaceFlinger> mFlinger;
// Check if the damage region is a small dirty.
- void setIsSmallDirty(const Region& damageRegion, const ui::Transform& layerToDisplayTransform);
void setIsSmallDirty(frontend::LayerSnapshot* snapshot);
protected:
@@ -856,52 +494,16 @@
friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
- void preparePerFrameCompositionState();
- void preparePerFrameBufferCompositionState();
- void preparePerFrameEffectsCompositionState();
void gatherBufferInfo();
- void prepareBasicGeometryCompositionState();
- void prepareGeometryCompositionState();
- void prepareCursorCompositionState();
-
- uint32_t getEffectiveUsage(uint32_t usage) const;
-
- /**
- * Setup rounded corners coordinates of this layer, taking into account the layer bounds and
- * crop coordinates, transforming them into layer space.
- */
- void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const;
- void setParent(const sp<Layer>&);
- LayerVector makeTraversalList(LayerVector::StateSet, bool* outSkipRelativeZUsers);
- void addZOrderRelative(const wp<Layer>& relative);
- void removeZOrderRelative(const wp<Layer>& relative);
compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const;
compositionengine::OutputLayer* findOutputLayerForDisplay(
const DisplayDevice*, const frontend::LayerHierarchy::TraversalPath& path) const;
- bool usingRelativeZ(LayerVector::StateSet) const;
- virtual ui::Transform getInputTransform() const;
- /**
- * Get the bounds in layer space within which this layer can receive input.
- *
- * These bounds are used to:
- * - Determine the input frame for the layer to be used for occlusion detection; and
- * - Determine the coordinate space within which the layer will receive input. The top-left of
- * this rect will be the origin of the coordinate space that the input events sent to the
- * layer will be in (prior to accounting for surface insets).
- *
- * The layer can still receive touch input if these bounds are invalid if
- * "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input
- * in this layer's space, regardless of the specified crop layer.
- */
- std::pair<FloatRect, bool> getInputBounds(bool fillParentBounds) const;
-
- bool mPremultipliedAlpha{true};
const std::string mName;
const std::string mTransactionName{"TX - " + mName};
- // These are only accessed by the main thread or the tracing thread.
+ // These are only accessed by the main thread.
State mDrawingState;
TrustedPresentationThresholds mTrustedPresentationThresholds;
@@ -921,34 +523,16 @@
// main thread
sp<NativeHandle> mSidebandStream;
- // False if the buffer and its contents have been previously used for GPU
- // composition, true otherwise.
- bool mIsActiveBufferUpdatedForGpu = true;
// We encode unset as -1.
std::atomic<uint64_t> mCurrentFrameNumber{0};
- // Whether filtering is needed b/c of the drawingstate
- bool mNeedsFiltering{false};
-
- std::atomic<bool> mRemovedFromDrawingState{false};
-
- // page-flip thread (currently main thread)
- bool mProtectedByApp{false}; // application requires protected path to external sink
// protected by mLock
mutable Mutex mLock;
- const wp<Client> mClientRef;
-
// This layer can be a cursor on some displays.
bool mPotentialCursor{false};
- LayerVector mCurrentChildren{LayerVector::StateSet::Current};
- LayerVector mDrawingChildren{LayerVector::StateSet::Drawing};
-
- wp<Layer> mCurrentParent;
- wp<Layer> mDrawingParent;
-
// Window types from WindowManager.LayoutParams
const gui::WindowInfo::Type mWindowType;
@@ -966,8 +550,6 @@
// Used in buffer stuffing analysis in FrameTimeline.
nsecs_t mLastLatchTime = 0;
- mutable bool mDrawingStateModified = false;
-
sp<Fence> mLastClientCompositionFence;
bool mClearClientCompositionFenceOnLayerDisplayed = false;
private:
@@ -979,44 +561,20 @@
friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
- bool getAutoRefresh() const { return mDrawingState.autoRefresh; }
bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
std::atomic<bool> mSidebandStreamChanged{false};
- // Returns true if the layer can draw shadows on its border.
- virtual bool canDrawShadows() const { return true; }
-
aidl::android::hardware::graphics::composer3::Composition getCompositionType(
const DisplayDevice&) const;
aidl::android::hardware::graphics::composer3::Composition getCompositionType(
const compositionengine::OutputLayer*) const;
- bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overrideChildren,
- bool* transactionNeeded);
- void setZOrderRelativeOf(const wp<Layer>& relativeOf);
- bool isTrustedOverlay() const;
- gui::DropInputMode getDropInputMode() const;
- void handleDropInputMode(gui::WindowInfo& info) const;
-
- // Finds the top most layer in the hierarchy. This will find the root Layer where the parent is
- // null.
- sp<Layer> getRootLayer();
-
- // Fills in the touch occlusion mode of the first parent (including this layer) that
- // hasInputInfo() or no-op if no such parent is found.
- void fillTouchOcclusionMode(gui::WindowInfo& info);
-
- // Fills in the frame and transform info for the gui::WindowInfo.
- void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& screenToDisplay);
-
inline void tracePendingBufferCount(int32_t pendingBuffers);
// Latch sideband stream and returns true if the dirty region should be updated.
bool latchSidebandStream(bool& recomputeVisibleRegions);
- bool hasFrameUpdate() const;
-
void updateTexImage(nsecs_t latchTime, bool bgColorOnly = false);
// Crop that applies to the buffer
@@ -1027,15 +585,6 @@
const sp<Fence>& releaseFence,
uint32_t currentMaxAcquiredBufferCount);
- // Returns true if the transformed buffer size does not match the layer size and we need
- // to apply filtering.
- bool bufferNeedsFiltering() const;
-
- // Returns true if there is a valid color to fill.
- bool fillsColor() const;
- // Returns true if this layer has a blur value.
- bool hasBlur() const;
- bool hasEffect() const { return fillsColor() || drawShadows() || hasBlur(); }
bool hasBufferOrSidebandStream() const {
return ((mSidebandStream != nullptr) || (mBufferInfo.mBuffer != nullptr));
}
@@ -1044,33 +593,6 @@
return ((mDrawingState.sidebandStream != nullptr) || (mDrawingState.buffer != nullptr));
}
- bool hasSomethingToDraw() const { return hasEffect() || hasBufferOrSidebandStream(); }
-
- bool shouldOverrideChildrenFrameRate() const {
- return getDrawingState().frameRateSelectionStrategy ==
- FrameRateSelectionStrategy::OverrideChildren;
- }
-
- bool shouldPropagateFrameRate() const {
- return getDrawingState().frameRateSelectionStrategy != FrameRateSelectionStrategy::Self;
- }
-
- // Cached properties computed from drawing state
- // Effective transform taking into account parent transforms and any parent scaling, which is
- // a transform from the current layer coordinate space to display(screen) coordinate space.
- ui::Transform mEffectiveTransform;
-
- // Bounds of the layer before any transformation is applied and before it has been cropped
- // by its parents.
- FloatRect mSourceBounds;
-
- // Bounds of the layer in layer space. This is the mSourceBounds cropped by its layer crop and
- // its parent bounds.
- FloatRect mBounds;
-
- // Layer bounds in screen space.
- FloatRect mScreenBounds;
-
bool mGetHandleCalled = false;
// The inherited shadow radius after taking into account the layer hierarchy. This is the
@@ -1081,15 +603,10 @@
// Game mode for the layer. Set by WindowManagerShell and recorded by SurfaceFlingerStats.
gui::GameMode mGameMode = gui::GameMode::Unsupported;
- // A list of regions on this layer that should have blurs.
- const std::vector<BlurRegion> getBlurRegions() const;
-
bool mIsAtRoot = false;
uint32_t mLayerCreationFlags;
- bool findInHierarchy(const sp<Layer>&);
-
void releasePreviousBuffer();
void resetDrawingStateBufferInfo();
@@ -1122,10 +639,7 @@
// not specify a destination frame.
ui::Transform mRequestedTransform;
- sp<LayerFE> mLegacyLayerFE;
std::vector<std::pair<frontend::LayerHierarchy::TraversalPath, sp<LayerFE>>> mLayerFEs;
- std::unique_ptr<frontend::LayerSnapshot> mSnapshot =
- std::make_unique<frontend::LayerSnapshot>();
bool mHandleAlive = false;
};
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 885c3d3..5eea45b 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -178,7 +178,7 @@
}
void LayerProtoHelper::writeToProto(
- const WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+ const WindowInfo& inputInfo,
std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto) {
if (inputInfo.token == nullptr) {
return;
@@ -208,13 +208,6 @@
proto->set_global_scale_factor(inputInfo.globalScaleFactor);
LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform());
proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop);
- auto cropLayer = touchableRegionBounds.promote();
- if (cropLayer != nullptr) {
- proto->set_crop_layer_id(cropLayer->sequence);
- LayerProtoHelper::writeToProto(cropLayer->getScreenBounds(
- false /* reduceTransparentRegion */),
- [&]() { return proto->mutable_touchable_region_crop(); });
- }
}
void LayerProtoHelper::writeToProto(const mat4 matrix,
@@ -482,7 +475,7 @@
layerInfo->set_owner_uid(requestedState.ownerUid.val());
if ((traceFlags & LayerTracing::TRACE_INPUT) && snapshot.hasInputInfo()) {
- LayerProtoHelper::writeToProto(snapshot.inputInfo, {},
+ LayerProtoHelper::writeToProto(snapshot.inputInfo,
[&]() { return layerInfo->mutable_input_window_info(); });
}
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index c0198b6..41ea684 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -62,7 +62,7 @@
const renderengine::ExternalTexture& buffer,
std::function<perfetto::protos::ActiveBufferProto*()> getActiveBufferProto);
static void writeToProto(
- const gui::WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+ const gui::WindowInfo& inputInfo,
std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto);
static void writeToProto(const mat4 matrix,
perfetto::protos::ColorTransformProto* colorTransformProto);
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index ff0a955..13e054e 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -45,16 +45,6 @@
const auto& lState = l->getDrawingState();
const auto& rState = r->getDrawingState();
- const auto ls = lState.layerStack;
- const auto rs = rState.layerStack;
- if (ls != rs)
- return (ls > rs) ? 1 : -1;
-
- int32_t lz = lState.z;
- int32_t rz = rState.z;
- if (lz != rz)
- return (lz > rz) ? 1 : -1;
-
if (l->sequence == r->sequence)
return 0;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 034e467..aa66ccf 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -39,21 +39,6 @@
mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill) {}
- static std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> fromTraverseLayersLambda(
- std::function<void(const LayerVector::Visitor&)> traverseLayers) {
- return [traverseLayers = std::move(traverseLayers)]() {
- std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
- traverseLayers([&](Layer* layer) {
- // Layer::prepareClientComposition uses the layer's snapshot to populate the
- // resulting LayerSettings. Calling Layer::updateSnapshot ensures that LayerSettings
- // are generated with the layer's current buffer and geometry.
- layer->updateSnapshot(true /* updateGeometry */);
- layers.emplace_back(layer, layer->copyCompositionEngineLayerFE());
- });
- return layers;
- };
- }
-
virtual ~RenderArea() = default;
// Returns true if the render area is secure. A secure layer should be
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index d31fcea..218c56e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -320,7 +320,8 @@
mVsyncRegistration.update({.workDuration = mWorkDuration.get().count(),
.readyDuration = mReadyDuration.count(),
- .lastVsync = mLastVsyncCallbackTime.ns()});
+ .lastVsync = mLastVsyncCallbackTime.ns(),
+ .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
}
sp<EventThreadConnection> EventThread::createEventConnection(
@@ -527,10 +528,11 @@
}
if (mState == State::VSync) {
- const auto scheduleResult =
- mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
- .readyDuration = mReadyDuration.count(),
- .lastVsync = mLastVsyncCallbackTime.ns()});
+ const auto scheduleResult = mVsyncRegistration.schedule(
+ {.workDuration = mWorkDuration.get().count(),
+ .readyDuration = mReadyDuration.count(),
+ .lastVsync = mLastVsyncCallbackTime.ns(),
+ .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
LOG_ALWAYS_FATAL_IF(!scheduleResult, "Error scheduling callback");
} else {
mVsyncRegistration.cancel();
@@ -725,8 +727,9 @@
}
if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC &&
FlagManager::getInstance().vrr_config()) {
- mCallback.onExpectedPresentTimePosted(
- TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime()));
+ mLastCommittedVsyncTime =
+ TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime());
+ mCallback.onExpectedPresentTimePosted(mLastCommittedVsyncTime);
}
}
@@ -744,9 +747,12 @@
const auto relativeLastCallTime =
ticks<std::milli, float>(mLastVsyncCallbackTime - TimePoint::now());
+ const auto relativeLastCommittedTime =
+ ticks<std::milli, float>(mLastCommittedVsyncTime - TimePoint::now());
StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
mWorkDuration.get().count() / 1e6f, mReadyDuration.count() / 1e6f);
StringAppendF(&result, "%.2fms relative to now\n", relativeLastCallTime);
+ StringAppendF(&result, " with vsync committed at %.2fms", relativeLastCommittedTime);
StringAppendF(&result, " pending events (count=%zu):\n", mPendingEvents.size());
for (const auto& event : mPendingEvents) {
@@ -794,7 +800,8 @@
if (reschedule) {
mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
.readyDuration = mReadyDuration.count(),
- .lastVsync = mLastVsyncCallbackTime.ns()});
+ .lastVsync = mLastVsyncCallbackTime.ns(),
+ .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
}
return oldRegistration;
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index f772126..bbe4f9d 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -220,6 +220,7 @@
std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex);
std::shared_ptr<scheduler::VsyncSchedule> mVsyncSchedule GUARDED_BY(mMutex);
TimePoint mLastVsyncCallbackTime GUARDED_BY(mMutex) = TimePoint::now();
+ TimePoint mLastCommittedVsyncTime GUARDED_BY(mMutex) = TimePoint::now();
scheduler::VSyncCallbackRegistration mVsyncRegistration GUARDED_BY(mMutex);
frametimeline::TokenManager* const mTokenManager;
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index dbc458c..ff1926e 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -595,8 +595,7 @@
return true;
}
- if (FlagManager::getInstance().view_set_requested_frame_rate_mrr() &&
- category == FrameRateCategory::NoPreference && vote.rate.isValid() &&
+ if (category == FrameRateCategory::NoPreference && vote.rate.isValid() &&
vote.type == FrameRateCompatibility::ExactOrMultiple) {
return true;
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 9f6eab2..28fa036 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -841,7 +841,8 @@
return score.overallScore == 0;
});
- if (policy->primaryRangeIsSingleRate()) {
+ // TODO(b/364651864): Evaluate correctness of primaryRangeIsSingleRate.
+ if (!mIsVrrDevice.load() && policy->primaryRangeIsSingleRate()) {
// If we never scored any layers, then choose the rate from the primary
// range instead of picking a random score from the app range.
if (noLayerScore) {
@@ -887,8 +888,8 @@
const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
using fps_approx_ops::operator<;
- if (scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) {
- ALOGV("Touch Boost");
+ if (scores.front().frameRateMode.fps <= touchRefreshRates.front().frameRateMode.fps) {
+ ALOGV("Touch Boost [late]");
SFTRACE_FORMAT_INSTANT("%s (Touch Boost [late])",
to_string(touchRefreshRates.front().frameRateMode.fps).c_str());
return {touchRefreshRates, GlobalSignals{.touch = true}};
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 0c43ffb..8993c38 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -93,6 +93,8 @@
* readyDuration will typically be 0.
* @lastVsync: The targeted display time. This will be snapped to the closest
* predicted vsync time after lastVsync.
+ * @committedVsyncOpt: The display time that is committed to the callback as the
+ * target vsync time.
*
* callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync
* event.
@@ -101,10 +103,11 @@
nsecs_t workDuration = 0;
nsecs_t readyDuration = 0;
nsecs_t lastVsync = 0;
+ std::optional<nsecs_t> committedVsyncOpt;
bool operator==(const ScheduleTiming& other) const {
return workDuration == other.workDuration && readyDuration == other.readyDuration &&
- lastVsync == other.lastVsync;
+ lastVsync == other.lastVsync && committedVsyncOpt == other.committedVsyncOpt;
}
bool operator!=(const ScheduleTiming& other) const { return !(*this == other); }
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 900bce0..1925f11 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -103,7 +103,8 @@
tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
now + timing.workDuration +
timing.readyDuration),
- timing.lastVsync);
+ timing.committedVsyncOpt.value_or(
+ timing.lastVsync));
auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
bool const wouldSkipAVsyncTarget =
@@ -208,9 +209,12 @@
const auto workDelta = mWorkloadUpdateInfo->workDuration - mScheduleTiming.workDuration;
const auto readyDelta = mWorkloadUpdateInfo->readyDuration - mScheduleTiming.readyDuration;
const auto lastVsyncDelta = mWorkloadUpdateInfo->lastVsync - mScheduleTiming.lastVsync;
+ const auto lastCommittedVsyncDelta =
+ mWorkloadUpdateInfo->committedVsyncOpt.value_or(mWorkloadUpdateInfo->lastVsync) -
+ mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync);
SFTRACE_FORMAT_INSTANT("Workload updated workDelta=%" PRId64 " readyDelta=%" PRId64
- " lastVsyncDelta=%" PRId64,
- workDelta, readyDelta, lastVsyncDelta);
+ " lastVsyncDelta=%" PRId64 " committedVsyncDelta=%" PRId64,
+ workDelta, readyDelta, lastVsyncDelta, lastCommittedVsyncDelta);
mScheduleTiming = *mWorkloadUpdateInfo;
mWorkloadUpdateInfo.reset();
}
@@ -261,10 +265,14 @@
StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
mRunning ? "(in callback function)" : "", armedInfo.c_str());
StringAppendF(&result,
- "\t\t\tworkDuration: %.2fms readyDuration: %.2fms lastVsync: %.2fms relative "
- "to now\n",
+ "\t\t\tworkDuration: %.2fms readyDuration: %.2fms "
+ "lastVsync: %.2fms relative to now "
+ "committedVsync: %.2fms relative to now\n",
mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
- (mScheduleTiming.lastVsync - systemTime()) / 1e6f);
+ (mScheduleTiming.lastVsync - systemTime()) / 1e6f,
+ (mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync) -
+ systemTime()) /
+ 1e6f);
if (mLastDispatchTime) {
StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 4a7cff5..6e36f02 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -695,9 +695,12 @@
if (lastFrameMissed) {
// If the last frame missed is the last vsync, we already shifted the timeline. Depends
// on whether we skipped the frame (onFrameMissed) or not (onFrameBegin) we apply a
- // different fixup. There is no need to to shift the vsync timeline again.
- vsyncTime += missedVsync.fixup.ns();
- SFTRACE_FORMAT_INSTANT("lastFrameMissed");
+ // different fixup if we are violating the minFramePeriod.
+ // There is no need to shift the vsync timeline again.
+ if (vsyncTime - missedVsync.vsync.ns() < minFramePeriodOpt->ns()) {
+ vsyncTime += missedVsync.fixup.ns();
+ SFTRACE_FORMAT_INSTANT("lastFrameMissed");
+ }
} else if (mightBackpressure && lastVsyncOpt) {
if (!FlagManager::getInstance().vrr_bugfix_24q4()) {
// lastVsyncOpt does not need to be corrected with the new rate, and
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f4bff8f..e98dc5c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -532,9 +532,6 @@
mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
// These are set by the HWC implementation to indicate that they will use the workarounds.
- mIsHotplugErrViaNegVsync =
- base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false);
-
mIsHdcpViaNegVsync = base::GetBoolProperty("debug.sf.hwc_hdcp_via_neg_vsync"s, false);
}
@@ -2172,21 +2169,13 @@
std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
if (FlagManager::getInstance().connected_display() && timestamp < 0 &&
vsyncPeriod.has_value()) {
- // use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32
- if (mIsHotplugErrViaNegVsync && vsyncPeriod.value() == ~0) {
- const auto errorCode = static_cast<int32_t>(-timestamp);
- ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId);
- mScheduler->dispatchHotplugError(errorCode);
- return;
- }
-
if (mIsHdcpViaNegVsync && vsyncPeriod.value() == ~1) {
const int32_t value = static_cast<int32_t>(-timestamp);
// one byte is good enough to encode android.hardware.drm.HdcpLevel
const int32_t maxLevel = (value >> 8) & 0xFF;
const int32_t connectedLevel = value & 0xFF;
- ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for display %" PRIu64, __func__,
- connectedLevel, maxLevel, hwcDisplayId);
+ ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for hwcDisplayId %" PRIu64,
+ __func__, connectedLevel, maxLevel, hwcDisplayId);
updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel);
return;
}
@@ -2226,7 +2215,7 @@
if (FlagManager::getInstance().hotplug2()) {
// TODO(b/311403559): use enum type instead of int
const auto errorCode = static_cast<int32_t>(event);
- ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId);
+ ALOGD("%s: Hotplug error %d for hwcDisplayId %" PRIu64, __func__, errorCode, hwcDisplayId);
mScheduler->dispatchHotplugError(errorCode);
}
}
@@ -2276,6 +2265,18 @@
}));
}
+void SurfaceFlinger::onComposerHalHdcpLevelsChanged(hal::HWDisplayId hwcDisplayId,
+ const HdcpLevels& levels) {
+ if (FlagManager::getInstance().hdcp_level_hal()) {
+ // TODO(b/362270040): propagate enum constants
+ const int32_t maxLevel = static_cast<int32_t>(levels.maxLevel);
+ const int32_t connectedLevel = static_cast<int32_t>(levels.connectedLevel);
+ ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for hwcDisplayId %" PRIu64, __func__,
+ connectedLevel, maxLevel, hwcDisplayId);
+ updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel);
+ }
+}
+
void SurfaceFlinger::configure() {
Mutex::Autolock lock(mStateLock);
if (configureLocked()) {
@@ -2738,7 +2739,8 @@
if (!FlagManager::getInstance().ce_fence_promise()) {
refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
for (auto& [layer, _] : mLayersWithQueuedFrames) {
- if (const auto& layerFE = layer->getCompositionEngineLayerFE())
+ if (const auto& layerFE = layer->getCompositionEngineLayerFE(
+ {static_cast<uint32_t>(layer->sequence)}))
refreshArgs.layersWithQueuedFrames.push_back(layerFE);
}
}
@@ -2814,7 +2816,8 @@
refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
for (auto& [layer, _] : mLayersWithQueuedFrames) {
- if (const auto& layerFE = layer->getCompositionEngineLayerFE()) {
+ if (const auto& layerFE = layer->getCompositionEngineLayerFE(
+ {static_cast<uint32_t>(layer->sequence)})) {
refreshArgs.layersWithQueuedFrames.push_back(layerFE);
// Some layers are not displayed and do not yet have a future release fence
if (layerFE->getReleaseFencePromiseStatus() ==
@@ -3910,7 +3913,6 @@
// Commit display transactions.
const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
mFrontEndDisplayInfosChanged = displayTransactionNeeded;
- mForceTransactionDisplayChange = displayTransactionNeeded;
if (mSomeChildrenChanged) {
mVisibleRegionsDirty = true;
@@ -4231,6 +4233,8 @@
if (data.hintStatus.compare_exchange_strong(scheduleHintOnTx,
NotifyExpectedPresentHintStatus::Sent)) {
sendHint();
+ constexpr bool kAllowToEnable = true;
+ mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable);
}
}));
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 414088e..7e137c8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -135,6 +135,7 @@
class ScreenCapturer;
class WindowInfosListenerInvoker;
+using ::aidl::android::hardware::drm::HdcpLevels;
using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
using frontend::TransactionHandler;
@@ -671,6 +672,7 @@
void onComposerHalSeamlessPossible(hal::HWDisplayId) override;
void onComposerHalVsyncIdle(hal::HWDisplayId) override;
void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) override;
+ void onComposerHalHdcpLevelsChanged(hal::HWDisplayId, const HdcpLevels& levels) override;
// ICompositor overrides:
void configure() override REQUIRES(kMainThreadContext);
@@ -1228,7 +1230,6 @@
// TODO: Also move visibleRegions over to a boolean system.
bool mUpdateInputInfo = false;
bool mSomeChildrenChanged;
- bool mForceTransactionDisplayChange = false;
bool mUpdateAttachedChoreographer = false;
struct LayerIntHash {
@@ -1259,7 +1260,6 @@
};
bool mIsHdcpViaNegVsync = false;
- bool mIsHotplugErrViaNegVsync = false;
std::mutex mHotplugMutex;
std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex);
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 8ec908f..82aa557 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -119,7 +119,6 @@
DUMP_READ_ONLY_FLAG(connected_display);
DUMP_READ_ONLY_FLAG(enable_small_area_detection);
DUMP_READ_ONLY_FLAG(frame_rate_category_mrr);
- DUMP_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr);
DUMP_READ_ONLY_FLAG(misc1);
DUMP_READ_ONLY_FLAG(vrr_config);
DUMP_READ_ONLY_FLAG(hotplug2);
@@ -224,8 +223,6 @@
FLAG_MANAGER_READ_ONLY_FLAG(connected_display, "")
FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "")
FLAG_MANAGER_READ_ONLY_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr")
-FLAG_MANAGER_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr,
- "debug.sf.view_set_requested_frame_rate_mrr")
FLAG_MANAGER_READ_ONLY_FLAG(misc1, "")
FLAG_MANAGER_READ_ONLY_FLAG(vrr_config, "debug.sf.enable_vrr_config")
FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 473e564..6619975 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -56,7 +56,6 @@
/// Trunk stable readonly flags ///
bool connected_display() const;
bool frame_rate_category_mrr() const;
- bool view_set_requested_frame_rate_mrr() const;
bool enable_small_area_detection() const;
bool misc1() const;
bool vrr_config() const;
diff --git a/services/surfaceflinger/tests/OWNERS b/services/surfaceflinger/tests/OWNERS
index 56f2f1b..7857961 100644
--- a/services/surfaceflinger/tests/OWNERS
+++ b/services/surfaceflinger/tests/OWNERS
@@ -4,5 +4,5 @@
per-file Layer* = set noparent
per-file Layer* = pdwilliams@google.com, vishnun@google.com, melodymhsu@google.com
-per-file LayerHistoryTest.cpp = file:/services/surfaceflinger/OWNERS
+per-file LayerHistoryIntegrationTest.cpp = file:/services/surfaceflinger/OWNERS
per-file LayerInfoTest.cpp = file:/services/surfaceflinger/OWNERS
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index 3104dd4..ae380ad 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -515,6 +515,23 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setEdgeExtensionEffect(uint32_t id, int edge) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.what |= layer_state_t::eEdgeExtensionChanged;
+ transactions.back().states.front().state.edgeExtensionParameters =
+ gui::EdgeExtensionParameters();
+ transactions.back().states.front().state.edgeExtensionParameters.extendLeft = edge & LEFT;
+ transactions.back().states.front().state.edgeExtensionParameters.extendRight = edge & RIGHT;
+ transactions.back().states.front().state.edgeExtensionParameters.extendTop = edge & TOP;
+ transactions.back().states.front().state.edgeExtensionParameters.extendBottom =
+ edge & BOTTOM;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
private:
LayerLifecycleManager& mLifecycleManager;
};
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 2cff2f2..6030427 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -58,6 +58,7 @@
using Hwc2::Config;
+using ::aidl::android::hardware::drm::HdcpLevels;
using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
using hal::IComposerClient;
@@ -454,6 +455,8 @@
MOCK_METHOD1(onComposerHalSeamlessPossible, void(hal::HWDisplayId));
MOCK_METHOD1(onComposerHalVsyncIdle, void(hal::HWDisplayId));
MOCK_METHOD(void, onRefreshRateChangedDebug, (const RefreshRateChangedDebugData&), (override));
+ MOCK_METHOD(void, onComposerHalHdcpLevelsChanged, (hal::HWDisplayId, const HdcpLevels&),
+ (override));
};
struct HWComposerSetCallbackTest : HWComposerTest {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
index 7e84408..de37b63 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -894,7 +894,6 @@
TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithFixedSourceAndNoPreferenceCategory) {
SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false);
- SET_FLAG_FOR_TEST(flags::view_set_requested_frame_rate_mrr, true);
auto layer = createLegacyAndFrontedEndLayer(1);
setFrameRate(1, (45.6_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 2860345..9020723 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -27,6 +27,7 @@
#include "LayerHierarchyTest.h"
#include "ui/GraphicTypes.h"
+#include <com_android_graphics_libgui_flags.h>
#include <com_android_graphics_surfaceflinger_flags.h>
#define UPDATE_AND_VERIFY(BUILDER, ...) \
@@ -1761,4 +1762,162 @@
UPDATE_AND_VERIFY(mSnapshotBuilder, {2});
EXPECT_TRUE(getSnapshot(1)->isHiddenByPolicy());
}
+TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) {
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ setCrop(1, Rect(0, 0, 20, 20));
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(20 /* width */,
+ 20 /* height */,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ setEdgeExtensionEffect(12, LEFT);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(LEFT));
+ EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(LEFT));
+ EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(LEFT));
+
+ setEdgeExtensionEffect(12, RIGHT);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(RIGHT));
+ EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(RIGHT));
+ EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(RIGHT));
+
+ setEdgeExtensionEffect(12, TOP);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(TOP));
+ EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(TOP));
+ EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(TOP));
+
+ setEdgeExtensionEffect(12, BOTTOM);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(BOTTOM));
+ EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(BOTTOM));
+ EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(BOTTOM));
+}
+
+TEST_F(LayerSnapshotTest, leftEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The left bound is extended when shifting to the right
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ setCrop(1, Rect(0, 0, 20, 20));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = 5.0;
+ setPosition(12, translation, 0);
+ setEdgeExtensionEffect(12, LEFT);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+ EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.left, translation);
+ EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.left, 0.0);
+}
+
+TEST_F(LayerSnapshotTest, rightEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The right bound is extended when shifting to the left
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ const int crop = 20;
+ setCrop(1, Rect(0, 0, crop, crop));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = -5.0;
+ setPosition(12, translation, 0);
+ setEdgeExtensionEffect(12, RIGHT);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.left, 0);
+ EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+ EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.right, (float)crop);
+}
+
+TEST_F(LayerSnapshotTest, topEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The top bound is extended when shifting to the bottom
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ setCrop(1, Rect(0, 0, 20, 20));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = 5.0;
+ setPosition(12, 0, translation);
+ setEdgeExtensionEffect(12, TOP);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize + translation);
+ EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.top, translation);
+ EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0.0);
+}
+
+TEST_F(LayerSnapshotTest, bottomEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The bottom bound is extended when shifting to the top
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ const int crop = 20;
+ setCrop(1, Rect(0, 0, crop, crop));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = -5.0;
+ setPosition(12, 0, translation);
+ setEdgeExtensionEffect(12, BOTTOM);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.top, 0);
+ EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize - translation);
+ EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.bottom, (float)crop);
+}
+
+TEST_F(LayerSnapshotTest, multipleEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The left bound is extended when shifting to the right
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ const int crop = 20;
+ setCrop(1, Rect(0, 0, crop, crop));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = 5.0;
+ setPosition(12, translation, translation);
+ setEdgeExtensionEffect(12, LEFT | RIGHT | TOP | BOTTOM);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+ EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.right, (float)crop);
+ EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.left, translation);
+ EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.left, 0.0);
+ EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize + translation);
+ EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.bottom, (float)crop);
+ EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.top, translation);
+ EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 06c4e30..9efe73d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1837,6 +1837,43 @@
}
}
+TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_vrrHighHintTouch_primaryRangeIsSingleRate) {
+ if (GetParam() != Config::FrameRateOverride::Enabled) {
+ return;
+ }
+
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+ auto selector = createSelector(kVrrMode_120, kModeId120);
+ selector.setActiveMode(kModeId120, 60_Hz);
+
+ // Change primary physical range to be single rate, which on VRR device should not affect
+ // fps scoring.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}}));
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+ layers[0].vote = LayerVoteType::ExplicitCategory;
+ layers[0].frameRateCategory = FrameRateCategory::HighHint;
+ layers[0].name = "ExplicitCategory HighHint";
+
+ auto actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ // Expect late touch boost from HighHint.
+ EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+ EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
+
+ layers[1].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[1].desiredRefreshRate = 30_Hz;
+ layers[1].name = "ExplicitExactOrMultiple 30Hz";
+
+ actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ // Expect late touch boost from HighHint.
+ EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+ EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
+}
+
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighHint) {
auto selector = createSelector(makeModes(kMode24, kMode30, kMode60, kMode120), kModeId60);
@@ -1955,7 +1992,7 @@
// Gets touch boost
EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
- EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
}
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_TouchBoost) {
@@ -2049,7 +2086,7 @@
lr2.name = "Max";
actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true});
EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, actualRankedFrameRates.ranking.front().frameRateMode);
- EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitCategory;
lr1.frameRateCategory = FrameRateCategory::Normal;
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 710b5cc..22d7b24 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -335,13 +335,6 @@
return mFlinger->mLegacyLayers[layerId]->findOutputLayerForDisplay(display.get());
}
- static void setLayerSidebandStream(const sp<Layer>& layer,
- const sp<NativeHandle>& sidebandStream) {
- layer->mDrawingState.sidebandStream = sidebandStream;
- layer->mSidebandStream = sidebandStream;
- layer->editLayerSnapshot()->sidebandStream = sidebandStream;
- }
-
void setLayerCompositionType(const sp<Layer>& layer,
aidl::android::hardware::graphics::composer3::Composition type) {
auto outputLayer = findOutputLayerForDisplay(static_cast<uint32_t>(layer->sequence),
@@ -352,10 +345,6 @@
(*state.hwc).hwcCompositionType = type;
}
- static void setLayerDrawingParent(const sp<Layer>& layer, const sp<Layer>& drawingParent) {
- layer->mDrawingParent = drawingParent;
- }
-
/* ------------------------------------------------------------------------
* Forwarding for functions being tested
*/
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 7c678bd..918107d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -915,7 +915,8 @@
vrrTracker.onFrameBegin(TimePoint::fromNs(7000),
{TimePoint::fromNs(6500), TimePoint::fromNs(6500)});
- EXPECT_EQ(10500, vrrTracker.nextAnticipatedVSyncTimeFrom(9000, 7000));
+ EXPECT_EQ(8500, vrrTracker.nextAnticipatedVSyncTimeFrom(8000, 7000));
+ EXPECT_EQ(9500, vrrTracker.nextAnticipatedVSyncTimeFrom(9000, 7000));
}
TEST_F(VSyncPredictorTest, adjustsVrrTimelineTwoClients) {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index fdb6f4d..45f86fa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -31,15 +31,11 @@
explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
- MOCK_CONST_METHOD0(getType, const char*());
MOCK_METHOD0(getFrameSelectionPriority, int32_t());
- MOCK_CONST_METHOD0(isVisible, bool());
MOCK_METHOD0(createClone, sp<Layer>());
MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, scheduler::FrameRateCompatibility());
MOCK_CONST_METHOD0(getOwnerUid, uid_t());
- MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace());
- MOCK_METHOD(bool, isFrontBuffered, (), (const, override));
};
} // namespace android::mock
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 4c4e341..879d2d0 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -27,9 +27,6 @@
symbol_file: "libvulkan.map.txt",
first_version: "24",
unversioned_until: "current",
- export_header_libs: [
- "ndk_vulkan_headers",
- ],
}
aconfig_declarations {