Merge "Draw shadows when the casting layer is occluded or transparent"
diff --git a/aidl/gui/android/view/LayerMetadataKey.aidl b/aidl/gui/android/view/LayerMetadataKey.aidl
new file mode 100644
index 0000000..7026ca8
--- /dev/null
+++ b/aidl/gui/android/view/LayerMetadataKey.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/** @hide */
+@Backing(type="int")
+enum LayerMetadataKey {
+ METADATA_OWNER_UID = 1,
+ METADATA_WINDOW_TYPE = 2,
+ METADATA_TASK_ID = 3,
+ METADATA_MOUSE_CURSOR = 4,
+}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 9d6a7ff..fc94f23 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2729,15 +2729,13 @@
DurationReporter::~DurationReporter() {
if (!title_.empty()) {
float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
- if (elapsed < .5f && !verbose_) {
- return;
+ if (elapsed >= .5f || verbose_) {
+ MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
}
- MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
- if (logcat_only_) {
- return;
+ if (!logcat_only_) {
+ // Use "Yoda grammar" to make it easier to grep|sort sections.
+ printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
}
- // Use "Yoda grammar" to make it easier to grep|sort sections.
- printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
}
}
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 141171b..ae74ac3 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -18,6 +18,9 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
#include <binder/Stability.h>
#include <cutils/android_filesystem_config.h>
#include <cutils/multiuser.h>
@@ -80,7 +83,7 @@
ServiceManager::~ServiceManager() {
// this should only happen in tests
- for (const auto& [name, callbacks] : mNameToCallback) {
+ for (const auto& [name, callbacks] : mNameToRegistrationCallback) {
CHECK(!callbacks.empty()) << name;
for (const auto& callback : callbacks) {
CHECK(callback != nullptr) << name;
@@ -108,10 +111,11 @@
auto ctx = mAccess->getCallingContext();
sp<IBinder> out;
+ Service* service = nullptr;
if (auto it = mNameToService.find(name); it != mNameToService.end()) {
- const Service& service = it->second;
+ service = &(it->second);
- if (!service.allowIsolated) {
+ if (!service->allowIsolated) {
uid_t appid = multiuser_get_app_id(ctx.uid);
bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;
@@ -119,7 +123,7 @@
return nullptr;
}
}
- out = service.binder;
+ out = service->binder;
}
if (!mAccess->canFind(ctx, name)) {
@@ -130,6 +134,12 @@
tryStartService(name);
}
+ if (out) {
+ // Setting this guarantee each time we hand out a binder ensures that the client-checking
+ // loop knows about the event even if the client immediately drops the service
+ service->guaranteeClient = true;
+ }
+
return out;
}
@@ -182,15 +192,17 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- mNameToService[name] = Service {
+ auto entry = mNameToService.emplace(name, Service {
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
- };
+ .debugPid = ctx.debugPid,
+ });
- auto it = mNameToCallback.find(name);
- if (it != mNameToCallback.end()) {
+ auto it = mNameToRegistrationCallback.find(name);
+ if (it != mNameToRegistrationCallback.end()) {
for (const sp<IServiceCallback>& cb : it->second) {
+ entry.first->second.guaranteeClient = true;
// permission checked in registerForNotifications
cb->onRegistration(name, binder);
}
@@ -247,7 +259,7 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- mNameToCallback[name].push_back(callback);
+ mNameToRegistrationCallback[name].push_back(callback);
if (auto it = mNameToService.find(name); it != mNameToService.end()) {
const sp<IBinder>& binder = it->second.binder;
@@ -269,9 +281,9 @@
bool found = false;
- auto it = mNameToCallback.find(name);
- if (it != mNameToCallback.end()) {
- removeCallback(IInterface::asBinder(callback), &it, &found);
+ auto it = mNameToRegistrationCallback.find(name);
+ if (it != mNameToRegistrationCallback.end()) {
+ removeRegistrationCallback(IInterface::asBinder(callback), &it, &found);
}
if (!found) {
@@ -297,8 +309,8 @@
return Status::ok();
}
-void ServiceManager::removeCallback(const wp<IBinder>& who,
- CallbackMap::iterator* it,
+void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
+ ServiceCallbackMap::iterator* it,
bool* found) {
std::vector<sp<IServiceCallback>>& listeners = (*it)->second;
@@ -312,7 +324,7 @@
}
if (listeners.empty()) {
- *it = mNameToCallback.erase(*it);
+ *it = mNameToRegistrationCallback.erase(*it);
} else {
(*it)++;
}
@@ -327,8 +339,12 @@
}
}
- for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) {
- removeCallback(who, &it, nullptr /*found*/);
+ for (auto it = mNameToRegistrationCallback.begin(); it != mNameToRegistrationCallback.end();) {
+ removeRegistrationCallback(who, &it, nullptr /*found*/);
+ }
+
+ for (auto it = mNameToClientCallback.begin(); it != mNameToClientCallback.end();) {
+ removeClientCallback(who, &it);
}
}
@@ -341,4 +357,183 @@
}).detach();
}
-} // namespace android
+Status ServiceManager::registerClientCallback(const std::string& name, const sp<IBinder>& service,
+ const sp<IClientCallback>& cb) {
+ if (cb == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+
+ auto ctx = mAccess->getCallingContext();
+ if (!mAccess->canAdd(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ auto serviceIt = mNameToService.find(name);
+ if (serviceIt == mNameToService.end()) {
+ LOG(ERROR) << "Could not add callback for nonexistent service: " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) {
+ LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")";
+ return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
+ }
+
+ if (serviceIt->second.binder != service) {
+ LOG(WARNING) << "Tried to register client callback for " << name
+ << " but a different service is registered under this name.";
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (OK != IInterface::asBinder(cb)->linkToDeath(this)) {
+ LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ mNameToClientCallback[name].push_back(cb);
+
+ return Status::ok();
+}
+
+void ServiceManager::removeClientCallback(const wp<IBinder>& who,
+ ClientCallbackMap::iterator* it) {
+ std::vector<sp<IClientCallback>>& listeners = (*it)->second;
+
+ for (auto lit = listeners.begin(); lit != listeners.end();) {
+ if (IInterface::asBinder(*lit) == who) {
+ lit = listeners.erase(lit);
+ } else {
+ ++lit;
+ }
+ }
+
+ if (listeners.empty()) {
+ *it = mNameToClientCallback.erase(*it);
+ } else {
+ (*it)++;
+ }
+}
+
+ssize_t ServiceManager::Service::getNodeStrongRefCount() {
+ sp<BpBinder> bpBinder = binder->remoteBinder();
+ if (bpBinder == nullptr) return -1;
+
+ return ProcessState::self()->getStrongRefCountForNodeByHandle(bpBinder->handle());
+}
+
+void ServiceManager::handleClientCallbacks() {
+ for (const auto& [name, service] : mNameToService) {
+ handleServiceClientCallback(name);
+ }
+}
+
+ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) {
+ auto serviceIt = mNameToService.find(serviceName);
+ if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) {
+ return -1;
+ }
+
+ Service& service = serviceIt->second;
+ ssize_t count = service.getNodeStrongRefCount();
+
+ // binder driver doesn't support this feature
+ if (count == -1) return count;
+
+ bool hasClients = count > 1; // this process holds a strong count
+
+ if (service.guaranteeClient) {
+ // we have no record of this client
+ if (!service.hasClients && !hasClients) {
+ sendClientCallbackNotifications(serviceName, true);
+ }
+
+ // guarantee is temporary
+ service.guaranteeClient = false;
+ }
+
+ if (hasClients && !service.hasClients) {
+ // client was retrieved in some other way
+ sendClientCallbackNotifications(serviceName, true);
+ }
+
+ // there are no more clients, but the callback has not been called yet
+ if (!hasClients && service.hasClients) {
+ sendClientCallbackNotifications(serviceName, false);
+ }
+
+ return count;
+}
+
+void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) {
+ auto serviceIt = mNameToService.find(serviceName);
+ if (serviceIt == mNameToService.end()) {
+ LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName;
+ return;
+ }
+ Service& service = serviceIt->second;
+
+ CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients
+ << " so we can't tell clients again that we have client: " << hasClients;
+
+ LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients;
+
+ auto ccIt = mNameToClientCallback.find(serviceName);
+ CHECK(ccIt != mNameToClientCallback.end())
+ << "sendClientCallbackNotifications could not find callbacks for service ";
+
+ for (const auto& callback : ccIt->second) {
+ callback->onClients(service.binder, hasClients);
+ }
+
+ service.hasClients = hasClients;
+}
+
+Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IBinder>& binder) {
+ if (binder == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+
+ auto ctx = mAccess->getCallingContext();
+ if (!mAccess->canAdd(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ auto serviceIt = mNameToService.find(name);
+ if (serviceIt == mNameToService.end()) {
+ LOG(WARNING) << "Tried to unregister " << name
+ << ", but that service wasn't registered to begin with.";
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) {
+ LOG(WARNING) << "Only a server can unregister itself (for " << name << ")";
+ return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
+ }
+
+ sp<IBinder> storedBinder = serviceIt->second.binder;
+
+ if (binder != storedBinder) {
+ LOG(WARNING) << "Tried to unregister " << name
+ << ", but a different service is registered under this name.";
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ int clients = handleServiceClientCallback(name);
+
+ // clients < 0: feature not implemented or other error. Assume clients.
+ // Otherwise:
+ // - kernel driver will hold onto one refcount (during this transaction)
+ // - servicemanager has a refcount (guaranteed by this transaction)
+ // So, if clients > 2, then at least one other service on the system must hold a refcount.
+ if (clients < 0 || clients > 2) {
+ // client callbacks are either disabled or there are other clients
+ LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ mNameToService.erase(name);
+
+ return Status::ok();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 7dcdaa4..77f5250 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -17,12 +17,14 @@
#pragma once
#include <android/os/BnServiceManager.h>
+#include <android/os/IClientCallback.h>
#include <android/os/IServiceCallback.h>
#include "Access.h"
namespace android {
+using os::IClientCallback;
using os::IServiceCallback;
class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
@@ -40,9 +42,13 @@
const sp<IServiceCallback>& callback) override;
binder::Status unregisterForNotifications(const std::string& name,
const sp<IServiceCallback>& callback) override;
- binder::Status isDeclared(const std::string& name, bool* outReturn) override;
+ binder::Status isDeclared(const std::string& name, bool* outReturn) override;
+ binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
+ const sp<IClientCallback>& cb) override;
+ binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
void binderDied(const wp<IBinder>& who) override;
+ void handleClientCallbacks();
protected:
virtual void tryStartService(const std::string& name);
@@ -52,20 +58,35 @@
sp<IBinder> binder; // not null
bool allowIsolated;
int32_t dumpPriority;
+ bool hasClients = false; // notifications sent on true -> false.
+ bool guaranteeClient = false; // forces the client check to true
+ pid_t debugPid = 0; // the process in which this service runs
+
+ // the number of clients of the service, including servicemanager itself
+ ssize_t getNodeStrongRefCount();
};
- using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>;
+ using ServiceCallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>;
+ using ClientCallbackMap = std::map<std::string, std::vector<sp<IClientCallback>>>;
using ServiceMap = std::map<std::string, Service>;
- // removes a callback from mNameToCallback, removing it if the vector is empty
+ // removes a callback from mNameToRegistrationCallback, removing it if the vector is empty
// this updates iterator to the next location
- void removeCallback(const wp<IBinder>& who,
- CallbackMap::iterator* it,
+ void removeRegistrationCallback(const wp<IBinder>& who,
+ ServiceCallbackMap::iterator* it,
bool* found);
+ ssize_t handleServiceClientCallback(const std::string& serviceName);
+ // Also updates mHasClients (of what the last callback was)
+ void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients);
+ // removes a callback from mNameToClientCallback, deleting the entry if the vector is empty
+ // this updates the iterator to the next location
+ void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it);
+
sp<IBinder> tryGetService(const std::string& name, bool startIfNotFound);
- CallbackMap mNameToCallback;
ServiceMap mNameToService;
+ ServiceCallbackMap mNameToRegistrationCallback;
+ ClientCallbackMap mNameToClientCallback;
std::unique_ptr<Access> mAccess;
};
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 4b12fc6..2618906 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -18,18 +18,101 @@
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/Status.h>
+#include <sys/timerfd.h>
+#include <utils/Looper.h>
#include <utils/StrongPointer.h>
#include "Access.h"
#include "ServiceManager.h"
using ::android::Access;
+using ::android::sp;
+using ::android::Looper;
+using ::android::LooperCallback;
+using ::android::ProcessState;
using ::android::IPCThreadState;
using ::android::ProcessState;
using ::android::ServiceManager;
using ::android::os::IServiceManager;
using ::android::sp;
+class BinderCallback : public LooperCallback {
+public:
+ static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
+ sp<BinderCallback> cb = new BinderCallback;
+
+ int binder_fd = -1;
+ IPCThreadState::self()->setupPolling(&binder_fd);
+ LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);
+
+ // Flush after setupPolling(), to make sure the binder driver
+ // knows about this thread handling commands.
+ IPCThreadState::self()->flushCommands();
+
+ int ret = looper->addFd(binder_fd,
+ Looper::POLL_CALLBACK,
+ Looper::EVENT_INPUT,
+ cb,
+ nullptr /*data*/);
+ LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");
+
+ return cb;
+ }
+
+ int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
+ IPCThreadState::self()->handlePolledCommands();
+ return 1; // Continue receiving callbacks.
+ }
+};
+
+// LooperCallback for IClientCallback
+class ClientCallbackCallback : public LooperCallback {
+public:
+ static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) {
+ sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager);
+
+ int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/);
+ LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno);
+
+ itimerspec timespec {
+ .it_interval = {
+ .tv_sec = 5,
+ .tv_nsec = 0,
+ },
+ .it_value = {
+ .tv_sec = 5,
+ .tv_nsec = 0,
+ },
+ };
+
+ int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, ×pec, nullptr);
+ LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno);
+
+ int addRes = looper->addFd(fdTimer,
+ Looper::POLL_CALLBACK,
+ Looper::EVENT_INPUT,
+ cb,
+ nullptr);
+ LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper");
+
+ return cb;
+ }
+
+ int handleEvent(int fd, int /*events*/, void* /*data*/) override {
+ uint64_t expirations;
+ int ret = read(fd, &expirations, sizeof(expirations));
+ if (ret != sizeof(expirations)) {
+ ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno);
+ }
+
+ mManager->handleClientCallbacks();
+ return 1; // Continue receiving callbacks.
+ }
+private:
+ ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {}
+ sp<ServiceManager> mManager;
+};
+
int main(int argc, char** argv) {
if (argc > 2) {
LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
@@ -49,7 +132,14 @@
IPCThreadState::self()->setTheContextObject(manager);
ps->becomeContextManager(nullptr, nullptr);
- IPCThreadState::self()->joinThreadPool();
+ sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
+
+ BinderCallback::setupTo(looper);
+ ClientCallbackCallback::setupTo(looper, manager);
+
+ while(true) {
+ looper->pollAll(-1);
+ }
// should not be reached
return EXIT_FAILURE;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 7ee4882..079dd82 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -90,6 +90,7 @@
"IResultReceiver.cpp",
"IServiceManager.cpp",
"IShellCallback.cpp",
+ "LazyServiceRegistrar.cpp",
"MemoryBase.cpp",
"MemoryDealer.cpp",
"MemoryHeapBase.cpp",
@@ -160,6 +161,7 @@
name: "libbinder_aidl",
srcs: [
"aidl/android/content/pm/IPackageManagerNative.aidl",
+ "aidl/android/os/IClientCallback.aidl",
"aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
],
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index bac8b66..5ca9156 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -271,6 +271,8 @@
std::unique_lock<std::mutex> lock(mMutex);
mBinder = binder;
lock.unlock();
+ // Flushing here helps ensure the service's ref count remains accurate
+ IPCThreadState::self()->flushCommands();
mCv.notify_one();
return Status::ok();
}
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
new file mode 100644
index 0000000..dc9482c
--- /dev/null
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlLazyServiceRegistrar"
+
+#include <binder/LazyServiceRegistrar.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <android/os/BnClientCallback.h>
+#include <android/os/IServiceManager.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace binder {
+namespace internal {
+
+using AidlServiceManager = android::os::IServiceManager;
+
+class ClientCounterCallback : public ::android::os::BnClientCallback {
+public:
+ ClientCounterCallback() : mNumConnectedServices(0) {}
+
+ bool registerService(const sp<IBinder>& service, const std::string& name,
+ bool allowIsolated, int dumpFlags);
+
+protected:
+ Status onClients(const sp<IBinder>& service, bool clients) override;
+
+private:
+ /**
+ * Unregisters all services that we can. If we can't unregister all, re-register other
+ * services.
+ */
+ void tryShutdown();
+
+ /**
+ * Counter of the number of services that currently have at least one client.
+ */
+ size_t mNumConnectedServices;
+
+ struct Service {
+ sp<IBinder> service;
+ std::string name;
+ bool allowIsolated;
+ int dumpFlags;
+ };
+ /**
+ * Number of services that have been registered.
+ */
+ std::vector<Service> mRegisteredServices;
+};
+
+bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name,
+ bool allowIsolated, int dumpFlags) {
+ auto manager = interface_cast<AidlServiceManager>(
+ ProcessState::self()->getContextObject(nullptr));
+
+ ALOGI("Registering service %s", name.c_str());
+
+ if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) {
+ ALOGE("Failed to register service %s", name.c_str());
+ return false;
+ }
+
+ if (!manager->registerClientCallback(name, service, this).isOk())
+ {
+ ALOGE("Failed to add client callback for service %s", name.c_str());
+ return false;
+ }
+
+ mRegisteredServices.push_back({service, name, allowIsolated, dumpFlags});
+
+ return true;
+}
+
+/**
+ * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple
+ * invocations could occur on different threads however.
+ */
+Status ClientCounterCallback::onClients(const sp<IBinder>& service, bool clients) {
+ if (clients) {
+ mNumConnectedServices++;
+ } else {
+ mNumConnectedServices--;
+ }
+
+ ALOGI("Process has %zu (of %zu available) client(s) in use after notification %s has clients: %d",
+ mNumConnectedServices, mRegisteredServices.size(),
+ String8(service->getInterfaceDescriptor()).string(), clients);
+
+ if (mNumConnectedServices == 0) {
+ tryShutdown();
+ }
+
+ return Status::ok();
+}
+
+void ClientCounterCallback::tryShutdown() {
+ ALOGI("Trying to shut down the service. No clients in use for any service in process.");
+
+ // This makes the same assumption as IServiceManager.cpp. Could dedupe if used in more places.
+ auto manager = interface_cast<AidlServiceManager>(
+ ProcessState::self()->getContextObject(nullptr));
+
+ auto unRegisterIt = mRegisteredServices.begin();
+ for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
+ auto& entry = (*unRegisterIt);
+
+ bool success = manager->tryUnregisterService(entry.name, entry.service).isOk();
+
+ if (!success) {
+ ALOGI("Failed to unregister service %s", entry.name.c_str());
+ break;
+ }
+ }
+
+ if (unRegisterIt == mRegisteredServices.end()) {
+ ALOGI("Unregistered all clients and exiting");
+ exit(EXIT_SUCCESS);
+ }
+
+ for (auto reRegisterIt = mRegisteredServices.begin(); reRegisterIt != unRegisterIt;
+ reRegisterIt++) {
+ auto& entry = (*reRegisterIt);
+
+ // re-register entry
+ if (!registerService(entry.service, entry.name, entry.allowIsolated, entry.dumpFlags)) {
+ // Must restart. Otherwise, clients will never be able to get a hold of this service.
+ ALOGE("Bad state: could not re-register services");
+ }
+ }
+}
+
+} // namespace internal
+
+LazyServiceRegistrar::LazyServiceRegistrar() {
+ mClientCC = std::make_shared<internal::ClientCounterCallback>();
+}
+
+LazyServiceRegistrar& LazyServiceRegistrar::getInstance() {
+ static auto registrarInstance = new LazyServiceRegistrar();
+ return *registrarInstance;
+}
+
+status_t LazyServiceRegistrar::registerService(const sp<IBinder>& service, const std::string& name,
+ bool allowIsolated, int dumpFlags) {
+ if (!mClientCC->registerService(service, name, allowIsolated, dumpFlags)) {
+ return UNKNOWN_ERROR;
+ }
+ return OK;
+}
+
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/aidl/android/os/IClientCallback.aidl b/libs/binder/aidl/android/os/IClientCallback.aidl
new file mode 100644
index 0000000..36d7ee6
--- /dev/null
+++ b/libs/binder/aidl/android/os/IClientCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * @hide
+ */
+oneway interface IClientCallback {
+ /**
+ * This is called when there is a transition between having >= 1 clients and having 0 clients
+ * (or vice versa).
+ *
+ * Upon receiving hasClients false, if the process decides to exit, it is recommended to try to
+ * unregister using IServiceManager's tryUnregister before quitting in case another client
+ * associates.
+ *
+ * @param registered binder 'server' registered with IServiceManager's registerClientCallback
+ * @param hasClients whether there are currently clients
+ * true - when there are >= 1 clients. This must be called as soon as IServiceManager::get
+ * is called (no race).
+ * false - when there are 0 clients. This may be delayed if it is thought that another
+ * may be used again soon.
+ */
+ void onClients(IBinder registered, boolean hasClients);
+}
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index b965881..ff15460 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -16,6 +16,7 @@
package android.os;
+import android.os.IClientCallback;
import android.os.IServiceCallback;
/**
@@ -96,4 +97,15 @@
* manifest.
*/
boolean isDeclared(@utf8InCpp String name);
+
+ /**
+ * Request a callback when the number of clients of the service changes.
+ * Used by LazyServiceRegistrar to dynamically stop services that have no clients.
+ */
+ void registerClientCallback(@utf8InCpp String name, IBinder service, IClientCallback callback);
+
+ /**
+ * Attempt to unregister and remove a service. Will fail if the service is still in use.
+ */
+ void tryUnregisterService(@utf8InCpp String name, IBinder service);
}
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
new file mode 100644
index 0000000..efdecc4
--- /dev/null
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace binder {
+namespace internal {
+class ClientCounterCallback;
+} // namespace internal
+
+/** Exits when all services registered through this object have 0 clients */
+class LazyServiceRegistrar {
+ public:
+ static LazyServiceRegistrar& getInstance();
+ status_t registerService(const sp<IBinder>& service,
+ const std::string& name = "default",
+ bool allowIsolated = false,
+ int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+
+ private:
+ std::shared_ptr<internal::ClientCounterCallback> mClientCC;
+ LazyServiceRegistrar();
+};
+
+} // namespace binder
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 1ae148c..5959340 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -40,6 +40,7 @@
defaults: ["libgui_bufferqueue-defaults"],
srcs: [
+ ":framework_native_aidl",
":libgui_bufferqueue_sources",
"BitTube.cpp",
@@ -106,6 +107,10 @@
"libdvr_headers",
"libpdx_headers",
],
+
+ aidl: {
+ export_aidl_headers: true,
+ }
}
// Used by media codec services exclusively as a static lib for
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 3a7cb44..6418e8c 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -44,6 +44,28 @@
namespace android {
+// Macros for include BufferQueueCore information in log messages
+#define BQ_LOGV(x, ...) \
+ ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+#define BQ_LOGD(x, ...) \
+ ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+#define BQ_LOGI(x, ...) \
+ ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+#define BQ_LOGW(x, ...) \
+ ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+#define BQ_LOGE(x, ...) \
+ ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
mCore(core),
mSlots(core->mSlots),
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index d6009d6..3b0120b 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -42,6 +42,23 @@
namespace android {
+// Macros for include BufferQueueCore information in log messages
+#define BQ_LOGV(x, ...) \
+ ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
+#define BQ_LOGD(x, ...) \
+ ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
+#define BQ_LOGI(x, ...) \
+ ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
+#define BQ_LOGW(x, ...) \
+ ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
+#define BQ_LOGE(x, ...) \
+ ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
+
static String8 getUniqueName() {
static volatile int32_t counter = 0;
return String8::format("unnamed-%d-%d", getpid(),
@@ -54,6 +71,19 @@
return id | counter++;
}
+static status_t getProcessName(int pid, String8& name) {
+ FILE* fp = fopen(String8::format("/proc/%d/cmdline", pid), "r");
+ if (NULL != fp) {
+ const size_t size = 64;
+ char proc_name[size];
+ fgets(proc_name, size, fp);
+ fclose(fp);
+ name = proc_name;
+ return NO_ERROR;
+ }
+ return INVALID_OPERATION;
+}
+
BufferQueueCore::BufferQueueCore() :
mMutex(),
mIsAbandoned(false),
@@ -132,6 +162,20 @@
mTransformHintInUse, mAutoPrerotation);
outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size());
+
+ outResult->appendFormat("%s(mConsumerName=%s, ", prefix.string(), mConsumerName.string());
+
+ outResult->appendFormat("mConnectedApi=%d, mConsumerUsageBits=%" PRIu64 ", ", mConnectedApi,
+ mConsumerUsageBits);
+
+ String8 producerProcName = String8("\?\?\?");
+ String8 consumerProcName = String8("\?\?\?");
+ int32_t pid = getpid();
+ getProcessName(mConnectedPid, producerProcName);
+ getProcessName(pid, consumerProcName);
+ outResult->appendFormat("mId=%" PRIx64 ", producer=[%d:%s], consumer=[%d:%s])\n", mUniqueId,
+ mConnectedPid, producerProcName.string(), pid,
+ consumerProcName.string());
Fifo::const_iterator current(mQueue.begin());
while (current != mQueue.end()) {
double timestamp = current->mTimestamp / 1e9;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index a159f85..e6df757 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -44,6 +44,28 @@
namespace android {
+// Macros for include BufferQueueCore information in log messages
+#define BQ_LOGV(x, ...) \
+ ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+#define BQ_LOGD(x, ...) \
+ ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+#define BQ_LOGI(x, ...) \
+ ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+#define BQ_LOGW(x, ...) \
+ ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+#define BQ_LOGE(x, ...) \
+ ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
+ ##__VA_ARGS__)
+
static constexpr uint32_t BQ_LAYER_COUNT = 1;
BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 546757b..ab4d51e 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -525,6 +525,88 @@
return static_cast<status_t>(reply.readInt32());
}
+ virtual status_t getAutoLowLatencyModeSupport(const sp<IBinder>& display,
+ bool* outSupport) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ status_t result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("getAutoLowLatencyModeSupport failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::GET_AUTO_LOW_LATENCY_MODE_SUPPORT, data,
+ &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getAutoLowLatencyModeSupport failed to transact: %d", result);
+ return result;
+ }
+ return reply.readBool(outSupport);
+ }
+
+ virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("setAutoLowLatencyMode failed to writeInterfaceToken: %d", result);
+ return;
+ }
+
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("setAutoLowLatencyMode failed to writeStrongBinder: %d", result);
+ return;
+ }
+ result = data.writeBool(on);
+ if (result != NO_ERROR) {
+ ALOGE("setAutoLowLatencyMode failed to writeBool: %d", result);
+ return;
+ }
+ result = remote()->transact(BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("setAutoLowLatencyMode failed to transact: %d", result);
+ return;
+ }
+ }
+
+ virtual status_t getGameContentTypeSupport(const sp<IBinder>& display, bool* outSupport) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ status_t result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("getGameContentTypeSupport failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::GET_GAME_CONTENT_TYPE_SUPPORT, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getGameContentTypeSupport failed to transact: %d", result);
+ return result;
+ }
+ return reply.readBool(outSupport);
+ }
+
+ virtual void setGameContentType(const sp<IBinder>& display, bool on) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("setGameContentType failed to writeInterfaceToken: %d", result);
+ return;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("setGameContentType failed to writeStrongBinder: %d", result);
+ return;
+ }
+ result = data.writeBool(on);
+ if (result != NO_ERROR) {
+ ALOGE("setGameContentType failed to writeBool: %d", result);
+ return;
+ }
+ result = remote()->transact(BnSurfaceComposer::SET_GAME_CONTENT_TYPE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("setGameContentType failed to transact: %d", result);
+ }
+ }
+
virtual status_t clearAnimationFrameStats() {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -852,61 +934,8 @@
return error;
}
- virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- const std::vector<int32_t>& allowedConfigs) {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setAllowedDisplayConfigs failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(displayToken);
- if (result != NO_ERROR) {
- ALOGE("setAllowedDisplayConfigs failed to writeStrongBinder: %d", result);
- return result;
- }
- result = data.writeInt32Vector(allowedConfigs);
- if (result != NO_ERROR) {
- ALOGE("setAllowedDisplayConfigs failed to writeInt32Vector: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::SET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setAllowedDisplayConfigs failed to transact: %d", result);
- return result;
- }
- return reply.readInt32();
- }
-
- virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- std::vector<int32_t>* outAllowedConfigs) {
- if (!outAllowedConfigs) return BAD_VALUE;
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("getAllowedDisplayConfigs failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(displayToken);
- if (result != NO_ERROR) {
- ALOGE("getAllowedDisplayConfigs failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::GET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("getAllowedDisplayConfigs failed to transact: %d", result);
- return result;
- }
- result = reply.readInt32Vector(outAllowedConfigs);
- if (result != NO_ERROR) {
- ALOGE("getAllowedDisplayConfigs failed to readInt32Vector: %d", result);
- return result;
- }
- return reply.readInt32();
- }
-
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultModeId, float minRefreshRate,
+ int32_t defaultConfig, float minRefreshRate,
float maxRefreshRate) {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -919,9 +948,9 @@
ALOGE("setDesiredDisplayConfigSpecs: failed to write display token: %d", result);
return result;
}
- result = data.writeInt32(defaultModeId);
+ result = data.writeInt32(defaultConfig);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs failed to write defaultModeId: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
return result;
}
result = data.writeFloat(minRefreshRate);
@@ -945,10 +974,10 @@
}
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultModeId,
+ int32_t* outDefaultConfig,
float* outMinRefreshRate,
float* outMaxRefreshRate) {
- if (!outDefaultModeId || !outMinRefreshRate || !outMaxRefreshRate) return BAD_VALUE;
+ if (!outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) return BAD_VALUE;
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (result != NO_ERROR) {
@@ -966,9 +995,9 @@
ALOGE("getDesiredDisplayConfigSpecs failed to transact: %d", result);
return result;
}
- result = reply.readInt32(outDefaultModeId);
+ result = reply.readInt32(outDefaultConfig);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs failed to read defaultModeId: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
return result;
}
result = reply.readFloat(outMinRefreshRate);
@@ -1407,6 +1436,75 @@
result = reply->writeInt32(result);
return result;
}
+
+ case GET_AUTO_LOW_LATENCY_MODE_SUPPORT: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("getAutoLowLatencyModeSupport failed to readStrongBinder: %d", result);
+ return result;
+ }
+ bool supported = false;
+ result = getAutoLowLatencyModeSupport(display, &supported);
+ if (result == NO_ERROR) {
+ result = reply->writeBool(supported);
+ }
+ return result;
+ }
+
+ case SET_AUTO_LOW_LATENCY_MODE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("setAutoLowLatencyMode failed to readStrongBinder: %d", result);
+ return result;
+ }
+ bool setAllm = false;
+ result = data.readBool(&setAllm);
+ if (result != NO_ERROR) {
+ ALOGE("setAutoLowLatencyMode failed to readBool: %d", result);
+ return result;
+ }
+ setAutoLowLatencyMode(display, setAllm);
+ return result;
+ }
+
+ case GET_GAME_CONTENT_TYPE_SUPPORT: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("getGameContentTypeSupport failed to readStrongBinder: %d", result);
+ return result;
+ }
+ bool supported = false;
+ result = getGameContentTypeSupport(display, &supported);
+ if (result == NO_ERROR) {
+ result = reply->writeBool(supported);
+ }
+ return result;
+ }
+
+ case SET_GAME_CONTENT_TYPE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("setGameContentType failed to readStrongBinder: %d", result);
+ return result;
+ }
+ bool setGameContentTypeOn = false;
+ result = data.readBool(&setGameContentTypeOn);
+ if (result != NO_ERROR) {
+ ALOGE("setGameContentType failed to readBool: %d", result);
+ return result;
+ }
+ setGameContentType(display, setGameContentTypeOn);
+ return result;
+ }
+
case CLEAR_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
status_t result = clearAnimationFrameStats();
@@ -1644,31 +1742,13 @@
}
return removeRegionSamplingListener(listener);
}
- case SET_ALLOWED_DISPLAY_CONFIGS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken = data.readStrongBinder();
- std::vector<int32_t> allowedConfigs;
- data.readInt32Vector(&allowedConfigs);
- status_t result = setAllowedDisplayConfigs(displayToken, allowedConfigs);
- reply->writeInt32(result);
- return result;
- }
- case GET_ALLOWED_DISPLAY_CONFIGS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken = data.readStrongBinder();
- std::vector<int32_t> allowedConfigs;
- status_t result = getAllowedDisplayConfigs(displayToken, &allowedConfigs);
- reply->writeInt32Vector(allowedConfigs);
- reply->writeInt32(result);
- return result;
- }
case SET_DESIRED_DISPLAY_CONFIG_SPECS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
- int32_t defaultModeId;
- status_t result = data.readInt32(&defaultModeId);
+ int32_t defaultConfig;
+ status_t result = data.readInt32(&defaultConfig);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultModeId: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
return result;
}
float minRefreshRate;
@@ -1683,7 +1763,7 @@
ALOGE("setDesiredDisplayConfigSpecs: failed to read maxRefreshRate: %d", result);
return result;
}
- result = setDesiredDisplayConfigSpecs(displayToken, defaultModeId, minRefreshRate,
+ result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, minRefreshRate,
maxRefreshRate);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
@@ -1697,11 +1777,11 @@
case GET_DESIRED_DISPLAY_CONFIG_SPECS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
- int32_t defaultModeId;
+ int32_t defaultConfig;
float minRefreshRate;
float maxRefreshRate;
- status_t result = getDesiredDisplayConfigSpecs(displayToken, &defaultModeId,
+ status_t result = getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
&minRefreshRate, &maxRefreshRate);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayConfigSpecs: failed to get getDesiredDisplayConfigSpecs: "
@@ -1710,9 +1790,9 @@
return result;
}
- result = reply->writeInt32(defaultModeId);
+ result = reply->writeInt32(defaultConfig);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultModeId: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
return result;
}
result = reply->writeFloat(minRefreshRate);
diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp
index 04d2871..b3eb994 100644
--- a/libs/gui/LayerMetadata.cpp
+++ b/libs/gui/LayerMetadata.cpp
@@ -18,6 +18,8 @@
#include <binder/Parcel.h>
#include <gui/LayerMetadata.h>
+#include "android/view/LayerMetadataKey.h"
+
using android::base::StringPrintf;
namespace android {
@@ -113,12 +115,12 @@
std::string LayerMetadata::itemToString(uint32_t key, const char* separator) const {
if (!has(key)) return std::string();
- switch (key) {
- case METADATA_OWNER_UID:
+ switch (static_cast<view::LayerMetadataKey>(key)) {
+ case view::LayerMetadataKey::METADATA_OWNER_UID:
return StringPrintf("ownerUID%s%d", separator, getInt32(key, 0));
- case METADATA_WINDOW_TYPE:
+ case view::LayerMetadataKey::METADATA_WINDOW_TYPE:
return StringPrintf("windowType%s%d", separator, getInt32(key, 0));
- case METADATA_TASK_ID:
+ case view::LayerMetadataKey::METADATA_TASK_ID:
return StringPrintf("taskId%s%d", separator, getInt32(key, 0));
default:
return StringPrintf("%d%s%dbytes", key, separator,
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 73150dc..274153c 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -4,4 +4,5 @@
marissaw@google.com
mathias@google.com
racarr@google.com
+steventhomas@google.com
stoza@google.com
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9d7d7d0..1d887ea 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1605,34 +1605,22 @@
return ComposerService::getComposerService()->setActiveConfig(display, id);
}
-status_t SurfaceComposerClient::setAllowedDisplayConfigs(
- const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) {
- return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken,
- allowedConfigs);
-}
-
-status_t SurfaceComposerClient::getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- std::vector<int32_t>* outAllowedConfigs) {
- return ComposerService::getComposerService()->getAllowedDisplayConfigs(displayToken,
- outAllowedConfigs);
-}
-
status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultModeId,
+ int32_t defaultConfig,
float minRefreshRate,
float maxRefreshRate) {
return ComposerService::getComposerService()->setDesiredDisplayConfigSpecs(displayToken,
- defaultModeId,
+ defaultConfig,
minRefreshRate,
maxRefreshRate);
}
status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultModeId,
+ int32_t* outDefaultConfig,
float* outMinRefreshRate,
float* outMaxRefreshRate) {
return ComposerService::getComposerService()->getDesiredDisplayConfigSpecs(displayToken,
- outDefaultModeId,
+ outDefaultConfig,
outMinRefreshRate,
outMaxRefreshRate);
}
@@ -1656,6 +1644,26 @@
return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
}
+bool SurfaceComposerClient::getAutoLowLatencyModeSupport(const sp<IBinder>& display) {
+ bool supported = false;
+ ComposerService::getComposerService()->getAutoLowLatencyModeSupport(display, &supported);
+ return supported;
+}
+
+void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
+ ComposerService::getComposerService()->setAutoLowLatencyMode(display, on);
+}
+
+bool SurfaceComposerClient::getGameContentTypeSupport(const sp<IBinder>& display) {
+ bool supported = false;
+ ComposerService::getComposerService()->getGameContentTypeSupport(display, &supported);
+ return supported;
+}
+
+void SurfaceComposerClient::setGameContentType(const sp<IBinder>& display, bool on) {
+ ComposerService::getComposerService()->setGameContentType(display, on);
+}
+
void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token,
int mode) {
ComposerService::getComposerService()->setPowerMode(token, mode);
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 3c96089..557c28b 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -34,12 +34,6 @@
#include <mutex>
#include <condition_variable>
-#define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
-#define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
-#define BQ_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
-#define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
-#define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
-
#define ATRACE_BUFFER_INDEX(index) \
do { \
if (ATRACE_ENABLED()) { \
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 345425d..998973c 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -195,6 +195,37 @@
ui::ColorMode colorMode) = 0;
/**
+ * Returns true if the connected display reports support for HDMI 2.1 Auto
+ * Low Latency Mode.
+ * For more information, see the HDMI 2.1 specification.
+ */
+ virtual status_t getAutoLowLatencyModeSupport(const sp<IBinder>& display,
+ bool* outSupport) const = 0;
+
+ /**
+ * Switches Auto Low Latency Mode on/off on the connected display, if it is
+ * available. This should only be called if #getAutoLowLatencyMode returns
+ * true.
+ * For more information, see the HDMI 2.1 specification.
+ */
+ virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) = 0;
+
+ /**
+ * Returns true if the connected display reports support for Game Content Type.
+ * For more information, see the HDMI 1.4 specification.
+ */
+ virtual status_t getGameContentTypeSupport(const sp<IBinder>& display,
+ bool* outSupport) const = 0;
+
+ /**
+ * This will start sending infoframes to the connected display with
+ * ContentType=Game (if on=true). This will switch the disply to Game mode.
+ * This should only be called if #getGameContentTypeSupport returns true.
+ * For more information, see the HDMI 1.4 specification.
+ */
+ virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0;
+
+ /**
* Capture the specified screen. This requires READ_FRAME_BUFFER
* permission. This function will fail if there is a secure window on
* screen.
@@ -386,31 +417,16 @@
virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
/*
- * Sets the allowed display configurations to be used.
- * The allowedConfigs in a vector of indexes corresponding to the configurations
- * returned from getDisplayConfigs().
- */
- virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- const std::vector<int32_t>& allowedConfigs) = 0;
-
- /*
- * Returns the allowed display configurations currently set.
- * The allowedConfigs in a vector of indexes corresponding to the configurations
- * returned from getDisplayConfigs().
- */
- virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- std::vector<int32_t>* outAllowedConfigs) = 0;
- /*
* Sets the refresh rate boundaries for display configuration.
* For all other parameters, default configuration is used. The index for the default is
* corresponding to the configs returned from getDisplayConfigs().
*/
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultModeId, float minRefreshRate,
+ int32_t defaultConfig, float minRefreshRate,
float maxRefreshRate) = 0;
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultModeId,
+ int32_t* outDefaultConfig,
float* outMinRefreshRate,
float* outMaxRefreshRate) = 0;
/*
@@ -523,8 +539,6 @@
GET_PHYSICAL_DISPLAY_IDS,
ADD_REGION_SAMPLING_LISTENER,
REMOVE_REGION_SAMPLING_LISTENER,
- SET_ALLOWED_DISPLAY_CONFIGS,
- GET_ALLOWED_DISPLAY_CONFIGS,
SET_DESIRED_DISPLAY_CONFIG_SPECS,
GET_DESIRED_DISPLAY_CONFIG_SPECS,
GET_DISPLAY_BRIGHTNESS_SUPPORT,
@@ -532,6 +546,10 @@
CAPTURE_SCREEN_BY_ID,
NOTIFY_POWER_HINT,
SET_GLOBAL_SHADOW_SETTINGS,
+ GET_AUTO_LOW_LATENCY_MODE_SUPPORT,
+ SET_AUTO_LOW_LATENCY_MODE,
+ GET_GAME_CONTENT_TYPE_SUPPORT,
+ SET_GAME_CONTENT_TYPE,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2c0b143..86468a4 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -117,23 +117,11 @@
// returned by getDisplayInfo
static status_t setActiveConfig(const sp<IBinder>& display, int id);
- // Sets the allowed display configurations to be used.
- // The allowedConfigs in a vector of indexes corresponding to the configurations
- // returned from getDisplayConfigs().
- static status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- const std::vector<int32_t>& allowedConfigs);
-
- // Returns the allowed display configurations currently set.
- // The allowedConfigs in a vector of indexes corresponding to the configurations
- // returned from getDisplayConfigs().
- static status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- std::vector<int32_t>* outAllowedConfigs);
-
// Sets the refresh rate boundaries for display configuration.
// For all other parameters, default configuration is used. The index for the default is
// corresponting to the configs returned from getDisplayConfigs().
static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultModeId, float minRefreshRate,
+ int32_t defaultConfig, float minRefreshRate,
float maxRefreshRate);
// Gets the refresh rate boundaries for display configuration.
// For all other parameters, default configuration is used. The index for the default is
@@ -141,7 +129,7 @@
// The reason is passed in for telemetry tracking, and it corresponds to the list of all
// the policy rules that were used.
static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultModeId,
+ int32_t* outDefaultConfig,
float* outMinRefreshRate,
float* outMaxRefreshRate);
@@ -160,6 +148,21 @@
static status_t setActiveColorMode(const sp<IBinder>& display,
ui::ColorMode colorMode);
+ // Reports whether the connected display supports Auto Low Latency Mode
+ static bool getAutoLowLatencyModeSupport(const sp<IBinder>& display);
+
+ // Switches on/off Auto Low Latency Mode on the connected display. This should only be
+ // called if the connected display supports Auto Low Latency Mode as reported by
+ // #getAutoLowLatencyModeSupport
+ static void setAutoLowLatencyMode(const sp<IBinder>& display, bool on);
+
+ // Reports whether the connected display supports Game content type
+ static bool getGameContentTypeSupport(const sp<IBinder>& display);
+
+ // Turns Game mode on/off on the connected display. This should only be called
+ // if the display supports Game content type, as reported by #getGameContentTypeSupport
+ static void setGameContentType(const sp<IBinder>& display, bool on);
+
/* Triggers screen on/off or low power mode and waits for it to complete */
static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 3d90369..0445755 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -750,6 +750,16 @@
bool /*captureSecureLayers*/) override {
return NO_ERROR;
}
+ status_t getAutoLowLatencyModeSupport(const sp<IBinder>& /*display*/,
+ bool* /*outSupport*/) const override {
+ return NO_ERROR;
+ }
+ void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
+ status_t getGameContentTypeSupport(const sp<IBinder>& /*display*/,
+ bool* /*outSupport*/) const override {
+ return NO_ERROR;
+ }
+ void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
status_t captureScreen(uint64_t /*displayOrLayerStack*/, ui::Dataspace* /*outDataspace*/,
sp<GraphicBuffer>* /*outBuffer*/) override {
return NO_ERROR;
@@ -823,21 +833,13 @@
const sp<IRegionSamplingListener>& /*listener*/) override {
return NO_ERROR;
}
- status_t setAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/,
- const std::vector<int32_t>& /*allowedConfigs*/) override {
- return NO_ERROR;
- }
- status_t getAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/,
- std::vector<int32_t>* /*outAllowedConfigs*/) override {
- return NO_ERROR;
- }
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
- int32_t /*defaultModeId*/, float /*minRefreshRate*/,
- float /*maxRefreshRate*/) override {
+ int32_t /*defaultConfig*/, float /*minRefreshRate*/,
+ float /*maxRefreshRate*/) {
return NO_ERROR;
}
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
- int32_t* /*outDefaultModeId*/,
+ int32_t* /*outDefaultConfig*/,
float* /*outMinRefreshRate*/,
float* /*outMaxRefreshRate*/) override {
return NO_ERROR;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index b7f7ac5..b4d7608 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -21,6 +21,7 @@
#include <gtest/gtest.h>
#include <linux/input.h>
+#include <vector>
namespace android::inputdispatcher {
@@ -37,6 +38,10 @@
static const int32_t INJECTOR_PID = 999;
static const int32_t INJECTOR_UID = 1001;
+struct PointF {
+ float x;
+ float y;
+};
// --- FakeInputDispatcherPolicy ---
@@ -411,6 +416,11 @@
class FakeInputReceiver {
public:
+ explicit FakeInputReceiver(const sp<InputChannel>& clientChannel, const std::string name)
+ : mName(name) {
+ mConsumer = std::make_unique<InputConsumer>(clientChannel);
+ }
+
InputEvent* consume() {
uint32_t consumeSeq;
InputEvent* event;
@@ -440,7 +450,7 @@
return nullptr;
}
- status = mConsumer->sendFinishedSignal(consumeSeq, handled());
+ status = mConsumer->sendFinishedSignal(consumeSeq, true);
if (status != OK) {
ADD_FAILURE() << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
}
@@ -478,6 +488,82 @@
}
}
+ void assertNoEvents() {
+ InputEvent* event = consume();
+ ASSERT_EQ(nullptr, event)
+ << mName.c_str()
+ << ": should not have received any events, so consume() should return NULL";
+ }
+
+ sp<IBinder> getToken() { return mConsumer->getChannel()->getConnectionToken(); }
+
+protected:
+ std::unique_ptr<InputConsumer> mConsumer;
+ PreallocatedInputEventFactory mEventFactory;
+
+ std::string mName;
+};
+
+class FakeWindowHandle : public InputWindowHandle {
+public:
+ static const int32_t WIDTH = 600;
+ static const int32_t HEIGHT = 800;
+ const std::string mName;
+
+ FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<InputDispatcher>& dispatcher, const std::string name,
+ int32_t displayId, sp<IBinder> token = nullptr)
+ : mName(name) {
+ if (token == nullptr) {
+ sp<InputChannel> serverChannel, clientChannel;
+ InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
+ mInputReceiver = std::make_unique<FakeInputReceiver>(clientChannel, name);
+ dispatcher->registerInputChannel(serverChannel);
+ token = serverChannel->getConnectionToken();
+ }
+
+ inputApplicationHandle->updateInfo();
+ mInfo.applicationInfo = *inputApplicationHandle->getInfo();
+
+ mInfo.token = token;
+ mInfo.name = name;
+ mInfo.layoutParamsFlags = 0;
+ mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo.frameLeft = 0;
+ mInfo.frameTop = 0;
+ mInfo.frameRight = WIDTH;
+ mInfo.frameBottom = HEIGHT;
+ mInfo.globalScaleFactor = 1.0;
+ mInfo.touchableRegion.clear();
+ mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+ mInfo.visible = true;
+ mInfo.canReceiveKeys = true;
+ mInfo.hasFocus = false;
+ mInfo.hasWallpaper = false;
+ mInfo.paused = false;
+ mInfo.layer = 0;
+ mInfo.ownerPid = INJECTOR_PID;
+ mInfo.ownerUid = INJECTOR_UID;
+ mInfo.inputFeatures = 0;
+ mInfo.displayId = displayId;
+ }
+
+ virtual bool updateInfo() { return true; }
+
+ void setFocus() { mInfo.hasFocus = true; }
+
+ void setFrame(const Rect& frame) {
+ mInfo.frameLeft = frame.left;
+ mInfo.frameTop = frame.top;
+ mInfo.frameRight = frame.right;
+ mInfo.frameBottom = frame.bottom;
+ mInfo.touchableRegion.clear();
+ mInfo.addTouchableRegion(frame);
+ }
+
+ void setLayoutParamFlags(int32_t flags) { mInfo.layoutParamsFlags = flags; }
+
void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
expectedFlags);
@@ -493,102 +579,21 @@
expectedFlags);
}
+ void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
+ int32_t expectedFlags) {
+ ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver";
+ mInputReceiver->consumeEvent(expectedEventType, expectedAction, expectedDisplayId,
+ expectedFlags);
+ }
+
void assertNoEvents() {
- InputEvent* event = consume();
- ASSERT_EQ(nullptr, event)
- << mName.c_str()
- << ": should not have received any events, so consume() should return NULL";
+ ASSERT_NE(mInputReceiver, nullptr)
+ << "Call 'assertNoEvents' on a window with an InputReceiver";
+ mInputReceiver->assertNoEvents();
}
-protected:
- explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher,
- const std::string name, int32_t displayId) :
- mDispatcher(dispatcher), mName(name), mDisplayId(displayId) {
- InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
- mConsumer = std::make_unique<InputConsumer>(mClientChannel);
- }
-
- virtual ~FakeInputReceiver() {
- }
-
- // return true if the event has been handled.
- virtual bool handled() {
- return false;
- }
-
- sp<InputDispatcher> mDispatcher;
- sp<InputChannel> mServerChannel, mClientChannel;
- std::unique_ptr<InputConsumer> mConsumer;
- PreallocatedInputEventFactory mEventFactory;
-
- std::string mName;
- int32_t mDisplayId;
-};
-
-class FakeWindowHandle : public InputWindowHandle, public FakeInputReceiver {
-public:
- static const int32_t WIDTH = 600;
- static const int32_t HEIGHT = 800;
-
- FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) :
- FakeInputReceiver(dispatcher, name, displayId),
- mFocused(false), mFrame(Rect(0, 0, WIDTH, HEIGHT)), mLayoutParamFlags(0) {
- mDispatcher->registerInputChannel(mServerChannel);
-
- inputApplicationHandle->updateInfo();
- mInfo.applicationInfo = *inputApplicationHandle->getInfo();
- }
-
- virtual bool updateInfo() {
- mInfo.token = mServerChannel ? mServerChannel->getConnectionToken() : nullptr;
- mInfo.name = mName;
- mInfo.layoutParamsFlags = mLayoutParamFlags;
- mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
- mInfo.frameLeft = mFrame.left;
- mInfo.frameTop = mFrame.top;
- mInfo.frameRight = mFrame.right;
- mInfo.frameBottom = mFrame.bottom;
- mInfo.globalScaleFactor = 1.0;
- mInfo.touchableRegion.clear();
- mInfo.addTouchableRegion(mFrame);
- mInfo.visible = true;
- mInfo.canReceiveKeys = true;
- mInfo.hasFocus = mFocused;
- mInfo.hasWallpaper = false;
- mInfo.paused = false;
- mInfo.layer = 0;
- mInfo.ownerPid = INJECTOR_PID;
- mInfo.ownerUid = INJECTOR_UID;
- mInfo.inputFeatures = 0;
- mInfo.displayId = mDisplayId;
-
- return true;
- }
-
- void setFocus() {
- mFocused = true;
- }
-
- void setFrame(const Rect& frame) {
- mFrame.set(frame);
- }
-
- void setLayoutParamFlags(int32_t flags) {
- mLayoutParamFlags = flags;
- }
-
- void releaseChannel() {
- mServerChannel.clear();
- InputWindowHandle::releaseChannel();
- }
-protected:
- virtual bool handled() override { return true; }
-
- bool mFocused;
- Rect mFrame;
- int32_t mLayoutParamFlags;
+private:
+ std::unique_ptr<FakeInputReceiver> mInputReceiver;
};
static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
@@ -659,31 +664,39 @@
return args;
}
-static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) {
- PointerProperties pointerProperties[1];
- PointerCoords pointerCoords[1];
+static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId,
+ const std::vector<PointF>& points) {
+ size_t pointerCount = points.size();
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
- pointerProperties[0].clear();
- pointerProperties[0].id = 0;
- pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].clear();
+ pointerProperties[i].id = i;
+ pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
- pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200);
+ pointerCoords[i].clear();
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
+ }
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
// Define a valid motion event.
NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId,
POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0,
AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, pointerProperties, pointerCoords,
- /* xPrecision */ 0, /* yPrecision */ 0,
+ AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
+ pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {});
return args;
}
+static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) {
+ return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
+}
+
TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window",
@@ -857,15 +870,37 @@
0 /*expectedFlags*/);
}
-class FakeMonitorReceiver : public FakeInputReceiver, public RefBase {
+class FakeMonitorReceiver {
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
- int32_t displayId, bool isGestureMonitor = false)
- : FakeInputReceiver(dispatcher, name, displayId) {
- mDispatcher->registerInputMonitor(mServerChannel, displayId, isGestureMonitor);
+ int32_t displayId, bool isGestureMonitor = false) {
+ sp<InputChannel> serverChannel, clientChannel;
+ InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
+ mInputReceiver = std::make_unique<FakeInputReceiver>(clientChannel, name);
+ dispatcher->registerInputMonitor(serverChannel, displayId, isGestureMonitor);
}
- sp<IBinder> getToken() { return mServerChannel->getConnectionToken(); }
+ sp<IBinder> getToken() { return mInputReceiver->getToken(); }
+
+ void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_DOWN,
+ expectedDisplayId, expectedFlags);
+ }
+
+ void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN,
+ expectedDisplayId, expectedFlags);
+ }
+
+ void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP,
+ expectedDisplayId, expectedFlags);
+ }
+
+ void assertNoEvents() { mInputReceiver->assertNoEvents(); }
+
+private:
+ std::unique_ptr<FakeInputReceiver> mInputReceiver;
};
// Tests for gesture monitors
@@ -875,15 +910,14 @@
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
- sp<FakeMonitorReceiver> monitor =
- new FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
}
TEST_F(InputDispatcherTest, GestureMonitor_DoesNotReceiveKeyEvents) {
@@ -896,14 +930,13 @@
mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
- sp<FakeMonitorReceiver> monitor =
- new FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
<< "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
- monitor->assertNoEvents();
+ monitor.assertNoEvents();
}
TEST_F(InputDispatcherTest, GestureMonitor_CanPilferAfterWindowIsRemovedMidStream) {
@@ -912,24 +945,23 @@
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
- sp<FakeMonitorReceiver> monitor =
- new FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
window->releaseChannel();
- mDispatcher->pilferPointers(monitor->getToken());
+ mDispatcher->pilferPointers(monitor.getToken());
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
- monitor->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
}
TEST_F(InputDispatcherTest, TestMoveEvent) {
@@ -1047,28 +1079,28 @@
// Test per-display input monitors for motion event.
TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
- sp<FakeMonitorReceiver> monitorInPrimary =
- new FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
- sp<FakeMonitorReceiver> monitorInSecondary =
- new FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID);
+ FakeMonitorReceiver monitorInPrimary =
+ FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
+ FakeMonitorReceiver monitorInSecondary =
+ FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID);
// Test touch down on primary display.
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitorInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
windowInSecondary->assertNoEvents();
- monitorInSecondary->assertNoEvents();
+ monitorInSecondary.assertNoEvents();
// Test touch down on second display.
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->assertNoEvents();
- monitorInPrimary->assertNoEvents();
+ monitorInPrimary.assertNoEvents();
windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
- monitorInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
+ monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
// Test inject a non-pointer motion event.
// If specific a display, it will dispatch to the focused window of particular display,
@@ -1077,26 +1109,26 @@
AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->assertNoEvents();
- monitorInPrimary->assertNoEvents();
+ monitorInPrimary.assertNoEvents();
windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
- monitorInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
+ monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE);
}
// Test per-display input monitors for key event.
TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
//Input monitor per display.
- sp<FakeMonitorReceiver> monitorInPrimary =
- new FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
- sp<FakeMonitorReceiver> monitorInSecondary =
- new FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID);
+ FakeMonitorReceiver monitorInPrimary =
+ FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
+ FakeMonitorReceiver monitorInSecondary =
+ FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID);
// Test inject a key down.
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
<< "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->assertNoEvents();
- monitorInPrimary->assertNoEvents();
+ monitorInPrimary.assertNoEvents();
windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
- monitorInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
+ monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
}
class InputFilterTest : public InputDispatcherTest {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index ce0222c..82d2422 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -231,7 +231,7 @@
* (NOTE: the matrices are multiplied in reverse order)
*/
const ui::Transform& layerTransform = layerState.geomLayerTransform;
- const ui::Transform displayTransform{outputState.orientation};
+ const ui::Transform displayTransform{outputState.transform};
const ui::Transform bufferTransform{layerState.geomBufferTransform};
ui::Transform transform(displayTransform * layerTransform * bufferTransform);
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 364661b..9971791 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -86,6 +86,9 @@
MOCK_METHOD4(setActiveConfigWithConstraints,
status_t(DisplayId, size_t, const HWC2::VsyncPeriodChangeConstraints&,
HWC2::VsyncPeriodChangeTimeline*));
+ MOCK_METHOD2(setAutoLowLatencyMode, status_t(DisplayId, bool));
+ MOCK_METHOD2(getSupportedContentTypes, status_t(DisplayId, std::vector<HWC2::ContentType>*));
+ MOCK_METHOD2(setContentType, status_t(DisplayId, HWC2::ContentType));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*());
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 2e030a1..0e579fa 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -364,6 +364,7 @@
mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
mLayerFEState.geomBufferTransform = entry.buffer;
mOutputState.orientation = entry.display;
+ mOutputState.transform = ui::Transform{entry.display};
auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
EXPECT_EQ(entry.expected, actual) << "entry " << i;
@@ -422,6 +423,7 @@
mLayerFEState.geomLayerTransform = ui::Transform{entry.layer};
mLayerFEState.geomBufferTransform = entry.buffer;
mOutputState.orientation = entry.display;
+ mOutputState.transform = ui::Transform{entry.display};
auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
EXPECT_EQ(entry.expected, actual) << "entry " << i;
@@ -764,6 +766,21 @@
mOutputLayer.writeStateToHWC(true);
}
+TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) {
+ mLayerFEState.geomBufferUsesDisplayInverseTransform = false;
+ mLayerFEState.geomLayerTransform = ui::Transform{TR_IDENT};
+ // This test simulates a scenario where displayInstallOrientation is set to
+ // ROT_90. This only has an effect on the transform; orientation stays 0 (see
+ // DisplayDevice::setProjection).
+ mOutputState.orientation = TR_IDENT;
+ mOutputState.transform = ui::Transform{TR_ROT_90};
+ // Buffers are pre-rotated based on the transform hint (ROT_90); their
+ // geomBufferTransform is set to the inverse transform.
+ mLayerFEState.geomBufferTransform = TR_ROT_270;
+
+ EXPECT_EQ(TR_IDENT, mOutputLayer.calculateOutputRelativeBufferTransform());
+}
+
TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) {
mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index dc71128..eb032f3 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -1281,6 +1281,45 @@
return error;
}
+V2_4::Error Composer::setAutoLowLatencyMode(Display display, bool on) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ return mClient_2_4->setAutoLowLatencyMode(display, on);
+}
+
+V2_4::Error Composer::getSupportedContentTypes(
+ Display displayId, std::vector<IComposerClient::ContentType>* outSupportedContentTypes) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ Error error = kDefaultError_2_4;
+ mClient_2_4->getSupportedContentTypes(displayId,
+ [&](const auto& tmpError,
+ const auto& tmpSupportedContentTypes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outSupportedContentTypes = tmpSupportedContentTypes;
+ });
+ return error;
+}
+
+V2_4::Error Composer::setContentType(Display display, IComposerClient::ContentType contentType) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ return mClient_2_4->setContentType(display, contentType);
+}
+
CommandReader::~CommandReader()
{
resetData();
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 336fdd8..301f54f 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -221,6 +221,13 @@
Display display, Config config,
const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
VsyncPeriodChangeTimeline* outTimeline) = 0;
+
+ virtual V2_4::Error setAutoLowLatencyMode(Display displayId, bool on) = 0;
+ virtual V2_4::Error getSupportedContentTypes(
+ Display displayId,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) = 0;
+ virtual V2_4::Error setContentType(Display displayId,
+ IComposerClient::ContentType contentType) = 0;
};
namespace impl {
@@ -442,6 +449,12 @@
Display display, Config config,
const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
VsyncPeriodChangeTimeline* outTimeline) override;
+ V2_4::Error setAutoLowLatencyMode(Display displayId, bool on) override;
+ V2_4::Error getSupportedContentTypes(
+ Display displayId,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
+ V2_4::Error setContentType(Display displayId,
+ IComposerClient::ContentType contentType) override;
private:
#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 4f96ad3..c4f91be 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -812,6 +812,26 @@
return static_cast<Error>(intError);
}
+Error Display::setAutoLowLatencyMode(bool on) const {
+ auto intError = mComposer.setAutoLowLatencyMode(mId, on);
+ return static_cast<Error>(intError);
+}
+
+Error Display::getSupportedContentTypes(std::vector<ContentType>* outSupportedContentTypes) const {
+ std::vector<Hwc2::IComposerClient::ContentType> tmpSupportedContentTypes;
+ auto intError = mComposer.getSupportedContentTypes(mId, &tmpSupportedContentTypes);
+ for (Hwc2::IComposerClient::ContentType contentType : tmpSupportedContentTypes) {
+ outSupportedContentTypes->push_back(static_cast<ContentType>(contentType));
+ }
+ return static_cast<Error>(intError);
+}
+
+Error Display::setContentType(ContentType contentType) const {
+ using Hwc2_ContentType = Hwc2::IComposerClient::ContentType;
+ auto intError = mComposer.setContentType(mId, static_cast<Hwc2_ContentType>(contentType));
+ return static_cast<Error>(intError);
+}
+
// For use by Device
void Display::setConnected(bool connected) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 5abebab..59f36d0 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -283,6 +283,10 @@
const std::shared_ptr<const HWC2::Display::Config>& config,
const VsyncPeriodChangeConstraints& constraints,
VsyncPeriodChangeTimeline* outTimeline) = 0;
+ [[clang::warn_unused_result]] virtual Error setAutoLowLatencyMode(bool on) const = 0;
+ [[clang::warn_unused_result]] virtual Error getSupportedContentTypes(
+ std::vector<HWC2::ContentType>*) const = 0;
+ [[clang::warn_unused_result]] virtual Error setContentType(HWC2::ContentType) const = 0;
};
namespace impl {
@@ -346,7 +350,10 @@
Error setActiveConfigWithConstraints(const std::shared_ptr<const HWC2::Display::Config>& config,
const VsyncPeriodChangeConstraints& constraints,
VsyncPeriodChangeTimeline* outTimeline) override;
-
+ Error setAutoLowLatencyMode(bool on) const override;
+ Error getSupportedContentTypes(
+ std::vector<HWC2::ContentType>* outSupportedContentTypes) const override;
+ Error setContentType(HWC2::ContentType contentType) const override;
// Other Display methods
hwc2_display_t getId() const override { return mId; }
bool isConnected() const override { return mIsConnected; }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d8dad0b..9accefb 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -722,6 +722,44 @@
return getComposer()->isUsingVrComposer();
}
+status_t HWComposer::setAutoLowLatencyMode(DisplayId displayId, bool on) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on);
+ if (error == HWC2::Error::Unsupported) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == HWC2::Error::BadParameter) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return NO_ERROR;
+}
+
+status_t HWComposer::getSupportedContentTypes(
+ DisplayId displayId, std::vector<HWC2::ContentType>* outSupportedContentTypes) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto error =
+ mDisplayData[displayId].hwcDisplay->getSupportedContentTypes(outSupportedContentTypes);
+
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+
+ return NO_ERROR;
+}
+
+status_t HWComposer::setContentType(DisplayId displayId, HWC2::ContentType contentType) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto error = mDisplayData[displayId].hwcDisplay->setContentType(contentType);
+ if (error == HWC2::Error::Unsupported) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == HWC2::Error::BadParameter) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+
+ return NO_ERROR;
+}
+
void HWComposer::dump(std::string& result) const {
// TODO: In order to provide a dump equivalent to HWC1, we need to shadow
// all the state going into the layers. This is probably better done in
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 077e452..c51002c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -184,6 +184,10 @@
DisplayId displayId, size_t configId,
const HWC2::VsyncPeriodChangeConstraints& constraints,
HWC2::VsyncPeriodChangeTimeline* outTimeline) = 0;
+ virtual status_t setAutoLowLatencyMode(DisplayId displayId, bool on) = 0;
+ virtual status_t getSupportedContentTypes(
+ DisplayId displayId, std::vector<HWC2::ContentType>* outSupportedContentTypes) = 0;
+ virtual status_t setContentType(DisplayId displayId, HWC2::ContentType contentType) = 0;
// for debugging ----------------------------------------------------------
virtual void dump(std::string& out) const = 0;
@@ -313,6 +317,10 @@
status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId,
const HWC2::VsyncPeriodChangeConstraints& constraints,
HWC2::VsyncPeriodChangeTimeline* outTimeline) override;
+ status_t setAutoLowLatencyMode(DisplayId displayId, bool) override;
+ status_t getSupportedContentTypes(DisplayId displayId,
+ std::vector<HWC2::ContentType>*) override;
+ status_t setContentType(DisplayId displayId, HWC2::ContentType) override;
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 23fb96a..847e20c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -110,13 +110,48 @@
init(inputConfigs, currentConfigId);
}
-void RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
- float maxRefreshRate) {
+status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
+ float maxRefreshRate, bool* outPolicyChanged) {
std::lock_guard lock(mLock);
- mCurrentGroupId = mRefreshRates.at(defaultConfigId).configGroup;
+ bool policyChanged = defaultConfigId != mDefaultConfig ||
+ minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps;
+ if (outPolicyChanged) {
+ *outPolicyChanged = policyChanged;
+ }
+ if (!policyChanged) {
+ return NO_ERROR;
+ }
+ // defaultConfigId must be a valid config ID, and within the given refresh rate range.
+ if (mRefreshRates.count(defaultConfigId) == 0) {
+ return BAD_VALUE;
+ }
+ const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
+ if (refreshRate.fps < minRefreshRate || refreshRate.fps > maxRefreshRate) {
+ return BAD_VALUE;
+ }
+ mDefaultConfig = defaultConfigId;
mMinRefreshRateFps = minRefreshRate;
mMaxRefreshRateFps = maxRefreshRate;
constructAvailableRefreshRates();
+ return NO_ERROR;
+}
+
+void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
+ float* maxRefreshRate) const {
+ std::lock_guard lock(mLock);
+ *defaultConfigId = mDefaultConfig;
+ *minRefreshRate = mMinRefreshRateFps;
+ *maxRefreshRate = mMaxRefreshRateFps;
+}
+
+bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
+ std::lock_guard lock(mLock);
+ for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
+ if (refreshRate->configId == config) {
+ return true;
+ }
+ }
+ return false;
}
void RefreshRateConfigs::getSortedRefreshRateList(
@@ -140,15 +175,18 @@
void RefreshRateConfigs::constructAvailableRefreshRates() {
// Filter configs based on current policy and sort based on vsync period
- ALOGV("constructRefreshRateMap: group %d min %.2f max %.2f", mCurrentGroupId.value(),
- mMinRefreshRateFps, mMaxRefreshRateFps);
+ HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
+ ALOGV("constructRefreshRateMap: default %d group %d min %.2f max %.2f", mDefaultConfig.value(),
+ group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
getSortedRefreshRateList(
- [this](const RefreshRate& refreshRate) REQUIRES(mLock) {
- return refreshRate.configGroup == mCurrentGroupId &&
- refreshRate.fps >= mMinRefreshRateFps &&
+ [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
+ return refreshRate.configGroup == group && refreshRate.fps >= mMinRefreshRateFps &&
refreshRate.fps <= mMaxRefreshRateFps;
},
&mAvailableRefreshRates);
+ LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
+ "No compatible display configs for default=%d min=%.0f max=%.0f",
+ mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
}
// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor
@@ -167,12 +205,12 @@
mRefreshRates.emplace(config.configId, buildRefreshRate(config));
if (config.configId == currentHwcConfig) {
mCurrentRefreshRate = &mRefreshRates.at(config.configId);
- mCurrentGroupId = config.configGroup;
}
}
std::vector<const RefreshRate*> sortedConfigs;
getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
+ mDefaultConfig = currentHwcConfig;
mMinSupportedRefreshRate = sortedConfigs.front();
mMaxSupportedRefreshRate = sortedConfigs.back();
constructAvailableRefreshRates();
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index fb14dc7..1e740ca 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -73,9 +73,17 @@
using AllRefreshRatesMapType = std::unordered_map<HwcConfigIndexType, const RefreshRate>;
- // Sets the current policy to choose refresh rates.
- void setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate, float maxRefreshRate)
- EXCLUDES(mLock);
+ // Sets the current policy to choose refresh rates. Returns NO_ERROR if the requested policy is
+ // valid, or a negative error value otherwise. policyChanged, if non-null, will be set to true
+ // if the new policy is different from the old policy.
+ status_t setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
+ float maxRefreshRate, bool* policyChanged) EXCLUDES(mLock);
+ // Gets the current policy.
+ void getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
+ float* maxRefreshRate) const EXCLUDES(mLock);
+
+ // Returns true if config is allowed by the current policy.
+ bool isConfigAllowed(HwcConfigIndexType config) const EXCLUDES(mLock);
// Returns true if this device is doing refresh rate switching. This won't change at runtime.
bool refreshRateSwitchingSupported() const { return mRefreshRateSwitching; }
@@ -143,9 +151,9 @@
// the main thread, and read by the Scheduler (and other objects) on other threads.
const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock);
- // The current config group. This will change at runtime. This is set by SurfaceFlinger on
+ // The default config. This will change at runtime. This is set by SurfaceFlinger on
// the main thread, and read by the Scheduler (and other objects) on other threads.
- HwcConfigGroupType mCurrentGroupId GUARDED_BY(mLock);
+ HwcConfigIndexType mDefaultConfig GUARDED_BY(mLock);
// The min and max FPS allowed by the policy. This will change at runtime and set by
// SurfaceFlinger on the main thread.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 537489f..7f819dd 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -910,10 +910,30 @@
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
ATRACE_CALL();
- std::vector<int32_t> allowedConfig;
- allowedConfig.push_back(mode);
+ if (!displayToken) {
+ return BAD_VALUE;
+ }
- return setAllowedDisplayConfigs(displayToken, allowedConfig);
+ status_t result = NO_ERROR;
+
+ postMessageSync(new LambdaMessage([&]() {
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set allowed display configs for invalid display token %p",
+ displayToken.get());
+ result = BAD_VALUE;
+ } else if (display->isVirtual()) {
+ ALOGW("Attempt to set allowed display configs for virtual display");
+ result = BAD_VALUE;
+ } else {
+ HwcConfigIndexType config(mode);
+ const auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(config);
+ result = setDesiredDisplayConfigSpecsInternal(display, config, refreshRate.fps,
+ refreshRate.fps);
+ }
+ }));
+
+ return result;
}
void SurfaceFlinger::setActiveConfigInternal() {
@@ -1111,6 +1131,86 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getAutoLowLatencyModeSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const {
+ Mutex::Autolock _l(mStateLock);
+
+ if (!displayToken) {
+ ALOGE("getAutoLowLatencyModeSupport() failed. Missing display token.");
+ return BAD_VALUE;
+ }
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ ALOGE("getAutoLowLatencyModeSupport() failed. Display id for display token %p not found.",
+ displayToken.get());
+ return NAME_NOT_FOUND;
+ }
+ *outSupport = getHwComposer().hasDisplayCapability(displayId,
+ HWC2::DisplayCapability::AutoLowLatencyMode);
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
+ postMessageAsync(new LambdaMessage([=] { setAutoLowLatencyModeInternal(displayToken, on); }));
+}
+
+void SurfaceFlinger::setAutoLowLatencyModeInternal(const sp<IBinder>& displayToken, bool on) {
+ if (!displayToken) {
+ ALOGE("setAutoLowLatencyMode() failed. Missing display token.");
+ return;
+ }
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ ALOGE("setAutoLowLatencyMode() failed. Display id for display token %p not found.",
+ displayToken.get());
+ return;
+ }
+
+ getHwComposer().setAutoLowLatencyMode(*displayId, on);
+}
+
+status_t SurfaceFlinger::getGameContentTypeSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const {
+ Mutex::Autolock _l(mStateLock);
+
+ if (!displayToken) {
+ ALOGE("getGameContentTypeSupport() failed. Missing display token.");
+ return BAD_VALUE;
+ }
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ ALOGE("getGameContentTypeSupport() failed. Display id for display token %p not found.",
+ displayToken.get());
+ return NAME_NOT_FOUND;
+ }
+
+ std::vector<HWC2::ContentType> outSupportedContentTypes;
+ getHwComposer().getSupportedContentTypes(*displayId, &outSupportedContentTypes);
+ *outSupport = std::find(outSupportedContentTypes.begin(), outSupportedContentTypes.end(),
+ HWC2::ContentType::Game) != outSupportedContentTypes.end();
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
+ postMessageAsync(new LambdaMessage([=] { setGameContentTypeInternal(displayToken, on); }));
+}
+
+void SurfaceFlinger::setGameContentTypeInternal(const sp<IBinder>& displayToken, bool on) {
+ if (!displayToken) {
+ ALOGE("setGameContentType() failed. Missing display token.");
+ return;
+ }
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ ALOGE("setGameContentType() failed. Display id for display token %p not found.",
+ displayToken.get());
+ return;
+ }
+
+ const HWC2::ContentType type = on ? HWC2::ContentType::Game : HWC2::ContentType::None;
+ getHwComposer().setContentType(*displayId, type);
+}
+
status_t SurfaceFlinger::clearAnimationFrameStats() {
Mutex::Autolock _l(mStateLock);
mAnimFrameTracker.clearStats();
@@ -1413,7 +1513,7 @@
}
bool SurfaceFlinger::isDisplayConfigAllowed(HwcConfigIndexType configId) const {
- return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId);
+ return mRefreshRateConfigs->isConfigAllowed(configId);
}
void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
@@ -3995,18 +4095,13 @@
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriod());
- StringAppendF(&result, "Allowed Display Configs: ");
- for (auto configId : mAllowedDisplayConfigs) {
- StringAppendF(&result, "%" PRIu32 " Hz, ",
- static_cast<int32_t>(
- mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps));
- }
+ HwcConfigIndexType defaultConfig;
+ float minFps, maxFps;
+ mRefreshRateConfigs->getPolicy(&defaultConfig, &minFps, &maxFps);
StringAppendF(&result,
- "DesiredDisplayConfigSpecs: default config ID: %" PRIu32
+ "DesiredDisplayConfigSpecs: default config ID: %d"
", min: %.2f Hz, max: %.2f Hz",
- mDesiredDisplayConfigSpecs.defaultModeId,
- mDesiredDisplayConfigSpecs.minRefreshRate,
- mDesiredDisplayConfigSpecs.maxRefreshRate);
+ defaultConfig.value(), minFps, maxFps);
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
@@ -4434,11 +4529,13 @@
case GET_ANIMATION_FRAME_STATS:
case GET_HDR_CAPABILITIES:
case SET_ACTIVE_CONFIG:
- case SET_ALLOWED_DISPLAY_CONFIGS:
- case GET_ALLOWED_DISPLAY_CONFIGS:
case SET_DESIRED_DISPLAY_CONFIG_SPECS:
case GET_DESIRED_DISPLAY_CONFIG_SPECS:
case SET_ACTIVE_COLOR_MODE:
+ case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
+ case SET_AUTO_LOW_LATENCY_MODE:
+ case GET_GAME_CONTENT_TYPE_SUPPORT:
+ case SET_GAME_CONTENT_TYPE:
case INJECT_VSYNC:
case SET_POWER_MODE:
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
@@ -4861,7 +4958,7 @@
mDebugDisplayConfigSetByBackdoor = false;
if (n >= 0) {
const auto displayToken = getInternalDisplayToken();
- status_t result = setAllowedDisplayConfigs(displayToken, {n});
+ status_t result = setActiveConfig(displayToken, n);
if (result != NO_ERROR) {
return result;
}
@@ -5457,8 +5554,12 @@
}
}
-void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
- const std::vector<int32_t>& allowedConfigs) {
+status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sp<DisplayDevice>& display,
+ HwcConfigIndexType defaultConfig,
+ float minRefreshRate,
+ float maxRefreshRate) {
+ Mutex::Autolock lock(mStateLock);
+
if (!display->isPrimary()) {
// TODO(b/144711714): For non-primary displays we should be able to set an active config
// as well. For now, just call directly to setActiveConfigWithConstraints but ideally
@@ -5472,26 +5573,36 @@
constraints.seamlessRequired = false;
HWC2::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
- getHwComposer().setActiveConfigWithConstraints(*displayId, allowedConfigs[0], constraints,
- &timeline);
+ if (getHwComposer().setActiveConfigWithConstraints(*displayId, defaultConfig.value(),
+ constraints, &timeline) < 0) {
+ return BAD_VALUE;
+ }
if (timeline.refreshRequired) {
repaintEverythingForHWC();
}
- auto configId = HwcConfigIndexType(allowedConfigs[0]);
+ auto configId = HwcConfigIndexType(defaultConfig);
display->setActiveConfig(configId);
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId);
- return;
+ return NO_ERROR;
}
- const auto allowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(),
- allowedConfigs.end());
- if (allowedDisplayConfigs == mAllowedDisplayConfigs) {
- return;
+ if (mDebugDisplayConfigSetByBackdoor) {
+ // ignore this request as config is overridden by backdoor
+ return NO_ERROR;
}
- ALOGV("Updating allowed configs");
- mAllowedDisplayConfigs = std::move(allowedDisplayConfigs);
+ bool policyChanged;
+ if (mRefreshRateConfigs->setPolicy(defaultConfig, minRefreshRate, maxRefreshRate,
+ &policyChanged) < 0) {
+ return BAD_VALUE;
+ }
+ if (!policyChanged) {
+ return NO_ERROR;
+ }
+
+ ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f",
+ defaultConfig.value(), minRefreshRate, maxRefreshRate);
// TODO(b/140204874): This hack triggers a notification that something has changed, so
// that listeners that care about a change in allowed configs can get the notification.
@@ -5499,25 +5610,6 @@
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
display->getActiveConfig());
- // Prepare the parameters needed for RefreshRateConfigs::setPolicy. This will change to just
- // passthrough once DisplayManager provide these parameters directly.
- const auto refreshRate =
- mRefreshRateConfigs->getRefreshRateFromConfigId(HwcConfigIndexType(allowedConfigs[0]));
- const auto defaultModeId = refreshRate.configId;
- auto minRefreshRateFps = refreshRate.fps;
- auto maxRefreshRateFps = minRefreshRateFps;
-
- for (auto config : allowedConfigs) {
- const auto configRefreshRate =
- mRefreshRateConfigs->getRefreshRateFromConfigId(HwcConfigIndexType(config));
- if (configRefreshRate.fps < minRefreshRateFps) {
- minRefreshRateFps = configRefreshRate.fps;
- } else if (configRefreshRate.fps > maxRefreshRateFps) {
- maxRefreshRateFps = configRefreshRate.fps;
- }
- }
- mRefreshRateConfigs->setPolicy(defaultModeId, minRefreshRateFps, maxRefreshRateFps);
-
if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
auto configId = mScheduler->getPreferredConfigId();
auto preferredRefreshRate = configId
@@ -5536,70 +5628,15 @@
Scheduler::ConfigEvent::Changed});
}
} else {
- if (!allowedConfigs.empty()) {
- ALOGV("switching to config %d", allowedConfigs[0]);
- auto configId = HwcConfigIndexType(allowedConfigs[0]);
- setDesiredActiveConfig({configId, Scheduler::ConfigEvent::Changed});
- }
- }
-}
-
-status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- const std::vector<int32_t>& allowedConfigs) {
- ATRACE_CALL();
-
- if (!displayToken || allowedConfigs.empty()) {
- return BAD_VALUE;
- }
-
- if (mDebugDisplayConfigSetByBackdoor) {
- // ignore this request as config is overridden by backdoor
- return NO_ERROR;
- }
-
- postMessageSync(new LambdaMessage([&]() {
- const auto display = getDisplayDeviceLocked(displayToken);
- if (!display) {
- ALOGE("Attempt to set allowed display configs for invalid display token %p",
- displayToken.get());
- } else if (display->isVirtual()) {
- ALOGW("Attempt to set allowed display configs for virtual display");
- } else {
- Mutex::Autolock lock(mStateLock);
- setAllowedDisplayConfigsInternal(display, allowedConfigs);
- }
- }));
-
- return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- std::vector<int32_t>* outAllowedConfigs) {
- ATRACE_CALL();
-
- if (!displayToken || !outAllowedConfigs) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mStateLock);
-
- const auto display = getDisplayDeviceLocked(displayToken);
- if (!display) {
- return NAME_NOT_FOUND;
- }
-
- if (display->isPrimary()) {
- outAllowedConfigs->reserve(mAllowedDisplayConfigs.size());
- for (auto configId : mAllowedDisplayConfigs) {
- outAllowedConfigs->push_back(configId.value());
- }
+ ALOGV("switching to config %d", defaultConfig.value());
+ setDesiredActiveConfig({defaultConfig, Scheduler::ConfigEvent::Changed});
}
return NO_ERROR;
}
status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultModeId, float minRefreshRate,
+ int32_t defaultConfig, float minRefreshRate,
float maxRefreshRate) {
ATRACE_CALL();
@@ -5607,39 +5644,34 @@
return BAD_VALUE;
}
+ status_t result = NO_ERROR;
+
postMessageSync(new LambdaMessage([&]() {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
+ result = BAD_VALUE;
ALOGE("Attempt to set desired display configs for invalid display token %p",
displayToken.get());
} else if (display->isVirtual()) {
+ result = BAD_VALUE;
ALOGW("Attempt to set desired display configs for virtual display");
} else {
- // TODO(b/142507213): Plug through to HWC once the interface is ready.
- Mutex::Autolock lock(mStateLock);
- const DesiredDisplayConfigSpecs desiredDisplayConfigSpecs = {defaultModeId,
- minRefreshRate,
- maxRefreshRate};
- if (desiredDisplayConfigSpecs == mDesiredDisplayConfigSpecs) {
- return;
- }
- ALOGV("Updating desired display configs");
- ALOGD("desiredDisplayConfigSpecs: defaultId: %d min: %.f max: %.f decisions: ",
- desiredDisplayConfigSpecs.defaultModeId, desiredDisplayConfigSpecs.minRefreshRate,
- desiredDisplayConfigSpecs.maxRefreshRate);
- mDesiredDisplayConfigSpecs = desiredDisplayConfigSpecs;
+ result =
+ setDesiredDisplayConfigSpecsInternal(display, HwcConfigIndexType(defaultConfig),
+ minRefreshRate, maxRefreshRate);
}
}));
- return NO_ERROR;
+
+ return result;
}
status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultModeId,
+ int32_t* outDefaultConfig,
float* outMinRefreshRate,
float* outMaxRefreshRate) {
ATRACE_CALL();
- if (!displayToken || !outDefaultModeId || !outMinRefreshRate || !outMaxRefreshRate) {
+ if (!displayToken || !outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) {
return BAD_VALUE;
}
@@ -5650,12 +5682,23 @@
}
if (display->isPrimary()) {
- *outDefaultModeId = mDesiredDisplayConfigSpecs.defaultModeId;
- *outMinRefreshRate = mDesiredDisplayConfigSpecs.minRefreshRate;
- *outMaxRefreshRate = mDesiredDisplayConfigSpecs.maxRefreshRate;
+ HwcConfigIndexType defaultConfig;
+ mRefreshRateConfigs->getPolicy(&defaultConfig, outMinRefreshRate, outMaxRefreshRate);
+ *outDefaultConfig = defaultConfig.value();
+ return NO_ERROR;
+ } else if (display->isVirtual()) {
+ return BAD_VALUE;
+ } else {
+ const auto displayId = display->getId();
+ if (!displayId) {
+ return BAD_VALUE;
+ }
+ *outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId);
+ auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod();
+ *outMinRefreshRate = 1e9f / vsyncPeriod;
+ *outMaxRefreshRate = 1e9f / vsyncPeriod;
+ return NO_ERROR;
}
-
- return NO_ERROR;
}
void SurfaceFlinger::SetInputWindowsListener::onSetInputWindowsFinished() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 53b8908..ec7f871 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -384,17 +384,6 @@
void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
};
- struct DesiredDisplayConfigSpecs {
- int32_t defaultModeId;
- float minRefreshRate;
- float maxRefreshRate;
-
- bool operator==(const DesiredDisplayConfigSpecs& other) const {
- return defaultModeId == other.defaultModeId && minRefreshRate == other.minRefreshRate &&
- maxRefreshRate == other.maxRefreshRate;
- }
- };
-
/* ------------------------------------------------------------------------
* IBinder interface
*/
@@ -449,6 +438,12 @@
ui::DisplayPrimaries &primaries);
ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
+ status_t getAutoLowLatencyModeSupport(const sp<IBinder>& displayToken,
+ bool* outSupported) const override;
+ void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) override;
+ status_t getGameContentTypeSupport(const sp<IBinder>& displayToken,
+ bool* outSupported) const override;
+ void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
status_t setActiveConfig(const sp<IBinder>& displayToken, int id) override;
status_t clearAnimationFrameStats() override;
@@ -478,14 +473,10 @@
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
- status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- const std::vector<int32_t>& allowedConfigs) override;
- status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- std::vector<int32_t>* outAllowedConfigs) override;
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
float minRefreshRate, float maxRefreshRate) override;
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultModeId, float* outMinRefreshRate,
+ int32_t* outDefaultConfig, float* outMinRefreshRate,
float* outMaxRefreshRate) override;
status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
bool* outSupport) const override;
@@ -559,10 +550,16 @@
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
- // called on the main thread in response to setAllowedDisplayConfigs()
- void setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
- const std::vector<int32_t>& allowedConfigs)
- REQUIRES(mStateLock);
+ // Sets the desired display configs.
+ status_t setDesiredDisplayConfigSpecsInternal(const sp<DisplayDevice>& display,
+ HwcConfigIndexType defaultConfig,
+ float minRefreshRate, float maxRefreshRate)
+ EXCLUDES(mStateLock);
+
+ // called on the main thread in response to setAutoLowLatencyMode()
+ void setAutoLowLatencyModeInternal(const sp<IBinder>& displayToken, bool on);
+ // called on the main thread in response to setGameContentType()
+ void setGameContentTypeInternal(const sp<IBinder>& displayToken, bool on);
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -1140,11 +1137,6 @@
std::atomic<nsecs_t> mExpectedPresentTime = 0;
- // All configs are allowed if the set is empty.
- using DisplayConfigs = std::set<HwcConfigIndexType>;
- DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock);
- DesiredDisplayConfigSpecs mDesiredDisplayConfigSpecs GUARDED_BY(mStateLock);
-
std::mutex mActiveConfigLock;
// This bit is set once we start setting the config. We read from this bit during the
// process. If at the end, this bit is different than mDesiredActiveConfig, we restart
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index ca7e18d..dcfc077 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -21,7 +21,6 @@
"CommonTypes_test.cpp",
"Credentials_test.cpp",
"DereferenceSurfaceControl_test.cpp",
- "DisplayActiveConfig_test.cpp",
"DisplayConfigs_test.cpp",
"InvalidHandles_test.cpp",
"LayerCallback_test.cpp",
diff --git a/services/surfaceflinger/tests/DisplayActiveConfig_test.cpp b/services/surfaceflinger/tests/DisplayActiveConfig_test.cpp
deleted file mode 100644
index 2e3b760..0000000
--- a/services/surfaceflinger/tests/DisplayActiveConfig_test.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <thread>
-#include "LayerTransactionTest.h"
-namespace android {
-
-using android::hardware::graphics::common::V1_1::BufferUsage;
-
-::testing::Environment* const binderEnv =
- ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
-
-class DisplayActiveConfigTest : public ::testing::Test {
-protected:
- void SetUp() override {
- mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
- SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &mDisplayconfigs);
- EXPECT_GT(mDisplayconfigs.size(), 0);
-
- // set display power to on to make sure config can be changed
- SurfaceComposerClient::setDisplayPowerMode(mDisplayToken, HWC_POWER_MODE_NORMAL);
- }
-
- sp<IBinder> mDisplayToken;
- Vector<DisplayInfo> mDisplayconfigs;
-};
-
-TEST_F(DisplayActiveConfigTest, allConfigsAllowed) {
- std::vector<int32_t> allowedConfigs;
-
- // Add all configs to the allowed configs
- for (int i = 0; i < mDisplayconfigs.size(); i++) {
- allowedConfigs.push_back(i);
- }
-
- status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
- EXPECT_EQ(res, NO_ERROR);
-
- std::vector<int32_t> outConfigs;
- res = SurfaceComposerClient::getAllowedDisplayConfigs(mDisplayToken, &outConfigs);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(allowedConfigs, outConfigs);
-}
-
-TEST_F(DisplayActiveConfigTest, changeAllowedConfig) {
- // we need at least 2 configs available for this test
- if (mDisplayconfigs.size() <= 1) return;
-
- int activeConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
-
- // We want to set the allowed config to everything but the active config
- std::vector<int32_t> allowedConfigs;
- for (int i = 0; i < mDisplayconfigs.size(); i++) {
- if (i != activeConfig) {
- allowedConfigs.push_back(i);
- }
- }
-
- status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
- EXPECT_EQ(res, NO_ERROR);
-
- // Allow some time for the config change
- std::this_thread::sleep_for(200ms);
-
- int newActiveConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
- EXPECT_NE(activeConfig, newActiveConfig);
-
- // Make sure the new config is part of allowed config
- EXPECT_TRUE(std::find(allowedConfigs.begin(), allowedConfigs.end(), newActiveConfig) !=
- allowedConfigs.end());
-}
-} // namespace android
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index 6d79615..0c370a6 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -760,6 +760,22 @@
return V2_4::Error::UNSUPPORTED;
}
+V2_4::Error FakeComposerClient::setAutoLowLatencyMode(Display, bool) {
+ ALOGV("setAutoLowLatencyMode");
+ return V2_4::Error::UNSUPPORTED;
+}
+
+V2_4::Error FakeComposerClient::getSupportedContentTypes(
+ Display, std::vector<IComposerClient::ContentType>*) {
+ ALOGV("getSupportedContentTypes");
+ return V2_4::Error::UNSUPPORTED;
+}
+
+V2_4::Error FakeComposerClient::setContentType(Display, IComposerClient::ContentType) {
+ ALOGV("setContentType");
+ return V2_4::Error::UNSUPPORTED;
+}
+
//////////////////////////////////////////////////////////////////
void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index 2a08b9b..f9ff2bf 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -246,6 +246,11 @@
Display display, Config config,
const V2_4::IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
VsyncPeriodChangeTimeline* outTimeline) override;
+ V2_4::Error setAutoLowLatencyMode(Display display, bool on) override;
+ V2_4::Error getSupportedContentTypes(
+ Display display,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
+ V2_4::Error setContentType(Display display, IComposerClient::ContentType type) override;
void setClient(ComposerClient* client);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 546e65c..ed620ef 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -79,6 +79,16 @@
ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported());
}
+TEST_F(RefreshRateConfigsTest, invalidPolicy) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+ ASSERT_LT(refreshRateConfigs->setPolicy(HwcConfigIndexType(10), 60, 60, nullptr), 0);
+ ASSERT_LT(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 20, 40, nullptr), 0);
+}
+
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -123,7 +133,7 @@
ASSERT_EQ(expectedDefaultConfig, minRate60);
ASSERT_EQ(expectedDefaultConfig, performanceRate60);
- refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90);
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
@@ -154,7 +164,7 @@
90};
ASSERT_EQ(expectedPerformanceConfig, performanceRate);
- refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60);
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -181,7 +191,7 @@
EXPECT_EQ(current.configId, HWC_CONFIG_ID_90);
}
- refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 90, 90);
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
{
auto current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.configId, HWC_CONFIG_ID_90);
@@ -207,20 +217,20 @@
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f));
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f));
- refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60);
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(90.0f));
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f));
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(45.0f));
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f));
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f));
- refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 90, 90);
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f));
ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(60.0f));
ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f));
ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(30.0f));
ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(24.0f));
- refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120);
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0);
ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f));
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f));
ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f));
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 2453ccb..0f9dd5b 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -130,6 +130,10 @@
MOCK_METHOD4(setActiveConfigWithConstraints,
V2_4::Error(Display, Config, const IComposerClient::VsyncPeriodChangeConstraints&,
VsyncPeriodChangeTimeline*));
+ MOCK_METHOD2(setAutoLowLatencyMode, V2_4::Error(Display, bool));
+ MOCK_METHOD2(getSupportedContentTypes,
+ V2_4::Error(Display, std::vector<IComposerClient::ContentType>*));
+ MOCK_METHOD2(setContentType, V2_4::Error(Display, IComposerClient::ContentType));
};
} // namespace mock