Merge "Update external display property in hardware_composer."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index a8e6738..b781da3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2328,9 +2328,6 @@
// clang-format off
case 'd': do_add_date = true; break;
case 'z': do_zip_file = true; break;
- // o=use_outfile not supported anymore.
- // TODO(b/111441001): Remove when all callers have migrated.
- case 'o': break;
case 's': use_socket = true; break;
case 'S': use_control_socket = true; break;
case 'v': show_header_only = true; break;
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 14937b8..e491a4b 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -11,8 +11,7 @@
# dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
# it is finished.
-service dumpstatez /system/bin/dumpstate -S -d -z \
- -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
+service dumpstatez /system/bin/dumpstate -S -d -z
socket dumpstate stream 0660 shell log
class main
disabled
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 181046a..dbbcdff 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -201,9 +201,7 @@
(char*)"dumpstate",
(char*)"-d",
(char*)"-z",
- (char*)"-B",
- (char*)"-o",
- (char*)dirname(android::base::GetExecutablePath().c_str())
+ (char*)"-B"
};
// clang-format on
sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 3ada153..cbac839 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -53,7 +53,7 @@
MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
MOCK_METHOD1(listServices, Vector<String16>(int));
-
+ MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 119e4c3..b3aa342 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -28,6 +28,13 @@
ServiceManager::~ServiceManager() {
// this should only happen in tests
+ for (const auto& [name, callbacks] : mNameToCallback) {
+ CHECK(!callbacks.empty()) << name;
+ for (const auto& callback : callbacks) {
+ CHECK(callback != nullptr) << name;
+ }
+ }
+
for (const auto& [name, service] : mNameToService) {
CHECK(service.binder != nullptr) << name;
}
@@ -117,6 +124,14 @@
.dumpPriority = dumpPriority,
};
+ auto it = mNameToCallback.find(name);
+ if (it != mNameToCallback.end()) {
+ for (const sp<IServiceCallback>& cb : it->second) {
+ // permission checked in registerForNotifications
+ cb->onRegistration(name, binder);
+ }
+ }
+
return Status::ok();
}
@@ -146,6 +161,84 @@
return Status::ok();
}
+Status ServiceManager::registerForNotifications(
+ const std::string& name, const sp<IServiceCallback>& callback) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ if (!isValidServiceName(name)) {
+ LOG(ERROR) << "Invalid service name: " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (callback == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+
+ if (OK != IInterface::asBinder(callback)->linkToDeath(this)) {
+ LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ mNameToCallback[name].push_back(callback);
+
+ if (auto it = mNameToService.find(name); it != mNameToService.end()) {
+ const sp<IBinder>& binder = it->second.binder;
+
+ // never null if an entry exists
+ CHECK(binder != nullptr) << name;
+ callback->onRegistration(name, binder);
+ }
+
+ return Status::ok();
+}
+Status ServiceManager::unregisterForNotifications(
+ const std::string& name, const sp<IServiceCallback>& callback) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ bool found = false;
+
+ auto it = mNameToCallback.find(name);
+ if (it != mNameToCallback.end()) {
+ removeCallback(IInterface::asBinder(callback), &it, &found);
+ }
+
+ if (!found) {
+ LOG(ERROR) << "Trying to unregister callback, but none exists " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ return Status::ok();
+}
+
+void ServiceManager::removeCallback(const wp<IBinder>& who,
+ CallbackMap::iterator* it,
+ bool* found) {
+ std::vector<sp<IServiceCallback>>& listeners = (*it)->second;
+
+ for (auto lit = listeners.begin(); lit != listeners.end();) {
+ if (IInterface::asBinder(*lit) == who) {
+ if(found) *found = true;
+ lit = listeners.erase(lit);
+ } else {
+ ++lit;
+ }
+ }
+
+ if (listeners.empty()) {
+ *it = mNameToCallback.erase(*it);
+ } else {
+ it++;
+ }
+}
+
void ServiceManager::binderDied(const wp<IBinder>& who) {
for (auto it = mNameToService.begin(); it != mNameToService.end();) {
if (who == it->second.binder) {
@@ -154,6 +247,10 @@
++it;
}
}
+
+ for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) {
+ removeCallback(who, &it, nullptr /*found*/);
+ }
}
} // namespace android
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 43723c5..fcc5124 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -17,11 +17,14 @@
#pragma once
#include <android/os/BnServiceManager.h>
+#include <android/os/IServiceCallback.h>
#include "Access.h"
namespace android {
+using os::IServiceCallback;
+
class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
public:
ServiceManager(std::unique_ptr<Access>&& access);
@@ -29,19 +32,35 @@
binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override;
binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override;
- binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override;
+ binder::Status addService(const std::string& name, const sp<IBinder>& binder,
+ bool allowIsolated, int32_t dumpPriority) override;
binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override;
+ binder::Status registerForNotifications(const std::string& name,
+ const sp<IServiceCallback>& callback) override;
+ binder::Status unregisterForNotifications(const std::string& name,
+ const sp<IServiceCallback>& callback) override;
void binderDied(const wp<IBinder>& who) override;
private:
struct Service {
- sp<IBinder> binder;
+ sp<IBinder> binder; // not null
bool allowIsolated;
int32_t dumpPriority;
};
- std::map<std::string, Service> mNameToService;
+ using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>;
+ using ServiceMap = std::map<std::string, Service>;
+
+ // removes a callback from mNameToCallback, removing it if the vector is empty
+ // this updates iterator to the next location
+ void removeCallback(const wp<IBinder>& who,
+ CallbackMap::iterator* it,
+ bool* found);
+
+ CallbackMap mNameToCallback;
+ ServiceMap mNameToService;
+
std::unique_ptr<Access> mAccess;
};
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 91485e4..3c211d2 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <android/os/BnServiceCallback.h>
+#include <binder/Binder.h>
#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <cutils/android_filesystem_config.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
@@ -24,8 +27,11 @@
using android::sp;
using android::Access;
+using android::BBinder;
using android::IBinder;
using android::ServiceManager;
+using android::binder::Status;
+using android::os::BnServiceCallback;
using android::os::IServiceManager;
using testing::_;
using testing::ElementsAre;
@@ -33,9 +39,14 @@
using testing::Return;
static sp<IBinder> getBinder() {
- // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work.
- // The context manager (servicemanager) is easy to get and is in another process.
- return android::ProcessState::self()->getContextObject(nullptr);
+ class LinkableBinder : public BBinder {
+ android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override {
+ // let SM linkToDeath
+ return android::OK;
+ }
+ };
+
+ return new LinkableBinder;
}
class MockAccess : public Access {
@@ -132,12 +143,14 @@
TEST(GetService, HappyHappy) {
auto sm = getPermissiveServiceManager();
- EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ sp<IBinder> service = getBinder();
+
+ EXPECT_TRUE(sm->addService("foo", service, false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
sp<IBinder> out;
EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(getBinder(), out);
+ EXPECT_EQ(service, out);
}
TEST(GetService, NonExistant) {
@@ -181,12 +194,13 @@
sp<ServiceManager> sm = new ServiceManager(std::move(access));
- EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/,
+ sp<IBinder> service = getBinder();
+ EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
sp<IBinder> out;
EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(getBinder(), out.get());
+ EXPECT_EQ(service, out.get());
}
TEST(GetService, NotAllowedFromIsolated) {
@@ -265,3 +279,145 @@
// all there and in the right order
EXPECT_THAT(out, ElementsAre("sa"));
}
+
+class CallbackHistorian : public BnServiceCallback {
+ Status onRegistration(const std::string& name, const sp<IBinder>& binder) override {
+ registrations.push_back(name);
+ binders.push_back(binder);
+ return Status::ok();
+ }
+
+ android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override {
+ // let SM linkToDeath
+ return android::OK;
+ }
+
+public:
+ std::vector<std::string> registrations;
+ std::vector<sp<IBinder>> binders;
+};
+
+TEST(ServiceNotifications, NoPermissionsRegister) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{}));
+ EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_EQ(sm->registerForNotifications("foofoo", cb).exceptionCode(),
+ Status::EX_SECURITY);
+}
+
+TEST(ServiceNotifications, NoPermissionsUnregister) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{}));
+ EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ // should always hit security error first
+ EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(),
+ Status::EX_SECURITY);
+}
+
+TEST(ServiceNotifications, InvalidName) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_EQ(sm->registerForNotifications("foo@foo", cb).exceptionCode(),
+ Status::EX_ILLEGAL_ARGUMENT);
+}
+
+TEST(ServiceNotifications, NullCallback) {
+ auto sm = getPermissiveServiceManager();
+
+ EXPECT_EQ(sm->registerForNotifications("foofoo", nullptr).exceptionCode(),
+ Status::EX_NULL_POINTER);
+}
+
+TEST(ServiceNotifications, Unregister) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk());
+ EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), 0);
+}
+
+TEST(ServiceNotifications, UnregisterWhenNoRegistrationExists) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(),
+ Status::EX_ILLEGAL_STATE);
+}
+
+TEST(ServiceNotifications, NoNotification) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk());
+ EXPECT_TRUE(sm->addService("otherservice", getBinder(),
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_THAT(cb->registrations, ElementsAre());
+ EXPECT_THAT(cb->binders, ElementsAre());
+}
+
+TEST(ServiceNotifications, GetNotification) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ sp<IBinder> service = getBinder();
+
+ EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk());
+ EXPECT_TRUE(sm->addService("asdfasdf", service,
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf"));
+ EXPECT_THAT(cb->binders, ElementsAre(service));
+}
+
+TEST(ServiceNotifications, GetNotificationForAlreadyRegisteredService) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ sp<IBinder> service = getBinder();
+
+ EXPECT_TRUE(sm->addService("asdfasdf", service,
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk());
+
+ EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf"));
+ EXPECT_THAT(cb->binders, ElementsAre(service));
+}
+
+TEST(ServiceNotifications, GetMultipleNotification) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ sp<IBinder> binder1 = getBinder();
+ sp<IBinder> binder2 = getBinder();
+
+ EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk());
+ EXPECT_TRUE(sm->addService("asdfasdf", binder1,
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+ EXPECT_TRUE(sm->addService("asdfasdf", binder2,
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf"));
+ EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf"));
+}
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 027418a..6ece4a2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -86,10 +86,8 @@
vendor: {
exclude_srcs: [
"ActivityManager.cpp",
- "AppOpsManager.cpp",
"IActivityManager.cpp",
"IAppOpsCallback.cpp",
- "IAppOpsService.cpp",
"IBatteryStats.cpp",
"IMediaResourceMonitor.cpp",
"IPermissionController.cpp",
@@ -145,6 +143,7 @@
name: "libbinder_aidl",
srcs: [
"aidl/android/content/pm/IPackageManagerNative.aidl",
+ "aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
],
path: "aidl",
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 525685c..e2af01c 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -21,10 +21,18 @@
#include <utils/SystemClock.h>
+#include <sys/types.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AppOpsManager"
+
namespace android {
namespace {
+#ifndef __ANDROID_VNDK__
#if defined(__BRILLO__)
// Because Brillo has no application model, security policy is managed
// statically (at build time) with SELinux controls.
@@ -33,13 +41,17 @@
#else
const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED;
#endif // defined(__BRILLO__)
+#endif // __ANDROID_VNDK__
} // namespace
static String16 _appops("appops");
+#ifndef __ANDROID_VNDK__
static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER;
+#endif // __ANDROID_VNDK__
static sp<IBinder> gToken;
+#ifndef __ANDROID_VNDK__
static const sp<IBinder>& getToken(const sp<IAppOpsService>& service) {
pthread_mutex_lock(&gTokenMutex);
if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) {
@@ -48,6 +60,17 @@
pthread_mutex_unlock(&gTokenMutex);
return gToken;
}
+#endif // __ANDROID_VNDK__
+
+thread_local uint64_t notedAppOpsInThisBinderTransaction[2];
+thread_local int32_t uidOfThisBinderTransaction = -1;
+
+// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note
+#ifndef __ANDROID_VNDK__
+uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0};
+#else
+uint8_t appOpsToNote[128] = {0};
+#endif // __ANDROID_VNDK__
AppOpsManager::AppOpsManager()
{
@@ -85,6 +108,7 @@
}
#endif // defined(__BRILLO__)
+#ifndef __ANDROID_VNDK__
int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
{
sp<IAppOpsService> service = getService();
@@ -102,18 +126,41 @@
}
int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
+ return noteOp(op, uid, callingPackage, String16("noteOp from native code"));
+}
+
+int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
+ const String16& message) {
sp<IAppOpsService> service = getService();
- return service != nullptr
+ int32_t mode = service != nullptr
? service->noteOperation(op, uid, callingPackage)
: APP_OPS_MANAGER_UNAVAILABLE_MODE;
+
+ if (mode == AppOpsManager::MODE_ALLOWED) {
+ markAppOpNoted(uid, callingPackage, op, message);
+ }
+
+ return mode;
}
int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault) {
+ return startOpNoThrow(op, uid, callingPackage, startIfModeDefault,
+ String16("startOpNoThrow from native code"));
+}
+
+int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+ bool startIfModeDefault, const String16& message) {
sp<IAppOpsService> service = getService();
- return service != nullptr
+ int32_t mode = service != nullptr
? service->startOperation(getToken(service), op, uid, callingPackage,
startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+
+ if (mode == AppOpsManager::MODE_ALLOWED) {
+ markAppOpNoted(uid, callingPackage, op, message);
+ }
+
+ return mode;
}
void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
@@ -146,5 +193,47 @@
return -1;
}
+void AppOpsManager::setCameraAudioRestriction(int32_t mode) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ service->setCameraAudioRestriction(mode);
+ }
+}
+
+#endif // __ANDROID_VNDK__
+
+bool AppOpsManager::shouldCollectNotes(int32_t opcode) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ return service->shouldCollectNotes(opcode);
+ }
+ return false;
+}
+
+void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
+ const String16& message) {
+ // check it the appops needs to be collected and cache result
+ if (appOpsToNote[opCode] == 0) {
+ if (shouldCollectNotes(opCode)) {
+ appOpsToNote[opCode] = 2;
+ } else {
+ appOpsToNote[opCode] = 1;
+ }
+ }
+
+ if (appOpsToNote[opCode] != 2) {
+ return;
+ }
+
+ noteAsyncOp(String16(), uid, packageName, opCode, message);
+}
+
+void AppOpsManager::noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+ }
+}
}; // namespace android
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index c426f3a..b6360cb 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -34,6 +34,7 @@
{
}
+#ifndef __ANDROID_VNDK__
virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -111,7 +112,6 @@
return reply.readStrongBinder();
}
-
virtual int32_t permissionToOpCode(const String16& permission) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -137,6 +137,52 @@
}
return reply.readInt32();
}
+
+ virtual void setCameraAudioRestriction(int32_t mode) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION, data, &reply);
+ }
+
+#endif
+ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+
+ // Convert empty callingPackage into null string
+ if (callingPackageName.size() != 0) {
+ data.writeString16(callingPackageName);
+ } else {
+ data.writeString16(nullptr, 0);
+ }
+
+ data.writeInt32(uid);
+
+ // Convert empty packageName into null string
+ if (packageName.size() != 0) {
+ data.writeString16(packageName);
+ } else {
+ data.writeString16(nullptr, 0);
+ }
+
+ data.writeInt32(opCode);
+ data.writeString16(message);
+ remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply);
+ }
+
+ virtual bool shouldCollectNotes(int32_t opCode) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeInt32(opCode);
+ remote()->transact(SHOULD_COLLECT_NOTES_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) {
+ return false;
+ }
+ return reply.readBool();
+ }
};
IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
@@ -149,6 +195,7 @@
{
//printf("AppOpsService received: "); data.print();
switch(code) {
+#ifndef __ANDROID_VNDK__
case CHECK_OPERATION_TRANSACTION: {
CHECK_INTERFACE(IAppOpsService, data, reply);
int32_t code = data.readInt32();
@@ -234,6 +281,33 @@
reply->writeInt32(res);
return NO_ERROR;
} break;
+ case SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ const int32_t mode = data.readInt32();
+ setCameraAudioRestriction(mode);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+#endif // __ANDROID_VNDK__
+ case NOTE_ASYNC_OP_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ String16 callingPackageName = data.readString16();
+ int32_t uid = data.readInt32();
+ String16 packageName = data.readString16();
+ int32_t opCode = data.readInt32();
+ String16 message = data.readString16();
+ noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case SHOULD_COLLECT_NOTES_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ int32_t opCode = data.readInt32();
+ bool shouldCollect = shouldCollectNotes(opCode);
+ reply->writeNoException();
+ reply->writeBool(shouldCollect);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 74f1f47..715a460 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -18,6 +18,7 @@
#include <binder/IServiceManager.h>
+#include <android/os/BnServiceCallback.h>
#include <android/os/IServiceManager.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
@@ -212,6 +213,64 @@
return res;
}
+ sp<IBinder> waitForService(const String16& name16) override {
+ class Waiter : public android::os::BnServiceCallback {
+ Status onRegistration(const std::string& /*name*/,
+ const sp<IBinder>& binder) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mBinder = binder;
+ lock.unlock();
+ mCv.notify_one();
+ return Status::ok();
+ }
+ public:
+ sp<IBinder> mBinder;
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ };
+
+ const std::string name = String8(name16).c_str();
+
+ sp<IBinder> out;
+ if(!mTheRealServiceManager->checkService(name, &out).isOk()) {
+ return nullptr;
+ }
+ if(out != nullptr) return out;
+
+ sp<Waiter> waiter = new Waiter;
+ if (!mTheRealServiceManager->registerForNotifications(
+ name, waiter).isOk()) {
+ return nullptr;
+ }
+
+ while(true) {
+ {
+ std::unique_lock<std::mutex> lock(waiter->mMutex);
+ using std::literals::chrono_literals::operator""s;
+ waiter->mCv.wait_for(lock, 1s, [&] {
+ return waiter->mBinder != nullptr;
+ });
+ if (waiter->mBinder != nullptr) return waiter->mBinder;
+ }
+
+ // Handle race condition for lazy services. Here is what can happen:
+ // - the service dies (not processed by init yet).
+ // - sm processes death notification.
+ // - sm gets checkService and calls init to start service.
+ // - init gets the start signal, but the service already appears
+ // started, so it does nothing.
+ // - init gets death signal, but doesn't know it needs to restart
+ // the service
+ // - we need to request service again to get it to start
+ if(!mTheRealServiceManager->checkService(name, &out).isOk()) {
+ return nullptr;
+ }
+ if(out != nullptr) return out;
+
+ ALOGW("Waited one second for %s", name.c_str());
+ }
+ }
+
private:
sp<AidlServiceManager> mTheRealServiceManager;
};
diff --git a/libs/binder/IpPrefix.cpp b/libs/binder/IpPrefix.cpp
index 3a8a63c..8d62266 100644
--- a/libs/binder/IpPrefix.cpp
+++ b/libs/binder/IpPrefix.cpp
@@ -30,7 +30,6 @@
using android::Parcel;
using android::status_t;
using android::UNEXPECTED_NULL;
-using namespace ::android::binder;
namespace android {
diff --git a/libs/binder/aidl/android/os/IServiceCallback.aidl b/libs/binder/aidl/android/os/IServiceCallback.aidl
new file mode 100644
index 0000000..b29dfed
--- /dev/null
+++ b/libs/binder/aidl/android/os/IServiceCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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 IServiceCallback {
+ /**
+ * Called when a service is registered.
+ *
+ * @param name the service name that has been registered with
+ * @param binder the binder that is registered
+ */
+ void onRegistration(@utf8InCpp String name, IBinder binder);
+}
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 50a72aa..60c2cce 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.os.IServiceCallback;
+
/**
* Basic interface for finding and publishing system services.
*
@@ -77,4 +79,14 @@
* Return a list of all currently running services.
*/
@utf8InCpp String[] listServices(int dumpPriority);
+
+ /**
+ * Request a callback when a service is registered.
+ */
+ void registerForNotifications(@utf8InCpp String name, IServiceCallback callback);
+
+ /**
+ * Unregisters all requests for notifications for a specific callback.
+ */
+ void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback);
}
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 17493b4..dff4d49 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -17,8 +17,6 @@
#ifndef ANDROID_APP_OPS_MANAGER_H
#define ANDROID_APP_OPS_MANAGER_H
-#ifndef __ANDROID_VNDK__
-
#include <binder/IAppOpsService.h>
#include <utils/threads.h>
@@ -35,6 +33,7 @@
MODE_ERRORED = IAppOpsService::MODE_ERRORED
};
+#ifndef __ANDROID_VNDK__
enum {
OP_NONE = -1,
OP_COARSE_LOCATION = 0,
@@ -109,34 +108,60 @@
OP_START_FOREGROUND = 76,
OP_BLUETOOTH_SCAN = 77,
OP_USE_BIOMETRIC = 78,
+ OP_ACTIVITY_RECOGNITION = 79,
+ OP_SMS_FINANCIAL_TRANSACTIONS = 80,
+ OP_READ_MEDIA_AUDIO = 81,
+ OP_WRITE_MEDIA_AUDIO = 82,
+ OP_READ_MEDIA_VIDEO = 83,
+ OP_WRITE_MEDIA_VIDEO = 84,
+ OP_READ_MEDIA_IMAGES = 85,
+ OP_WRITE_MEDIA_IMAGES = 86,
+ OP_LEGACY_STORAGE = 87,
+ OP_ACCESS_ACCESSIBILITY = 88,
+ OP_READ_DEVICE_IDENTIFIERS = 89,
+ _NUM_OP = 90
};
+#endif // __ANDROID_VNDK__
AppOpsManager();
+#ifndef __ANDROID_VNDK__
int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
const String16& callingPackage);
+ // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&) instead
int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
+ int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
+ const String16& message);
+ // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&)
+ // instead
int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault);
+ int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+ bool startIfModeDefault, const String16& message);
void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback);
void stopWatchingMode(const sp<IAppOpsCallback>& callback);
int32_t permissionToOpCode(const String16& permission);
+ void setCameraAudioRestriction(int32_t mode);
+#endif // __ANDROID_VNDK__
+ void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName,
+ int32_t opCode, const String16& message);
private:
Mutex mLock;
sp<IAppOpsService> mService;
sp<IAppOpsService> getService();
+ void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
+ const String16& message);
+ bool shouldCollectNotes(int32_t opCode);
};
}; // namespace android
+
// ---------------------------------------------------------------------------
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
#endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 3dbd0d9..009ef6c 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -19,8 +19,8 @@
#define ANDROID_IAPP_OPS_SERVICE_H
#ifndef __ANDROID_VNDK__
-
#include <binder/IAppOpsCallback.h>
+#endif
#include <binder/IInterface.h>
namespace android {
@@ -32,6 +32,7 @@
public:
DECLARE_META_INTERFACE(AppOpsService)
+#ifndef __ANDROID_VNDK__
virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
@@ -45,8 +46,14 @@
virtual int32_t permissionToOpCode(const String16& permission) = 0;
virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid,
const String16& packageName) = 0;
+ virtual void setCameraAudioRestriction(int32_t mode) = 0;
+#endif // __ANDROID_VNDK__
+ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) = 0;
+ virtual bool shouldCollectNotes(int32_t opCode) = 0;
enum {
+#ifndef __ANDROID_VNDK__
CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1,
START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2,
@@ -56,6 +63,13 @@
GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
+#endif // __ANDROID_VNDK__
+ NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
+ SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10,
+#ifndef __ANDROID_VNDK__
+ SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+11,
+#endif // __ANDROID_VNDK__
+
};
enum {
@@ -81,8 +95,4 @@
}; // namespace android
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
-
#endif // ANDROID_IAPP_OPS_SERVICE_H
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 30786fa..8ae860d 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -71,11 +71,24 @@
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
+
+ /**
+ * Efficiently wait for a service.
+ *
+ * Returns nullptr only for permission problem or fatal error.
+ */
+ virtual sp<IBinder> waitForService(const String16& name) = 0;
};
sp<IServiceManager> defaultServiceManager();
template<typename INTERFACE>
+sp<INTERFACE> waitForService(const String16& name) {
+ const sp<IServiceManager> sm = defaultServiceManager();
+ return interface_cast<INTERFACE>(sm->waitForService(name));
+}
+
+template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index f5aafc7..c2f6d55 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -45,10 +45,6 @@
class String8;
class TextOutput;
-namespace binder {
-class Value;
-};
-
class Parcel {
friend class IPCThreadState;
public:
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 528bfb1..3a7cb44 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -166,7 +166,9 @@
mCore->mFreeBuffers.push_back(front->mSlot);
}
- listener = mCore->mConnectedProducerListener;
+ if (mCore->mBufferReleasedCbEnabled) {
+ listener = mCore->mConnectedProducerListener;
+ }
++numDroppedBuffers;
}
@@ -457,7 +459,9 @@
mCore->mFreeBuffers.push_back(slot);
}
- listener = mCore->mConnectedProducerListener;
+ if (mCore->mBufferReleasedCbEnabled) {
+ listener = mCore->mConnectedProducerListener;
+ }
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
mCore->mDequeueCondition.notify_all();
@@ -668,7 +672,7 @@
BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
VALIDATE_CONSISTENCY();
- if (delta < 0) {
+ if (delta < 0 && mCore->mBufferReleasedCbEnabled) {
listener = mCore->mConsumerListener;
}
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index b429d38..d6009d6 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -65,6 +65,7 @@
mConnectedApi(NO_CONNECTED_API),
mLinkedToDeath(),
mConnectedProducerListener(),
+ mBufferReleasedCbEnabled(false),
mSlots(),
mQueue(),
mFreeSlots(),
@@ -264,6 +265,12 @@
}
void BufferQueueCore::discardFreeBuffersLocked() {
+ // Notify producer about the discarded buffers.
+ if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) {
+ std::vector<int32_t> freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end());
+ mConnectedProducerListener->onBuffersDiscarded(freeBuffers);
+ }
+
for (int s : mFreeBuffers) {
mFreeSlots.insert(s);
clearBufferSlotLocked(s);
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index d149674..5674674 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1223,9 +1223,8 @@
}
mCore->mLinkedToDeath = listener;
}
- if (listener->needsReleaseNotify()) {
- mCore->mConnectedProducerListener = listener;
- }
+ mCore->mConnectedProducerListener = listener;
+ mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
}
break;
default:
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 936063a..808e336 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -24,6 +24,7 @@
enum {
ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
NEEDS_RELEASE_NOTIFY,
+ ON_BUFFERS_DISCARDED,
};
class BpProducerListener : public BpInterface<IProducerListener>
@@ -56,6 +57,13 @@
}
return result;
}
+
+ virtual void onBuffersDiscarded(const std::vector<int>& discardedSlots) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+ data.writeInt32Vector(discardedSlots);
+ remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -76,6 +84,10 @@
virtual bool needsReleaseNotify() override {
return mBase->needsReleaseNotify();
}
+
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& discardedSlots) override {
+ return mBase->onBuffersDiscarded(discardedSlots);
+ }
};
IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener,
@@ -92,6 +104,17 @@
CHECK_INTERFACE(IProducerListener, data, reply);
reply->writeBool(needsReleaseNotify());
return NO_ERROR;
+ case ON_BUFFERS_DISCARDED: {
+ CHECK_INTERFACE(IProducerListener, data, reply);
+ std::vector<int32_t> discardedSlots;
+ status_t result = data.readInt32Vector(&discardedSlots);
+ if (result != NO_ERROR) {
+ ALOGE("ON_BUFFERS_DISCARDED failed to read discardedSlots: %d", result);
+ return result;
+ }
+ onBuffersDiscarded(discardedSlots);
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
@@ -104,4 +127,7 @@
return true;
}
+void BnProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*discardedSlots*/) {
+}
+
} // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index eb2e3f0..7e356e4 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -35,6 +35,7 @@
#include <ui/DisplayStatInfo.h>
#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -1300,6 +1301,14 @@
}
int Surface::connect(
+ int api, bool reportBufferRemoval, const sp<SurfaceListener>& sListener) {
+ if (sListener != nullptr) {
+ mListenerProxy = new ProducerListenerProxy(this, sListener);
+ }
+ return connect(api, mListenerProxy, reportBufferRemoval);
+}
+
+int Surface::connect(
int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
ATRACE_CALL();
ALOGV("Surface::connect");
@@ -1700,6 +1709,28 @@
}
}
+status_t Surface::getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots,
+ std::vector<sp<GraphicBuffer>>* outBuffers) {
+ ALOGV("Surface::getAndFlushBuffersFromSlots");
+ for (int32_t i : slots) {
+ if (i < 0 || i >= NUM_BUFFER_SLOTS) {
+ ALOGE("%s: Invalid slotIndex: %d", __FUNCTION__, i);
+ return BAD_VALUE;
+ }
+ }
+
+ Mutex::Autolock lock(mMutex);
+ for (int32_t i : slots) {
+ if (mSlots[i].buffer == nullptr) {
+ ALOGW("%s: Discarded slot %d doesn't contain buffer!", __FUNCTION__, i);
+ continue;
+ }
+ outBuffers->push_back(mSlots[i].buffer);
+ mSlots[i].buffer = nullptr;
+ }
+ return OK;
+}
+
void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) {
ATRACE_CALL();
ALOGV("Surface::setSurfaceDamage");
@@ -1985,4 +2016,22 @@
return err;
}
+void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_t>& slots) {
+ ATRACE_CALL();
+ sp<Surface> parent = mParent.promote();
+ if (parent == nullptr) {
+ return;
+ }
+
+ std::vector<sp<GraphicBuffer>> discardedBufs;
+ status_t res = parent->getAndFlushBuffersFromSlots(slots, &discardedBufs);
+ if (res != OK) {
+ ALOGE("%s: Failed to get buffers from slots: %s(%d)", __FUNCTION__,
+ strerror(-res), res);
+ return;
+ }
+
+ mSurfaceListener->onBuffersDiscarded(discardedBufs);
+}
+
}; // namespace android
diff --git a/libs/gui/TEST_MAPPING b/libs/gui/TEST_MAPPING
new file mode 100644
index 0000000..1c43530
--- /dev/null
+++ b/libs/gui/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/native/libs/nativewindow"
+ }
+ ]
+}
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 205e79c..3c96089 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -189,8 +189,12 @@
sp<IProducerListener> mLinkedToDeath;
// mConnectedProducerListener is used to handle the onBufferReleased
- // notification.
+ // and onBuffersDiscarded notification.
sp<IProducerListener> mConnectedProducerListener;
+ // mBufferReleasedCbEnabled is used to indicate whether onBufferReleased()
+ // callback is registered by the listener. When set to false,
+ // mConnectedProducerListener will not trigger onBufferReleased() callback.
+ bool mBufferReleasedCbEnabled;
// mSlots is an array of buffer slots that must be mirrored on the producer
// side. This allows buffer ownership to be transferred between the producer
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index a13d8e4..32a3690 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GUI_IPRODUCERLISTENER_H
#define ANDROID_GUI_IPRODUCERLISTENER_H
+#include <vector>
+
#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
#include <binder/IInterface.h>
@@ -44,6 +46,9 @@
// multiple threads.
virtual void onBufferReleased() = 0; // Asynchronous
virtual bool needsReleaseNotify() = 0;
+ // onBuffersFreed is called from IGraphicBufferConsumer::discardFreeBuffers
+ // to notify the producer that certain free buffers are discarded by the consumer.
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) = 0; // Asynchronous
};
class IProducerListener : public ProducerListener, public IInterface
@@ -65,6 +70,7 @@
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0);
virtual bool needsReleaseNotify();
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
};
class DummyProducerListener : public BnProducerListener
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index fe528b3..28f5a26 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -20,6 +20,7 @@
#include <gui/BufferQueueDefs.h>
#include <gui/HdrMetadata.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
#include <ui/ANativeObjectBase.h>
#include <ui/GraphicTypes.h>
@@ -35,6 +36,21 @@
class ISurfaceComposer;
+/* This is the same as ProducerListener except that onBuffersDiscarded is
+ * called with a vector of graphic buffers instead of buffer slots.
+ */
+class SurfaceListener : public virtual RefBase
+{
+public:
+ SurfaceListener() = default;
+ virtual ~SurfaceListener() = default;
+
+ virtual void onBufferReleased() = 0;
+ virtual bool needsReleaseNotify() = 0;
+
+ virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) = 0;
+};
+
/*
* An implementation of ANativeWindow that feeds graphics buffers into a
* BufferQueue.
@@ -285,6 +301,10 @@
sp<Fence>* outFence);
virtual int attachBuffer(ANativeWindowBuffer*);
+ virtual int connect(
+ int api, bool reportBufferRemoval,
+ const sp<SurfaceListener>& sListener);
+
// When client connects to Surface with reportBufferRemoval set to true, any buffers removed
// from this Surface will be collected and returned here. Once this method returns, these
// buffers will no longer be referenced by this Surface unless they are attached to this
@@ -301,6 +321,26 @@
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+ class ProducerListenerProxy : public BnProducerListener {
+ public:
+ ProducerListenerProxy(wp<Surface> parent, sp<SurfaceListener> listener)
+ : mParent(parent), mSurfaceListener(listener) {}
+ virtual ~ProducerListenerProxy() {}
+
+ virtual void onBufferReleased() {
+ mSurfaceListener->onBufferReleased();
+ }
+
+ virtual bool needsReleaseNotify() {
+ return mSurfaceListener->needsReleaseNotify();
+ }
+
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
+ private:
+ wp<Surface> mParent;
+ sp<SurfaceListener> mSurfaceListener;
+ };
+
void querySupportedTimestampsLocked() const;
void freeAllBuffers();
@@ -470,6 +510,10 @@
bool mReportRemovedBuffers = false;
std::vector<sp<GraphicBuffer>> mRemovedBuffers;
int mMaxBufferCount;
+
+ sp<IProducerListener> mListenerProxy;
+ status_t getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots,
+ std::vector<sp<GraphicBuffer>>* outBuffers);
};
} // namespace android
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 98dc1e6..6d7b6bb 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1010,12 +1010,31 @@
ASSERT_EQ(true, thirdSegment.usedThirdBuffer);
}
+struct BufferDiscardedListener : public BnProducerListener {
+public:
+ BufferDiscardedListener() = default;
+ virtual ~BufferDiscardedListener() = default;
+
+ virtual void onBufferReleased() {}
+ virtual bool needsReleaseNotify() { return false; }
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) {
+ mDiscardedSlots.insert(mDiscardedSlots.end(), slots.begin(), slots.end());
+ }
+
+ const std::vector<int32_t>& getDiscardedSlots() const { return mDiscardedSlots; }
+private:
+ // No need to use lock given the test triggers the listener in the same
+ // thread context.
+ std::vector<int32_t> mDiscardedSlots;
+};
+
TEST_F(BufferQueueTest, TestDiscardFreeBuffers) {
createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
- ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ sp<BufferDiscardedListener> pl(new BufferDiscardedListener);
+ ASSERT_EQ(OK, mProducer->connect(pl,
NATIVE_WINDOW_API_CPU, false, &output));
int slot = BufferQueue::INVALID_BUFFER_SLOT;
@@ -1056,12 +1075,19 @@
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+ int releasedSlot = item.mSlot;
+
// Acquire 1 buffer, leaving 1 filled buffer in queue
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
// Now discard the free buffers
ASSERT_EQ(OK, mConsumer->discardFreeBuffers());
+ // Check onBuffersDiscarded is called with correct slots
+ auto buffersDiscarded = pl->getDiscardedSlots();
+ ASSERT_EQ(buffersDiscarded.size(), 1);
+ ASSERT_EQ(buffersDiscarded[0], releasedSlot);
+
// Check no free buffers in dump
String8 dumpString;
mConsumer->dumpState(String8{}, &dumpString);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 7718bc1..5a121d7 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -57,6 +57,37 @@
static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max();
+class DummySurfaceListener : public SurfaceListener {
+public:
+ DummySurfaceListener(bool enableReleasedCb = false) :
+ mEnableReleaseCb(enableReleasedCb),
+ mBuffersReleased(0) {}
+ virtual ~DummySurfaceListener() = default;
+
+ virtual void onBufferReleased() {
+ mBuffersReleased++;
+ }
+ virtual bool needsReleaseNotify() {
+ return mEnableReleaseCb;
+ }
+ virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) {
+ mDiscardedBuffers.insert(mDiscardedBuffers.end(), buffers.begin(), buffers.end());
+ }
+
+ int getReleaseNotifyCount() const {
+ return mBuffersReleased;
+ }
+ const std::vector<sp<GraphicBuffer>>& getDiscardedBuffers() const {
+ return mDiscardedBuffers;
+ }
+private:
+ // No need to use lock given the test triggers the listener in the same
+ // thread context.
+ bool mEnableReleaseCb;
+ int32_t mBuffersReleased;
+ std::vector<sp<GraphicBuffer>> mDiscardedBuffers;
+};
+
class SurfaceTest : public ::testing::Test {
protected:
SurfaceTest() {
@@ -88,6 +119,86 @@
mComposerClient->dispose();
}
+ void testSurfaceListener(bool hasSurfaceListener, bool enableReleasedCb,
+ int32_t extraDiscardedBuffers) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setConsumerName(String8("TestConsumer"));
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ sp<DummySurfaceListener> listener;
+ if (hasSurfaceListener) {
+ listener = new DummySurfaceListener(enableReleasedCb);
+ }
+ ASSERT_EQ(OK, surface->connect(
+ NATIVE_WINDOW_API_CPU,
+ /*reportBufferRemoval*/true,
+ /*listener*/listener));
+ const int BUFFER_COUNT = 4 + extraDiscardedBuffers;
+ ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT));
+
+ ANativeWindowBuffer* buffers[BUFFER_COUNT];
+ // Dequeue first to allocate a number of buffers
+ for (int i = 0; i < BUFFER_COUNT; i++) {
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffers[i]));
+ }
+ for (int i = 0; i < BUFFER_COUNT; i++) {
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], -1));
+ }
+
+ ANativeWindowBuffer* buffer;
+ // Fill BUFFER_COUNT-1 buffers
+ for (int i = 0; i < BUFFER_COUNT-1; i++) {
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer));
+ ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, -1));
+ }
+
+ // Dequeue 1 buffer
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer));
+
+ // Acquire and free 1+extraDiscardedBuffers buffer, check onBufferReleased is called.
+ std::vector<BufferItem> releasedItems;
+ releasedItems.resize(1+extraDiscardedBuffers);
+ for (int i = 0; i < releasedItems.size(); i++) {
+ ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&releasedItems[i], 0));
+ ASSERT_EQ(NO_ERROR, consumer->releaseBuffer(releasedItems[i].mSlot,
+ releasedItems[i].mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+ Fence::NO_FENCE));
+ }
+ int32_t expectedReleaseCb = (enableReleasedCb ? releasedItems.size() : 0);
+ if (hasSurfaceListener) {
+ ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount());
+ }
+
+ // Acquire 1 buffer, leaving 1+extraDiscardedBuffers filled buffer in queue
+ BufferItem item;
+ ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&item, 0));
+
+ // Discard free buffers
+ ASSERT_EQ(NO_ERROR, consumer->discardFreeBuffers());
+
+ if (hasSurfaceListener) {
+ ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount());
+
+ // Check onBufferDiscarded is called with correct buffer
+ auto discardedBuffers = listener->getDiscardedBuffers();
+ ASSERT_EQ(discardedBuffers.size(), releasedItems.size());
+ for (int i = 0; i < releasedItems.size(); i++) {
+ ASSERT_EQ(discardedBuffers[i], releasedItems[i].mGraphicBuffer);
+ }
+
+ ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount());
+ }
+
+ // Disconnect the surface
+ ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU));
+ }
+
sp<Surface> mSurface;
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mSurfaceControl;
@@ -480,6 +591,21 @@
ASSERT_LE(removedBuffers.size(), 1u);
}
+TEST_F(SurfaceTest, SurfaceListenerTest) {
+ // Test discarding 1 free buffers with no listener
+ testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/0);
+ // Test discarding 2 free buffers with no listener
+ testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/1);
+ // Test discarding 1 free buffers with a listener, disabling onBufferReleased
+ testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/0);
+ // Test discarding 2 free buffers with a listener, disabling onBufferReleased
+ testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/1);
+ // Test discarding 1 free buffers with a listener, enabling onBufferReleased
+ testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/0);
+ // Test discarding 3 free buffers with a listener, enabling onBufferReleased
+ testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/2);
+}
+
TEST_F(SurfaceTest, TestGetLastDequeueStartTime) {
sp<ANativeWindow> anw(mSurface);
ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU));
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 1751443..4c59e6c 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -266,3 +266,11 @@
int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation) {
return native_window_set_auto_prerotation(window, autoPrerotation);
}
+
+/**************************************************************************************************
+ * apex-stable
+ **************************************************************************************************/
+
+int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) {
+ return query(window, NATIVE_WINDOW_LAST_DEQUEUE_DURATION);
+}
diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING
new file mode 100644
index 0000000..3d7f3c2
--- /dev/null
+++ b/libs/nativewindow/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libnativewindow_test"
+ }
+ ]
+}
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
new file mode 100644
index 0000000..0260cbc
--- /dev/null
+++ b/libs/nativewindow/include/apex/window.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <nativebase/nativebase.h>
+
+// apex is a superset of the NDK
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+/**
+ * Retrieves how long it took for the last time a buffer was dequeued.
+ *
+ * \return a negative value on error, otherwise returns the duration in
+ * microseconds.
+ */
+int ANativeWindow_getLastDequeueDuration(ANativeWindow* window);
+
+__END_DECLS
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 8cbf0a4..78354bb 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -41,7 +41,8 @@
#include <unistd.h>
#include <stdbool.h>
-// system/window.h is a superset of the vndk
+// system/window.h is a superset of the vndk and apex apis
+#include <apex/window.h>
#include <vndk/window.h>
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 119a07d..7fe4df0 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -22,6 +22,7 @@
ANativeWindow_getBuffersDataSpace; # introduced=28
ANativeWindow_getFormat;
ANativeWindow_getHeight;
+ ANativeWindow_getLastDequeueDuration; # apex # introduced=30
ANativeWindow_getWidth;
ANativeWindow_lock;
ANativeWindow_query; # vndk
diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp
new file mode 100644
index 0000000..5247e04
--- /dev/null
+++ b/libs/nativewindow/tests/ANativeWindowTest.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ANativeWindow_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/BufferQueue.h>
+#include <gui/Surface.h>
+#include <log/log.h>
+#include <sync/sync.h>
+// We need to use the private system apis since not everything is visible to
+// apexes yet.
+#include <system/window.h>
+
+using namespace android;
+
+class TestableSurface final : public Surface {
+public:
+ explicit TestableSurface(const sp<IGraphicBufferProducer>& bufferProducer)
+ : Surface(bufferProducer) {}
+
+ // Exposes the internal last dequeue duration that's stored on the Surface.
+ nsecs_t getLastDequeueDuration() const { return mLastDequeueDuration; }
+};
+
+class ANativeWindowTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN);
+ mWindow = new TestableSurface(mProducer);
+ const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU);
+ EXPECT_EQ(0, success);
+ }
+
+ void TearDown() override {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGV("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ const int success = native_window_api_disconnect(mWindow.get(), NATIVE_WINDOW_API_CPU);
+ EXPECT_EQ(0, success);
+ }
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<BufferItemConsumer> mItemConsumer;
+
+ sp<TestableSurface> mWindow;
+};
+
+TEST_F(ANativeWindowTest, getLastDequeueDuration_noDequeue_returnsZero) {
+ int result = ANativeWindow_getLastDequeueDuration(mWindow.get());
+ EXPECT_EQ(0, result);
+ EXPECT_EQ(0, mWindow->getLastDequeueDuration() / 1000);
+}
+
+TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) {
+ ANativeWindowBuffer* buffer;
+ int fd;
+ int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+ close(fd);
+ EXPECT_EQ(0, result);
+
+ result = ANativeWindow_getLastDequeueDuration(mWindow.get());
+ EXPECT_GT(result, 0);
+ EXPECT_EQ(result, mWindow->getLastDequeueDuration() / 1000);
+}
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index 20071be..cdb3d20 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -15,13 +15,22 @@
//
cc_test {
- name: "AHardwareBufferTest",
+ name: "libnativewindow_test",
+ test_suites: [
+ "device-tests",
+ ],
shared_libs: [
+ "libgui",
+ "liblog",
"libnativewindow",
+ "libsync",
+ "libutils",
"android.hardware.graphics.common@1.0",
],
srcs: [
"AHardwareBufferTest.cpp",
- "c_compatibility.c"],
+ "ANativeWindowTest.cpp",
+ "c_compatibility.c",
+ ],
cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/nativewindow/tests/c_compatibility.c b/libs/nativewindow/tests/c_compatibility.c
index befd88f..aa9b4f7 100644
--- a/libs/nativewindow/tests/c_compatibility.c
+++ b/libs/nativewindow/tests/c_compatibility.c
@@ -16,6 +16,7 @@
#include <android/hardware_buffer.h>
#include <android/native_window.h>
+#include <apex/window.h>
#include <vndk/hardware_buffer.h>
#include <vndk/window.h>
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index f67e258..62856df 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -178,6 +178,10 @@
return status;
}
+Status<uint8_t> DisplayClient::GetDisplayIdentificationPort() {
+ return InvokeRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>();
+}
+
Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface(
const SurfaceAttributes& attributes) {
int error;
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index f8f5b3d..81546ac 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -72,6 +72,7 @@
public:
pdx::Status<Metrics> GetDisplayMetrics();
pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type);
+ pdx::Status<uint8_t> GetDisplayIdentificationPort();
pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
DvrGlobalBufferKey key, size_t size, uint64_t usage);
pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index 861dc6c..9f4cc4a 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -211,6 +211,7 @@
kOpGetSurfaceInfo,
kOpCreateQueue,
kOpSetAttributes,
+ kOpGetDisplayIdentificationPort,
};
// Aliases.
@@ -221,6 +222,8 @@
PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void));
PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData,
std::string(ConfigFileType config_type));
+ PDX_REMOTE_METHOD(GetDisplayIdentificationPort,
+ kOpGetDisplayIdentificationPort, uint8_t(Void));
PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
uint64_t usage));
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 2829353..4441672 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -35,7 +35,7 @@
]
sharedLibraries = [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 8980a92..5a9360c 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -47,7 +47,8 @@
uint8_t port;
const auto error = hidl->getDisplayIdentificationData(
- primary_display_id, &port, &display_identification_data_);
+ primary_display_id, &display_identification_port_,
+ &display_identification_data_);
if (error != android::hardware::graphics::composer::V2_1::Error::NONE) {
if (error !=
android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) {
@@ -151,6 +152,11 @@
*this, &DisplayService::OnGetConfigurationData, message);
return {};
+ case DisplayProtocol::GetDisplayIdentificationPort::Opcode:
+ DispatchRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>(
+ *this, &DisplayService::OnGetDisplayIdentificationPort, message);
+ return {};
+
case DisplayProtocol::CreateSurface::Opcode:
DispatchRemoteMethod<DisplayProtocol::CreateSurface>(
*this, &DisplayService::OnCreateSurface, message);
@@ -238,6 +244,11 @@
return std::move(data);
}
+pdx::Status<uint8_t> DisplayService::OnGetDisplayIdentificationPort(
+ pdx::Message& /*message*/) {
+ return display_identification_port_;
+}
+
// Creates a new DisplaySurface and associates it with this channel. This may
// only be done once per channel.
Status<display::SurfaceInfo> DisplayService::OnCreateSurface(
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index d45a61f..06ba566 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -82,6 +82,7 @@
pdx::Status<display::Metrics> OnGetMetrics(pdx::Message& message);
pdx::Status<std::string> OnGetConfigurationData(
pdx::Message& message, display::ConfigFileType config_type);
+ pdx::Status<uint8_t> OnGetDisplayIdentificationPort(pdx::Message& message);
pdx::Status<display::SurfaceInfo> OnCreateSurface(
pdx::Message& message, const display::SurfaceAttributes& attributes);
pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
@@ -121,6 +122,7 @@
void operator=(const DisplayService&) = delete;
DisplayIdentificationData display_identification_data_;
+ uint8_t display_identification_port_;
};
} // namespace dvr
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index e996be6..d1b4a4e 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -1379,6 +1379,9 @@
if (!_s.get())
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ if (n_rects < 0 || (n_rects > 0 && rects == NULL))
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+
egl_surface_t* const s = get_surface(draw);
if (CC_UNLIKELY(dp->traceGpuCompletion)) {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 438f8f3..93c738d 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -19,7 +19,7 @@
"-DEGL_EGLEXT_PROTOTYPES",
],
shared_libs: [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
@@ -58,6 +58,14 @@
"libutils",
"libSurfaceFlingerProp",
],
+ // VrComposer is not used when building surfaceflinger for vendors
+ target: {
+ vendor: {
+ exclude_shared_libs: [
+ "android.frameworks.vr.composer@2.0",
+ ],
+ },
+ },
static_libs: [
"libcompositionengine",
"libperfetto_client_experimental",
@@ -139,6 +147,7 @@
"DisplayHardware/VirtualDisplaySurface.cpp",
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
+ "FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
"Layer.cpp",
"LayerProtoHelper.cpp",
@@ -181,6 +190,17 @@
// can be easily replaced.
"SurfaceFlingerFactory.cpp",
],
+ cflags: [
+ "-DUSE_VR_COMPOSER=1",
+ ],
+ // VrComposer is not used when building surfaceflinger for vendors
+ target: {
+ vendor: {
+ cflags: [
+ "-DUSE_VR_COMPOSER=0",
+ ],
+ },
+ },
logtags: ["EventLog/EventLogTags.logtags"],
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index a8bdb79..26abe1c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -51,6 +51,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
+#include "FrameTracer/FrameTracer.h"
#include "LayerRejecter.h"
#include "TimeStats/TimeStats.h"
@@ -71,7 +72,9 @@
BufferLayer::~BufferLayer() {
mFlinger->deleteTextureAsync(mTextureName);
- mFlinger->mTimeStats->onDestroy(getSequence());
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
void BufferLayer::useSurfaceDamage() {
@@ -158,7 +161,8 @@
finished = true;
return;
}
- under.orSelf(layer->visibleRegion);
+
+ under.orSelf(layer->getScreenBounds());
});
// if not everything below us is covered, we plug the holes!
Region holes(targetSettings.clip.subtract(under));
@@ -314,17 +318,17 @@
if (presentFence->isValid()) {
mFlinger->mTimeStats->setPresentFence(layerID, mCurrentFrameNumber, presentFence);
- mFlinger->mTimeStats->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber,
- presentFence, TimeStats::FrameEvent::PRESENT_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber,
+ presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
} else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
mFlinger->mTimeStats->setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber,
- actualPresentTime,
- TimeStats::FrameEvent::PRESENT_FENCE);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber,
+ actualPresentTime,
+ FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 6cad3c7..4da39e4 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -29,6 +29,7 @@
#include "LayerRejecter.h"
#include "SurfaceInterceptor.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -48,9 +49,9 @@
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
- mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
- std::make_shared<FenceTime>(releaseFence),
- TimeStats::FrameEvent::RELEASE_FENCE);
+ mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
+ std::make_shared<FenceTime>(releaseFence),
+ FrameTracer::FrameEvent::RELEASE_FENCE);
mPreviousReleasedFrameNumber = mPreviousFrameNumber;
}
}
@@ -337,6 +338,7 @@
mQueueItems.clear();
mQueuedFrames = 0;
mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
// Once we have hit this state, the shadow queue may no longer
@@ -366,12 +368,12 @@
uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId();
mFlinger->mTimeStats->setAcquireFence(layerID, currentFrameNumber,
mQueueItems[0].mFenceTime);
- mFlinger->mTimeStats->traceFence(layerID, bufferID, currentFrameNumber,
- mQueueItems[0].mFenceTime,
- TimeStats::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, bufferID, currentFrameNumber,
+ mQueueItems[0].mFenceTime,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
mFlinger->mTimeStats->setLatchTime(layerID, currentFrameNumber, latchTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime,
- TimeStats::FrameEvent::LATCH);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
mQueueItems.removeAt(0);
}
@@ -429,9 +431,9 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
const int32_t layerID = getSequence();
- mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str());
- mFlinger->mTimeStats->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
- systemTime(), TimeStats::FrameEvent::POST);
+ mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
+ systemTime(), FrameTracer::FrameEvent::POST);
ATRACE_CALL();
// Add this buffer from our internal queue tracker
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4a8261d..e7d1b63 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -32,6 +32,7 @@
#include "BufferStateLayer.h"
#include "ColorLayer.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -90,9 +91,9 @@
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
- mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
- std::make_shared<FenceTime>(releaseFence),
- TimeStats::FrameEvent::RELEASE_FENCE);
+ mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
+ std::make_shared<FenceTime>(releaseFence),
+ FrameTracer::FrameEvent::RELEASE_FENCE);
mPreviousReleasedFrameNumber = mPreviousFrameNumber;
}
}
@@ -236,9 +237,9 @@
const int32_t layerID = getSequence();
mFlinger->mTimeStats->setPostTime(layerID, mFrameNumber, getName().c_str(), postTime);
- mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str());
- mFlinger->mTimeStats->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime,
- TimeStats::FrameEvent::POST);
+ mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime,
+ FrameTracer::FrameEvent::POST);
mCurrentState.desiredPresentTime = desiredPresentTime;
if (mFlinger->mUseSmart90ForVideo) {
@@ -569,17 +570,18 @@
status_t err = bindTextureImage();
if (err != NO_ERROR) {
mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
return BAD_VALUE;
}
}
const uint64_t bufferID = getCurrentBufferId();
mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime());
- mFlinger->mTimeStats->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(),
- TimeStats::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(),
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime,
- TimeStats::FrameEvent::LATCH);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
mCurrentStateModified = false;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 580bde8..e49b65f 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -5,7 +5,7 @@
"-DLOG_TAG=\"CompositionEngine\"",
],
shared_libs: [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index 31d6365..a8e05cb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -58,6 +58,12 @@
virtual bool needsAnotherUpdate() const = 0;
virtual nsecs_t getLastFrameRefreshTimestamp() const = 0;
+ // Presents the indicated outputs
+ virtual void present(CompositionRefreshArgs&) = 0;
+
+ // Updates the cursor position for the indicated outputs.
+ virtual void updateCursorAsync(CompositionRefreshArgs&) = 0;
+
// TODO(b/121291683): These will become private/internal
virtual void preComposition(CompositionRefreshArgs&) = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index b329f76..6f689ad 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -21,6 +21,8 @@
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
+#include <compositionengine/OutputColorSetting.h>
+#include <math/mat4.h>
namespace android::compositionengine {
@@ -42,6 +44,25 @@
// If true, forces the entire display to be considered dirty and repainted
bool repaintEverything{false};
+ // Controls how the color mode is chosen for an output
+ OutputColorSetting outputColorSetting{OutputColorSetting::kEnhanced};
+
+ // If not Dataspace::UNKNOWN, overrides the dataspace on each output
+ ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN};
+
+ // Forces a color mode on the outputs being refreshed
+ ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE};
+
+ // If true, there was a geometry update this frame
+ bool updatingGeometryThisFrame{false};
+
+ // The color matrix to use for this
+ // frame. Only set if the color transform is changing this frame.
+ std::optional<mat4> colorTransformMatrix;
+
+ // If true, client composition is always used.
+ bool devOptForceClientComposition{false};
+
// If set, causes the dirty regions to flash with the delay
std::optional<std::chrono::microseconds> devOptFlashDirtyRegionsDelay;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 2a901ae..db4f969 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -43,6 +43,10 @@
// geometry state can be skipped.
virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
+ // Latches the minimal bit of state for the cursor for a fast asynchronous
+ // update.
+ virtual void latchCursorCompositionState(LayerFECompositionState&) const = 0;
+
struct ClientCompositionTargetSettings {
// The clip region, or visible region that is being rendered to
const Region& clip;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index d5763d5..b066cd1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -56,10 +56,6 @@
Region geomActiveTransparentRegion;
FloatRect geomLayerBounds;
- // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
- // value recomputed / set every frame.
- Region geomVisibleRegion;
-
/*
* Presentation
*/
@@ -122,6 +118,13 @@
// True if the layer has protected content
bool hasProtectedContent{false};
+
+ /*
+ * Cursor state
+ */
+
+ // The output-independent frame for the cursor
+ Rect cursorFrame;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index df7add2..a509ca8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -21,7 +21,6 @@
#include <string>
#include <unordered_map>
-#include <math/mat4.h>
#include <renderengine/LayerSettings.h>
#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
@@ -44,6 +43,7 @@
class OutputLayer;
struct CompositionRefreshArgs;
+struct LayerFECompositionState;
namespace impl {
struct OutputCompositionState;
@@ -56,6 +56,7 @@
public:
using OutputLayers = std::vector<std::unique_ptr<compositionengine::OutputLayer>>;
using ReleasedLayers = std::vector<wp<LayerFE>>;
+ using UniqueFELayerStateMap = std::unordered_map<LayerFE*, LayerFECompositionState*>;
struct FrameFences {
sp<Fence> presentFence{Fence::NO_FENCE};
@@ -63,6 +64,13 @@
std::unordered_map<HWC2::Layer*, sp<Fence>> layerFences;
};
+ struct ColorProfile {
+ ui::ColorMode mode{ui::ColorMode::NATIVE};
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+ ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
+ ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN};
+ };
+
virtual ~Output();
// Returns true if the output is valid. This is meant to be checked post-
@@ -83,12 +91,8 @@
// belongsInOutput for full details.
virtual void setLayerStackFilter(uint32_t layerStackId, bool isInternal) = 0;
- // Sets the color transform matrix to use
- virtual void setColorTransform(const mat4&) = 0;
-
// Sets the output color mode
- virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent,
- ui::Dataspace colorSpaceAgnosticDataspace) = 0;
+ virtual void setColorProfile(const ColorProfile&) = 0;
// Outputs a string with a state dump
virtual void dump(std::string&) const = 0;
@@ -153,27 +157,28 @@
// Takes (moves) the set of layers being released this frame.
virtual ReleasedLayers takeReleasedLayers() = 0;
- // Signals that a frame is beginning on the output
- virtual void beginFrame() = 0;
+ // Prepare the output, updating the OutputLayers used in the output
+ virtual void prepare(CompositionRefreshArgs&) = 0;
- // Prepares a frame for display
- virtual void prepareFrame() = 0;
+ // Presents the output, finalizing all composition details
+ virtual void present(const CompositionRefreshArgs&) = 0;
- // Performs any debug related screen flashing due to the update
- virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0;
-
- // Performs client composition as needed for layers on the output. The
- // output fence is set to a fence to signal when client composition is
- // finished.
- // Returns false if client composition cannot be performed.
- virtual bool composeSurfaces(const Region& debugFence, base::unique_fd* outReadyFence) = 0;
-
- // Posts the new frame, and sets release fences.
- virtual void postFramebuffer() = 0;
+ // Latches the front-end layer state for each output layer
+ virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0;
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+
+ virtual void updateAndWriteCompositionState(const CompositionRefreshArgs&) = 0;
+ virtual void setColorTransform(const CompositionRefreshArgs&) = 0;
+ virtual void updateColorProfile(const CompositionRefreshArgs&) = 0;
+ virtual void beginFrame() = 0;
+ virtual void prepareFrame() = 0;
+ virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0;
+ virtual void finishFrame(const CompositionRefreshArgs&) = 0;
+ virtual std::optional<base::unique_fd> composeSurfaces(const Region&) = 0;
+ virtual void postFramebuffer() = 0;
virtual void chooseCompositionStrategy() = 0;
virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h
new file mode 100644
index 0000000..6e798ce
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android::compositionengine {
+
+enum class OutputColorSetting : int32_t {
+ kManaged = 0,
+ kUnmanaged = 1,
+ kEnhanced = 2,
+};
+
+} // namespace android::compositionengine
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 5f62b32c..cedd728 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -78,12 +78,18 @@
// skipped.
virtual void writeStateToHWC(bool includeGeometry) = 0;
+ // Updates the cursor position with the HWC
+ virtual void writeCursorPositionToHWC() const = 0;
+
// Returns the HWC2::Layer associated with this layer, if it exists
virtual HWC2::Layer* getHwcLayer() const = 0;
// Returns true if the current layer state requires client composition
virtual bool requiresClientComposition() const = 0;
+ // Returns true if the current layer should be treated as a cursor layer
+ virtual bool isHardwareCursor() const = 0;
+
// Applies a HWC device requested composition type change
virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 96e609d..6340b14 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -39,8 +39,14 @@
bool needsAnotherUpdate() const override;
nsecs_t getLastFrameRefreshTimestamp() const override;
+ void present(CompositionRefreshArgs&) override;
+
+ void updateCursorAsync(CompositionRefreshArgs&) override;
+
void preComposition(CompositionRefreshArgs&) override;
+ void updateLayerStateFromFE(CompositionRefreshArgs& args);
+
// Testing
void setNeedsAnotherUpdateForTest(bool);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 36e4aac..bd1aa08 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -40,12 +40,13 @@
// compositionengine::Output overrides
void dump(std::string&) const override;
- void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
+ void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
+ void setColorProfile(const ColorProfile&) override;
void chooseCompositionStrategy() override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
void setExpensiveRenderingExpected(bool) override;
+ void finishFrame(const compositionengine::CompositionRefreshArgs&) override;
// compositionengine::Display overrides
const std::optional<DisplayId>& getId() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
index ab01c20..726c850 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
@@ -21,6 +21,7 @@
#include <compositionengine/LayerFECompositionState.h>
#include <renderengine/Mesh.h>
+#include <ui/Region.h>
namespace android {
@@ -28,7 +29,7 @@
struct LayerCompositionState {
/*
- * State intended to be set by LayerFE::getCompositionState
+ * State set by LayerFE::getCompositionState
*/
LayerFECompositionState frontEnd;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 36d6a69..d826161 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -44,8 +44,8 @@
void setBounds(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
- void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
+ void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
+ void setColorProfile(const ColorProfile&) override;
void dump(std::string&) const override;
@@ -75,10 +75,17 @@
void setReleasedLayers(ReleasedLayers&&) override;
ReleasedLayers takeReleasedLayers() override;
+ void prepare(compositionengine::CompositionRefreshArgs&) override;
+ void present(const compositionengine::CompositionRefreshArgs&) override;
+
+ void updateLayerStateFromFE(const CompositionRefreshArgs&) const override;
+ void updateAndWriteCompositionState(const compositionengine::CompositionRefreshArgs&) override;
+ void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
void beginFrame() override;
void prepareFrame() override;
void devOptRepaintFlash(const compositionengine::CompositionRefreshArgs&) override;
- bool composeSurfaces(const Region&, base::unique_fd*) override;
+ void finishFrame(const compositionengine::CompositionRefreshArgs&) override;
+ std::optional<base::unique_fd> composeSurfaces(const Region&) override;
void postFramebuffer() override;
// Testing
@@ -99,6 +106,9 @@
private:
void dirtyEntireOutput();
+ ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
+ compositionengine::Output::ColorProfile pickColorProfile(
+ const compositionengine::CompositionRefreshArgs&) const;
const CompositionEngine& mCompositionEngine;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 1078f11..17d3d3f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -86,11 +86,8 @@
// True if the last composition frame had visible layers
bool lastCompositionHadVisibleLayers{false};
- // The color transform to apply
- android_color_transform_t colorTransform{HAL_COLOR_TRANSFORM_IDENTITY};
-
- // The color transform matrix to apply, corresponding with colorTransform.
- mat4 colorTransformMat;
+ // The color transform matrix to apply
+ mat4 colorTransformMatrix;
// Current active color mode
ui::ColorMode colorMode{ui::ColorMode::NATIVE};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 4c3f935..fa4d8cd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -49,9 +49,11 @@
void updateCompositionState(bool) override;
void writeStateToHWC(bool) override;
+ void writeCursorPositionToHWC() const override;
HWC2::Layer* getHwcLayer() const override;
bool requiresClientComposition() const override;
+ bool isHardwareCursor() const override;
void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
void prepareForDeviceLayerRequests() override;
void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index de0f08a..1347449 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -40,9 +40,18 @@
namespace compositionengine::impl {
struct OutputLayerCompositionState {
- // The region of this layer which is visible on this output
+ // The portion of the layer that is not obscured by opaque layers on top
Region visibleRegion;
+ // The portion of the layer that is not obscured and is also opaque
+ Region visibleNonTransparentRegion;
+
+ // The portion of the layer that is obscured by opaque layers on top
+ Region coveredRegion;
+
+ // The visibleRegion transformed to output space
+ Region outputSpaceVisibleRegion;
+
// If true, client composition will be used on this output
bool forceClientComposition{false};
@@ -62,7 +71,7 @@
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
// The Z order index of this layer on this output
- uint32_t z;
+ uint32_t z{0};
/*
* HWC state
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 82ecec5..e3254ac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -44,6 +44,9 @@
MOCK_CONST_METHOD0(needsAnotherUpdate, bool());
MOCK_CONST_METHOD0(getLastFrameRefreshTimestamp, nsecs_t());
+ MOCK_METHOD1(present, void(CompositionRefreshArgs&));
+ MOCK_METHOD1(updateCursorAsync, void(CompositionRefreshArgs&));
+
MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 48c2dbf..e280295 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -33,6 +33,7 @@
MOCK_METHOD1(onPreComposition, bool(nsecs_t));
MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
+ MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&));
MOCK_METHOD1(prepareClientComposition,
std::optional<renderengine::LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index b9e1c9c..33925d5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -41,8 +41,8 @@
MOCK_METHOD1(setBounds, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
- MOCK_METHOD1(setColorTransform, void(const mat4&));
- MOCK_METHOD4(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace));
+ MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD1(setColorProfile, void(const ColorProfile&));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getName, const std::string&());
@@ -74,13 +74,23 @@
MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&));
MOCK_METHOD0(takeReleasedLayers, ReleasedLayers());
+ MOCK_METHOD1(prepare, void(compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD1(present, void(const compositionengine::CompositionRefreshArgs&));
+
+ MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&));
+ MOCK_METHOD1(updateAndWriteCompositionState, void(const CompositionRefreshArgs&));
+ MOCK_METHOD1(updateColorProfile, void(const compositionengine::CompositionRefreshArgs&));
+
MOCK_METHOD0(beginFrame, void());
+
MOCK_METHOD0(prepareFrame, void());
MOCK_METHOD0(chooseCompositionStrategy, void());
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD2(composeSurfaces, bool(const Region&, base::unique_fd*));
+ MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
+
+ MOCK_METHOD1(composeSurfaces, std::optional<base::unique_fd>(const Region&));
MOCK_CONST_METHOD0(getSkipColorTransform, bool());
MOCK_METHOD0(postFramebuffer, void());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index d8d637d..6b2224a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -40,9 +40,11 @@
MOCK_METHOD1(updateCompositionState, void(bool));
MOCK_METHOD1(writeStateToHWC, void(bool));
+ MOCK_CONST_METHOD0(writeCursorPositionToHWC, void());
MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*());
MOCK_CONST_METHOD0(requiresClientComposition, bool());
+ MOCK_CONST_METHOD0(isHardwareCursor, bool());
MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
MOCK_METHOD0(prepareForDeviceLayerRequests, void());
MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 9558266..590c596 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -16,6 +16,7 @@
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/LayerFE.h>
+#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/Layer.h>
@@ -70,6 +71,34 @@
return mRefreshStartTime;
}
+void CompositionEngine::present(CompositionRefreshArgs& args) {
+ for (const auto& output : args.outputs) {
+ output->prepare(args);
+ }
+
+ updateLayerStateFromFE(args);
+
+ for (const auto& output : args.outputs) {
+ output->present(args);
+ }
+}
+
+void CompositionEngine::updateCursorAsync(CompositionRefreshArgs& args) {
+ std::unordered_map<compositionengine::LayerFE*, compositionengine::LayerFECompositionState*>
+ uniqueVisibleLayers;
+
+ for (const auto& output : args.outputs) {
+ for (auto& layer : output->getOutputLayersOrderedByZ()) {
+ if (layer->isHardwareCursor()) {
+ // Latch the cursor composition state from each front-end layer.
+ layer->getLayerFE().latchCursorCompositionState(
+ layer->getLayer().editState().frontEnd);
+ layer->writeCursorPositionToHWC();
+ }
+ }
+ }
+}
+
void CompositionEngine::preComposition(CompositionRefreshArgs& args) {
ATRACE_CALL();
ALOGV(__FUNCTION__);
@@ -92,5 +121,12 @@
mNeedsAnotherUpdate = value;
}
+void CompositionEngine::updateLayerStateFromFE(CompositionRefreshArgs& args) {
+ // Update the composition state from each front-end layer
+ for (const auto& output : args.outputs) {
+ output->updateLayerStateFromFE(args);
+ }
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 6cd392e..000a294 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -16,6 +16,7 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/DisplaySurface.h>
#include <compositionengine/impl/Display.h>
@@ -68,24 +69,28 @@
mId.reset();
}
-void Display::setColorTransform(const mat4& transform) {
- Output::setColorTransform(transform);
+void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& args) {
+ Output::setColorTransform(args);
+
+ if (!mId || CC_LIKELY(!args.colorTransformMatrix)) {
+ return;
+ }
auto& hwc = getCompositionEngine().getHwComposer();
- status_t result = hwc.setColorTransform(*mId, transform);
+ status_t result = hwc.setColorTransform(*mId, *args.colorTransformMatrix);
ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d",
mId ? to_string(*mId).c_str() : "", result);
}
-void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent,
- ui::Dataspace colorSpaceAgnosticDataspace) {
- ui::Dataspace targetDataspace =
- getDisplayColorProfile()->getTargetDataspace(mode, dataspace,
- colorSpaceAgnosticDataspace);
+void Display::setColorProfile(const ColorProfile& colorProfile) {
+ const ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace,
+ colorProfile.colorSpaceAgnosticDataspace);
- if (mode == getState().colorMode && dataspace == getState().dataspace &&
- renderIntent == getState().renderIntent && targetDataspace == getState().targetDataspace) {
+ if (colorProfile.mode == getState().colorMode &&
+ colorProfile.dataspace == getState().dataspace &&
+ colorProfile.renderIntent == getState().renderIntent &&
+ targetDataspace == getState().targetDataspace) {
return;
}
@@ -94,10 +99,10 @@
return;
}
- Output::setColorMode(mode, dataspace, renderIntent, colorSpaceAgnosticDataspace);
+ Output::setColorProfile(colorProfile);
auto& hwc = getCompositionEngine().getHwComposer();
- hwc.setActiveColorMode(*mId, mode, renderIntent);
+ hwc.setActiveColorMode(*mId, colorProfile.mode, colorProfile.renderIntent);
}
void Display::dump(std::string& out) const {
@@ -259,4 +264,19 @@
}
}
+void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ // We only need to actually compose the display if:
+ // 1) It is being handled by hardware composer, which may need this to
+ // keep its virtual display state machine in sync, or
+ // 2) There is work to be done (the dirty region isn't empty)
+ if (!mId) {
+ if (getDirtyRegion(refreshArgs.repaintEverything).isEmpty()) {
+ ALOGV("Skipping display composition");
+ return;
+ }
+ }
+
+ impl::Output::finishFrame(refreshArgs);
+}
+
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 10534f4..9f4f259 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -99,43 +99,37 @@
dirtyEntireOutput();
}
-void Output::setColorTransform(const mat4& transform) {
- if (mState.colorTransformMat == transform) {
+void Output::setColorTransform(const compositionengine::CompositionRefreshArgs& args) {
+ if (!args.colorTransformMatrix || mState.colorTransformMatrix == *args.colorTransformMatrix) {
return;
}
- const bool isIdentity = (transform == mat4());
- const auto newColorTransform =
- isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
-
- mState.colorTransform = newColorTransform;
- mState.colorTransformMat = transform;
+ mState.colorTransformMatrix = *args.colorTransformMatrix;
dirtyEntireOutput();
}
-void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent,
- ui::Dataspace colorSpaceAgnosticDataspace) {
- ui::Dataspace targetDataspace =
- getDisplayColorProfile()->getTargetDataspace(mode, dataspace,
- colorSpaceAgnosticDataspace);
+void Output::setColorProfile(const ColorProfile& colorProfile) {
+ const ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace,
+ colorProfile.colorSpaceAgnosticDataspace);
- if (mState.colorMode == mode && mState.dataspace == dataspace &&
- mState.renderIntent == renderIntent && mState.targetDataspace == targetDataspace) {
+ if (mState.colorMode == colorProfile.mode && mState.dataspace == colorProfile.dataspace &&
+ mState.renderIntent == colorProfile.renderIntent &&
+ mState.targetDataspace == targetDataspace) {
return;
}
- mState.colorMode = mode;
- mState.dataspace = dataspace;
- mState.renderIntent = renderIntent;
+ mState.colorMode = colorProfile.mode;
+ mState.dataspace = colorProfile.dataspace;
+ mState.renderIntent = colorProfile.renderIntent;
mState.targetDataspace = targetDataspace;
- mRenderSurface->setBufferDataspace(dataspace);
+ mRenderSurface->setBufferDataspace(colorProfile.dataspace);
ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
- decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent);
+ decodeColorMode(colorProfile.mode).c_str(), colorProfile.mode,
+ decodeRenderIntent(colorProfile.renderIntent).c_str(), colorProfile.renderIntent);
dirtyEntireOutput();
}
@@ -261,6 +255,163 @@
return std::move(mReleasedLayers);
}
+void Output::prepare(compositionengine::CompositionRefreshArgs& refreshArgs) {
+ if (CC_LIKELY(!refreshArgs.updatingGeometryThisFrame)) {
+ return;
+ }
+
+ uint32_t zOrder = 0;
+ for (auto& layer : mOutputLayersOrderedByZ) {
+ // Assign a simple Z order sequence to each visible layer.
+ layer->editState().z = zOrder++;
+ }
+}
+
+void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ updateColorProfile(refreshArgs);
+ updateAndWriteCompositionState(refreshArgs);
+ setColorTransform(refreshArgs);
+ beginFrame();
+ prepareFrame();
+ devOptRepaintFlash(refreshArgs);
+ finishFrame(refreshArgs);
+ postFramebuffer();
+}
+
+void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const {
+ for (auto& layer : mOutputLayersOrderedByZ) {
+ layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
+ args.updatingGeometryThisFrame);
+ }
+}
+
+void Output::updateAndWriteCompositionState(
+ const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ for (auto& layer : mOutputLayersOrderedByZ) {
+ if (refreshArgs.devOptForceClientComposition) {
+ layer->editState().forceClientComposition = true;
+ }
+
+ layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame);
+
+ // Send the updated state to the HWC, if appropriate.
+ layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame);
+ }
+}
+
+void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ setColorProfile(pickColorProfile(refreshArgs));
+}
+
+// Returns a data space that fits all visible layers. The returned data space
+// can only be one of
+// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
+// - Dataspace::DISPLAY_P3
+// - Dataspace::DISPLAY_BT2020
+// The returned HDR data space is one of
+// - Dataspace::UNKNOWN
+// - Dataspace::BT2020_HLG
+// - Dataspace::BT2020_PQ
+ui::Dataspace Output::getBestDataspace(ui::Dataspace* outHdrDataSpace,
+ bool* outIsHdrClientComposition) const {
+ ui::Dataspace bestDataSpace = ui::Dataspace::V0_SRGB;
+ *outHdrDataSpace = ui::Dataspace::UNKNOWN;
+
+ for (const auto& layer : mOutputLayersOrderedByZ) {
+ switch (layer->getLayer().getState().frontEnd.dataspace) {
+ case ui::Dataspace::V0_SCRGB:
+ case ui::Dataspace::V0_SCRGB_LINEAR:
+ case ui::Dataspace::BT2020:
+ case ui::Dataspace::BT2020_ITU:
+ case ui::Dataspace::BT2020_LINEAR:
+ case ui::Dataspace::DISPLAY_BT2020:
+ bestDataSpace = ui::Dataspace::DISPLAY_BT2020;
+ break;
+ case ui::Dataspace::DISPLAY_P3:
+ bestDataSpace = ui::Dataspace::DISPLAY_P3;
+ break;
+ case ui::Dataspace::BT2020_PQ:
+ case ui::Dataspace::BT2020_ITU_PQ:
+ bestDataSpace = ui::Dataspace::DISPLAY_P3;
+ *outHdrDataSpace = ui::Dataspace::BT2020_PQ;
+ *outIsHdrClientComposition =
+ layer->getLayer().getState().frontEnd.forceClientComposition;
+ break;
+ case ui::Dataspace::BT2020_HLG:
+ case ui::Dataspace::BT2020_ITU_HLG:
+ bestDataSpace = ui::Dataspace::DISPLAY_P3;
+ // When there's mixed PQ content and HLG content, we set the HDR
+ // data space to be BT2020_PQ and convert HLG to PQ.
+ if (*outHdrDataSpace == ui::Dataspace::UNKNOWN) {
+ *outHdrDataSpace = ui::Dataspace::BT2020_HLG;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return bestDataSpace;
+}
+
+compositionengine::Output::ColorProfile Output::pickColorProfile(
+ const compositionengine::CompositionRefreshArgs& refreshArgs) const {
+ if (refreshArgs.outputColorSetting == OutputColorSetting::kUnmanaged) {
+ return ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
+ ui::RenderIntent::COLORIMETRIC,
+ refreshArgs.colorSpaceAgnosticDataspace};
+ }
+
+ ui::Dataspace hdrDataSpace;
+ bool isHdrClientComposition = false;
+ ui::Dataspace bestDataSpace = getBestDataspace(&hdrDataSpace, &isHdrClientComposition);
+
+ switch (refreshArgs.forceOutputColorMode) {
+ case ui::ColorMode::SRGB:
+ bestDataSpace = ui::Dataspace::V0_SRGB;
+ break;
+ case ui::ColorMode::DISPLAY_P3:
+ bestDataSpace = ui::Dataspace::DISPLAY_P3;
+ break;
+ default:
+ break;
+ }
+
+ // respect hdrDataSpace only when there is no legacy HDR support
+ const bool isHdr = hdrDataSpace != ui::Dataspace::UNKNOWN &&
+ !mDisplayColorProfile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition;
+ if (isHdr) {
+ bestDataSpace = hdrDataSpace;
+ }
+
+ ui::RenderIntent intent;
+ switch (refreshArgs.outputColorSetting) {
+ case OutputColorSetting::kManaged:
+ case OutputColorSetting::kUnmanaged:
+ intent = isHdr ? ui::RenderIntent::TONE_MAP_COLORIMETRIC
+ : ui::RenderIntent::COLORIMETRIC;
+ break;
+ case OutputColorSetting::kEnhanced:
+ intent = isHdr ? ui::RenderIntent::TONE_MAP_ENHANCE : ui::RenderIntent::ENHANCE;
+ break;
+ default: // vendor display color setting
+ intent = static_cast<ui::RenderIntent>(refreshArgs.outputColorSetting);
+ break;
+ }
+
+ ui::ColorMode outMode;
+ ui::Dataspace outDataSpace;
+ ui::RenderIntent outRenderIntent;
+ mDisplayColorProfile->getBestColorMode(bestDataSpace, intent, &outDataSpace, &outMode,
+ &outRenderIntent);
+
+ return ColorProfile{outMode, outDataSpace, outRenderIntent,
+ refreshArgs.colorSpaceAgnosticDataspace};
+}
+
void Output::beginFrame() {
const bool dirty = !getDirtyRegion(false).isEmpty();
const bool empty = mOutputLayersOrderedByZ.empty();
@@ -313,7 +464,7 @@
if (!dirtyRegion.isEmpty()) {
base::unique_fd readyFence;
// redraw the whole screen
- composeSurfaces(dirtyRegion, &readyFence);
+ static_cast<void>(composeSurfaces(dirtyRegion));
mRenderSurface->queueBuffer(std::move(readyFence));
}
@@ -326,14 +477,35 @@
prepareFrame();
}
-bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFence) {
+void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (!mState.isEnabled) {
+ return;
+ }
+
+ // Repaint the framebuffer (if needed), getting the optional fence for when
+ // the composition completes.
+ auto optReadyFence = composeSurfaces(Region::INVALID_REGION);
+ if (!optReadyFence) {
+ return;
+ }
+
+ // swap buffers (presentation)
+ mRenderSurface->queueBuffer(std::move(*optReadyFence));
+}
+
+std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion) {
ATRACE_CALL();
ALOGV(__FUNCTION__);
const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
mState.usesClientComposition};
+ base::unique_fd readyFence;
+
if (!hasClientComposition) {
- return true;
+ return readyFence;
}
ALOGV("hasClientComposition");
@@ -353,7 +525,7 @@
// Compute the global color transform matrix.
if (!mState.usesDeviceComposition && !getSkipColorTransform()) {
- clientCompositionDisplay.colorTransform = mState.colorTransformMat;
+ clientCompositionDisplay.colorTransform = mState.colorTransformMatrix;
}
// Note: Updated by generateClientCompositionRequests
@@ -389,7 +561,7 @@
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
mName.c_str());
- return false;
+ return std::nullopt;
}
// We boost GPU frequency here because there will be color spaces conversion
@@ -404,13 +576,13 @@
renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
- readyFence);
+ &readyFence);
if (expensiveRenderingExpected) {
setExpensiveRenderingExpected(false);
}
- return true;
+ return readyFence;
}
std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
@@ -429,7 +601,7 @@
const auto& layerFEState = layer->getLayer().getState().frontEnd;
auto& layerFE = layer->getLayerFE();
- const Region clip(viewportRegion.intersect(layerFEState.geomVisibleRegion));
+ const Region clip(viewportRegion.intersect(layerState.visibleRegion));
ALOGV("Layer: %s", layerFE.getDebugName());
if (clip.isEmpty()) {
ALOGV(" Skipping for empty clip");
@@ -507,6 +679,9 @@
return;
}
+ mState.dirtyRegion.clear();
+ mRenderSurface->flip();
+
auto frame = presentAndGetFrameFences();
mRenderSurface->onPresentDisplayCompleted();
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 3e47fe2..0fcc308 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -47,7 +47,7 @@
dumpVal(out, "colorMode", toString(colorMode), colorMode);
dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
- dumpVal(out, "colorTransform", colorTransform);
+ dumpVal(out, "colorTransformMatrix", colorTransformMatrix);
dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
out.append("\n");
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e721cf5..21f0ce8 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -315,11 +315,6 @@
? outputState.targetDataspace
: layerFEState.dataspace;
- // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
- // value recomputed / set every frame.
- mState.visibleRegion = outputState.transform.transform(
- layerFEState.geomVisibleRegion.intersect(outputState.viewport));
-
// These are evaluated every frame as they can potentially change at any
// time.
if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(mState.dataspace)) {
@@ -421,13 +416,13 @@
void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
const auto& outputDependentState = getState();
- // TODO(lpique): b/121291683 visibleRegion is output-dependent geometry
+ // TODO(lpique): b/121291683 outputSpaceVisibleRegion is output-dependent geometry
// state and should not change every frame.
- if (auto error = hwcLayer->setVisibleRegion(outputDependentState.visibleRegion);
+ if (auto error = hwcLayer->setVisibleRegion(outputDependentState.outputSpaceVisibleRegion);
error != HWC2::Error::None) {
ALOGE("[%s] Failed to set visible region: %s (%d)", mLayerFE->getDebugName(),
to_string(error).c_str(), static_cast<int32_t>(error));
- outputDependentState.visibleRegion.dump(LOG_TAG);
+ outputDependentState.outputSpaceVisibleRegion.dump(LOG_TAG);
}
if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace);
@@ -550,6 +545,27 @@
}
}
+void OutputLayer::writeCursorPositionToHWC() const {
+ // Skip doing this if there is no HWC interface
+ auto hwcLayer = getHwcLayer();
+ if (!hwcLayer) {
+ return;
+ }
+
+ const auto& layerFEState = mLayer->getState().frontEnd;
+ const auto& outputState = mOutput.getState();
+
+ Rect frame = layerFEState.cursorFrame;
+ frame.intersect(outputState.viewport, &frame);
+ Rect position = outputState.transform.transform(frame);
+
+ if (auto error = hwcLayer->setCursorPosition(position.left, position.top);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set cursor position to (%d, %d): %s (%d)", mLayerFE->getDebugName(),
+ position.left, position.top, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
HWC2::Layer* OutputLayer::getHwcLayer() const {
return mState.hwc ? mState.hwc->hwcLayer.get() : nullptr;
}
@@ -559,6 +575,11 @@
mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
}
+bool OutputLayer::isHardwareCursor() const {
+ return mState.hwc &&
+ mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CURSOR;
+}
+
void OutputLayer::detectDisallowedCompositionTypeChange(
Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const {
bool result = false;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index e320bee..ad668b6 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -42,6 +42,15 @@
dumpVal(out, "visibleRegion", visibleRegion);
out.append(" ");
+ dumpVal(out, "visibleNonTransparentRegion", visibleNonTransparentRegion);
+
+ out.append(" ");
+ dumpVal(out, "coveredRegion", coveredRegion);
+
+ out.append(" ");
+ dumpVal(out, "output visibleRegion", outputSpaceVisibleRegion);
+
+ out.append(" ");
dumpVal(out, "forceClientComposition", forceClientComposition);
dumpVal(out, "clearClientTarget", clearClientTarget);
dumpVal(out, "displayFrame", displayFrame);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 743da82..008e631 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -138,23 +138,26 @@
*/
TEST_F(DisplayTest, setColorTransformSetsTransform) {
+ // No change does nothing
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = std::nullopt;
+ mDisplay.setColorTransform(refreshArgs);
+
// Identity matrix sets an identity state value
- const mat4 identity;
+ const mat4 kIdentity;
- EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kIdentity)).Times(1);
- mDisplay.setColorTransform(identity);
-
- EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mDisplay.getState().colorTransform);
+ refreshArgs.colorTransformMatrix = kIdentity;
+ mDisplay.setColorTransform(refreshArgs);
// Non-identity matrix sets a non-identity state value
- const mat4 nonIdentity = mat4() * 2;
+ const mat4 kNonIdentity = mat4() * 2;
- EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, nonIdentity)).Times(1);
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kNonIdentity)).Times(1);
- mDisplay.setColorTransform(nonIdentity);
-
- EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
+ refreshArgs.colorTransformMatrix = kNonIdentity;
+ mDisplay.setColorTransform(refreshArgs);
}
/*
@@ -162,6 +165,8 @@
*/
TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
+ using ColorProfile = Output::ColorProfile;
+
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
@@ -177,8 +182,8 @@
ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
// If the set values are unchanged, nothing happens
- mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
- ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN);
+ mDisplay.setColorProfile(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
+ ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN});
EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
@@ -192,8 +197,9 @@
ui::RenderIntent::TONE_MAP_COLORIMETRIC))
.Times(1);
- mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
+ mDisplay.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC,
+ ui::Dataspace::UNKNOWN});
EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace);
@@ -202,6 +208,8 @@
}
TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) {
+ using ColorProfile = Output::ColorProfile;
+
impl::Display virtualDisplay{mCompositionEngine,
DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
@@ -214,8 +222,9 @@
ui::Dataspace::UNKNOWN))
.WillOnce(Return(ui::Dataspace::UNKNOWN));
- virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
+ virtualDisplay.setColorProfile(
+ ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN});
EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace);
@@ -537,5 +546,90 @@
mDisplay.setExpensiveRenderingExpected(false);
}
+/*
+ * Display::finishFrame()
+ */
+
+TEST_F(DisplayTest, finishFrameDoesNotSkipCompositionIfNotDirtyOnHwcDisplay) {
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect no calls to queueBuffer if composition was skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+
+ mDisplay.editState().isEnabled = true;
+ mDisplay.editState().usesClientComposition = false;
+ mDisplay.editState().viewport = Rect(0, 0, 1, 1);
+ mDisplay.editState().dirtyRegion = Region::INVALID_REGION;
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.repaintEverything = false;
+
+ mDisplay.finishFrame(refreshArgs);
+}
+
+TEST_F(DisplayTest, finishFrameSkipsCompositionIfNotDirty) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect no calls to queueBuffer if composition was skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0);
+
+ nonHwcDisplay->editState().isEnabled = true;
+ nonHwcDisplay->editState().usesClientComposition = false;
+ nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+ nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION;
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.repaintEverything = false;
+
+ nonHwcDisplay->finishFrame(refreshArgs);
+}
+
+TEST_F(DisplayTest, finishFramePerformsCompositionIfDirty) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect a single call to queueBuffer when composition is not skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+
+ nonHwcDisplay->editState().isEnabled = true;
+ nonHwcDisplay->editState().usesClientComposition = false;
+ nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+ nonHwcDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.repaintEverything = false;
+
+ nonHwcDisplay->finishFrame(refreshArgs);
+}
+
+TEST_F(DisplayTest, finishFramePerformsCompositionIfRepaintEverything) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect a single call to queueBuffer when composition is not skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+
+ nonHwcDisplay->editState().isEnabled = true;
+ nonHwcDisplay->editState().usesClientComposition = false;
+ nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+ nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION;
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.repaintEverything = true;
+
+ nonHwcDisplay->finishFrame(refreshArgs);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index c83cae6..2276dc3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -574,7 +574,7 @@
static const half4 kColor;
static const Rect kDisplayFrame;
- static const Region kVisibleRegion;
+ static const Region kOutputSpaceVisibleRegion;
static const mat4 kColorTransform;
static const Region kSurfaceDamage;
static const HdrMetadata kHdrMetadata;
@@ -590,7 +590,7 @@
outputLayerState.sourceCrop = kSourceCrop;
outputLayerState.z = kZOrder;
outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
- outputLayerState.visibleRegion = kVisibleRegion;
+ outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion;
outputLayerState.dataspace = kDataspace;
mLayerState.frontEnd.blendMode = kBlendMode;
@@ -629,7 +629,7 @@
}
void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) {
- EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kVisibleRegion)))
+ EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kOutputSpaceVisibleRegion)))
.WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setDataspace(kDataspace)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
@@ -673,7 +673,8 @@
const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f,
84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
-const Region OutputLayerWriteStateToHWCTest::kVisibleRegion{Rect{1005, 1006, 1007, 1008}};
+const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
+ Rect{1005, 1006, 1007, 1008}};
const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{
1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016,
1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024,
@@ -782,6 +783,61 @@
}
/*
+ * OutputLayer::writeCursorPositionToHWC()
+ */
+
+struct OutputLayerWriteCursorPositionToHWCTest : public OutputLayerTest {
+ static constexpr int kDefaultTransform = TR_IDENT;
+ static constexpr HWC2::Error kDefaultError = HWC2::Error::Unsupported;
+
+ static const Rect kDefaultDisplayViewport;
+ static const Rect kDefaultCursorFrame;
+
+ OutputLayerWriteCursorPositionToHWCTest() {
+ auto& outputLayerState = mOutputLayer.editState();
+ outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer);
+
+ mLayerState.frontEnd.cursorFrame = kDefaultCursorFrame;
+
+ mOutputState.viewport = kDefaultDisplayViewport;
+ mOutputState.transform = ui::Transform{kDefaultTransform};
+ }
+
+ std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
+};
+
+const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultDisplayViewport{0, 0, 1920, 1080};
+const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultCursorFrame{1, 2, 3, 4};
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCHandlesNoHwcState) {
+ mOutputLayer.editState().hwc.reset();
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCWritesStateToHWC) {
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(1, 2)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCIntersectedWithViewport) {
+ mLayerState.frontEnd.cursorFrame = Rect{3000, 3000, 3016, 3016};
+
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(1920, 1080)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCRotatedByTransform) {
+ mOutputState.transform = ui::Transform{TR_ROT_90};
+
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(-4, 1)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+/*
* OutputLayer::getHwcLayer()
*/
@@ -829,6 +885,30 @@
}
/*
+ * OutputLayer::isHardwareCursor()
+ */
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfNoHWC2State) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_FALSE(mOutputLayer.isHardwareCursor());
+}
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsTrueIfSetToCursorComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CURSOR;
+
+ EXPECT_TRUE(mOutputLayer.isHardwareCursor());
+}
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfSetToDeviceComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ EXPECT_FALSE(mOutputLayer.isHardwareCursor());
+}
+
+/*
* OutputLayer::applyDeviceCompositionTypeChange()
*/
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index f4d2cf1..b0e8e36 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -45,6 +45,10 @@
constexpr auto TR_IDENT = 0u;
constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90;
+const mat4 kIdentity;
+const mat4 kNonIdentityHalf = mat4() * 0.5;
+const mat4 kNonIdentityQuarter = mat4() * 0.25;
+
struct OutputTest : public testing::Test {
OutputTest() {
mOutput.setDisplayColorProfileForTest(
@@ -171,38 +175,84 @@
* Output::setColorTransform
*/
-TEST_F(OutputTest, setColorTransformSetsTransform) {
- // Identity matrix sets an identity state value
- const mat4 identity;
+TEST_F(OutputTest, setColorTransformWithNoChangeFlaggedSkipsUpdates) {
+ mOutput.editState().colorTransformMatrix = kIdentity;
- mOutput.setColorTransform(identity);
+ // If no colorTransformMatrix is set the update should be skipped.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = std::nullopt;
- EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
- EXPECT_EQ(identity, mOutput.getState().colorTransformMat);
+ mOutput.setColorTransform(refreshArgs);
- // Since identity is the default, the dirty region should be unchanged (empty)
+ // The internal state should be unchanged
+ EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix);
+
+ // No dirty region should be set
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+}
- // Non-identity matrix sets a non-identity state value
- const mat4 nonIdentityHalf = mat4() * 0.5;
+TEST_F(OutputTest, setColorTransformWithNoActualChangeSkipsUpdates) {
+ mOutput.editState().colorTransformMatrix = kIdentity;
- mOutput.setColorTransform(nonIdentityHalf);
+ // Attempting to set the same colorTransformMatrix that is already set should
+ // also skip the update.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = kIdentity;
- EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
- EXPECT_EQ(nonIdentityHalf, mOutput.getState().colorTransformMat);
+ mOutput.setColorTransform(refreshArgs);
- // Since this is a state change, the entire output should now be dirty.
+ // The internal state should be unchanged
+ EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix);
+
+ // No dirty region should be set
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+}
+
+TEST_F(OutputTest, setColorTransformPerformsUpdateToIdentity) {
+ mOutput.editState().colorTransformMatrix = kNonIdentityHalf;
+
+ // Setting a different colorTransformMatrix should perform the update.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = kIdentity;
+
+ mOutput.setColorTransform(refreshArgs);
+
+ // The internal state should have been updated
+ EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix);
+
+ // The dirtyRegion should be set to the full display size
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+}
- // Non-identity matrix sets a non-identity state value
- const mat4 nonIdentityQuarter = mat4() * 0.25;
+TEST_F(OutputTest, setColorTransformPerformsUpdateForIdentityToHalf) {
+ mOutput.editState().colorTransformMatrix = kIdentity;
- mOutput.setColorTransform(nonIdentityQuarter);
+ // Setting a different colorTransformMatrix should perform the update.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = kNonIdentityHalf;
- EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
- EXPECT_EQ(nonIdentityQuarter, mOutput.getState().colorTransformMat);
+ mOutput.setColorTransform(refreshArgs);
- // Since this is a state change, the entire output should now be dirty.
+ // The internal state should have been updated
+ EXPECT_EQ(kNonIdentityHalf, mOutput.getState().colorTransformMatrix);
+
+ // The dirtyRegion should be set to the full display size
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+}
+
+TEST_F(OutputTest, setColorTransformPerformsUpdateForHalfToQuarter) {
+ mOutput.editState().colorTransformMatrix = kNonIdentityHalf;
+
+ // Setting a different colorTransformMatrix should perform the update.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = kNonIdentityQuarter;
+
+ mOutput.setColorTransform(refreshArgs);
+
+ // The internal state should have been updated
+ EXPECT_EQ(kNonIdentityQuarter, mOutput.getState().colorTransformMatrix);
+
+ // The dirtyRegion should be set to the full display size
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
@@ -211,14 +261,17 @@
*/
TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
+ using ColorProfile = Output::ColorProfile;
+
EXPECT_CALL(*mDisplayColorProfile,
getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
ui::Dataspace::UNKNOWN))
.WillOnce(Return(ui::Dataspace::UNKNOWN));
EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
- mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
+ mOutput.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC,
+ ui::Dataspace::UNKNOWN});
EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace);
@@ -229,6 +282,8 @@
}
TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) {
+ using ColorProfile = Output::ColorProfile;
+
EXPECT_CALL(*mDisplayColorProfile,
getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
ui::Dataspace::UNKNOWN))
@@ -239,8 +294,9 @@
mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
mOutput.editState().targetDataspace = ui::Dataspace::UNKNOWN;
- mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
+ mOutput.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC,
+ ui::Dataspace::UNKNOWN});
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
}
@@ -496,7 +552,7 @@
mOutput.editState().transform = ui::Transform{kDefaultOutputOrientation};
mOutput.editState().orientation = kDefaultOutputOrientation;
mOutput.editState().dataspace = kDefaultOutputDataspace;
- mOutput.editState().colorTransformMat = kDefaultColorTransformMat;
+ mOutput.editState().colorTransformMatrix = kDefaultColorTransformMat;
mOutput.editState().isSecure = true;
mOutput.editState().needsFiltering = false;
mOutput.editState().usesClientComposition = true;
@@ -527,8 +583,8 @@
mOutput.editState().usesClientComposition = false;
Region debugRegion;
- base::unique_fd readyFence;
- EXPECT_EQ(true, mOutput.composeSurfaces(debugRegion, &readyFence));
+ std::optional<base::unique_fd> readyFence = mOutput.composeSurfaces(debugRegion);
+ EXPECT_TRUE(readyFence);
}
TEST_F(OutputComposeSurfacesTest, worksIfNoClientLayersQueued) {
@@ -556,8 +612,8 @@
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(1);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)).Times(1);
- base::unique_fd readyFence;
- EXPECT_EQ(true, mOutput.composeSurfaces(kDebugRegion, &readyFence));
+ std::optional<base::unique_fd> readyFence = mOutput.composeSurfaces(kDebugRegion);
+ EXPECT_TRUE(readyFence);
}
/*
@@ -605,9 +661,9 @@
impl::OutputLayerCompositionState leftOutputLayerState;
leftOutputLayerState.clearClientTarget = false;
+ leftOutputLayerState.visibleRegion = Region{Rect{0, 0, 1000, 1000}};
impl::LayerCompositionState leftLayerState;
- leftLayerState.frontEnd.geomVisibleRegion = Region{Rect{0, 0, 1000, 1000}};
leftLayerState.frontEnd.isOpaque = true;
const half3 leftLayerColor{1.f, 0.f, 0.f};
@@ -616,9 +672,9 @@
impl::OutputLayerCompositionState rightOutputLayerState;
rightOutputLayerState.clearClientTarget = false;
+ rightOutputLayerState.visibleRegion = Region{Rect{1000, 0, 2000, 1000}};
impl::LayerCompositionState rightLayerState;
- rightLayerState.frontEnd.geomVisibleRegion = Region{Rect{1000, 0, 2000, 1000}};
rightLayerState.frontEnd.isOpaque = true;
const half3 rightLayerColor{0.f, 1.f, 0.f};
@@ -679,9 +735,9 @@
impl::OutputLayerCompositionState outputLayerState;
outputLayerState.clearClientTarget = false;
+ outputLayerState.visibleRegion = Region{Rect{3000, 0, 4000, 1000}};
impl::LayerCompositionState layerState;
- layerState.frontEnd.geomVisibleRegion = Region{Rect{3000, 0, 4000, 1000}};
layerState.frontEnd.isOpaque = true;
EXPECT_CALL(*outputLayer, getState()).WillRepeatedly(ReturnRef(outputLayerState));
@@ -734,16 +790,16 @@
impl::OutputLayerCompositionState leftOutputLayerState;
leftOutputLayerState.clearClientTarget = true;
+ leftOutputLayerState.visibleRegion = Region{Rect{0, 0, 1000, 1000}};
impl::LayerCompositionState leftLayerState;
- leftLayerState.frontEnd.geomVisibleRegion = Region{Rect{0, 0, 1000, 1000}};
leftLayerState.frontEnd.isOpaque = true;
impl::OutputLayerCompositionState rightOutputLayerState;
rightOutputLayerState.clearClientTarget = true;
+ rightOutputLayerState.visibleRegion = Region{Rect{1000, 0, 2000, 1000}};
impl::LayerCompositionState rightLayerState;
- rightLayerState.frontEnd.geomVisibleRegion = Region{Rect{1000, 0, 2000, 1000}};
rightLayerState.frontEnd.isOpaque = true;
const half3 rightLayerColor{0.f, 1.f, 0.f};
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b6d79d4..2ada86b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -117,16 +117,6 @@
}
// ----------------------------------------------------------------------------
-
-void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers) {
- mVisibleLayersSortedByZ = layers;
-}
-
-const Vector< sp<Layer> >& DisplayDevice::getVisibleLayersSortedByZ() const {
- return mVisibleLayersSortedByZ;
-}
-
-// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
getCompositionDisplay()->setCompositionEnabled(mPowerMode != HWC_POWER_MODE_OFF);
@@ -291,7 +281,6 @@
result.append(" ");
StringAppendF(&result, "powerMode=%d, ", mPowerMode);
StringAppendF(&result, "activeConfig=%d, ", mActiveConfig);
- StringAppendF(&result, "numLayers=%zu\n", mVisibleLayersSortedByZ.size());
getCompositionDisplay()->dump(result);
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 4321e3d..5277320 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -87,9 +87,6 @@
int getHeight() const;
int getInstallOrientation() const { return mDisplayInstallOrientation; }
- void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
- const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
-
void setLayerStack(uint32_t stack);
void setDisplaySize(const int newWidth, const int newHeight);
void setProjection(int orientation, const Rect& viewport, const Rect& frame);
@@ -179,9 +176,6 @@
* don't need synchronization.
*/
- // list of visible layers on that display
- Vector< sp<Layer> > mVisibleLayersSortedByZ;
-
/*
* Transaction state
*/
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 7f47a2e..e53d099 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -110,6 +110,7 @@
namespace impl {
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Composer::CommandWriter::CommandWriter(uint32_t initialMaxSize)
: CommandWriterBase(initialMaxSize) {}
@@ -160,6 +161,7 @@
writeSigned(static_cast<int32_t>(metadata.format));
write64(metadata.usage);
}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Composer::Composer(const std::string& serviceName)
: mWriter(kWriterInitialSize),
@@ -198,12 +200,14 @@
LOG_ALWAYS_FATAL("failed to create composer client");
}
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
if (mIsUsingVrComposer) {
sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
if (vrClient == nullptr) {
LOG_ALWAYS_FATAL("failed to create vr composer client");
}
}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
}
Composer::~Composer() = default;
@@ -565,17 +569,20 @@
const std::vector<IComposerClient::Rect>& damage)
{
mWriter.selectDisplay(display);
+
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
if (mIsUsingVrComposer && target.get()) {
IVrComposerClient::BufferMetadata metadata = {
- .width = target->getWidth(),
- .height = target->getHeight(),
- .stride = target->getStride(),
- .layerCount = target->getLayerCount(),
- .format = static_cast<types::V1_0::PixelFormat>(target->getPixelFormat()),
- .usage = target->getUsage(),
+ .width = target->getWidth(),
+ .height = target->getHeight(),
+ .stride = target->getStride(),
+ .layerCount = target->getLayerCount(),
+ .format = static_cast<types::V1_2::PixelFormat>(target->getPixelFormat()),
+ .usage = target->getUsage(),
};
mWriter.setClientTargetMetadata(metadata);
}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
const native_handle_t* handle = nullptr;
if (target.get()) {
@@ -695,17 +702,20 @@
{
mWriter.selectDisplay(display);
mWriter.selectLayer(layer);
+
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
if (mIsUsingVrComposer && buffer.get()) {
IVrComposerClient::BufferMetadata metadata = {
- .width = buffer->getWidth(),
- .height = buffer->getHeight(),
- .stride = buffer->getStride(),
- .layerCount = buffer->getLayerCount(),
- .format = static_cast<types::V1_0::PixelFormat>(buffer->getPixelFormat()),
- .usage = buffer->getUsage(),
+ .width = buffer->getWidth(),
+ .height = buffer->getHeight(),
+ .stride = buffer->getStride(),
+ .layerCount = buffer->getLayerCount(),
+ .format = static_cast<types::V1_2::PixelFormat>(buffer->getPixelFormat()),
+ .usage = buffer->getUsage(),
};
mWriter.setLayerBufferMetadata(metadata);
}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
const native_handle_t* handle = nullptr;
if (buffer.get()) {
@@ -823,6 +833,7 @@
return Error::NONE;
}
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type,
uint32_t appId)
{
@@ -833,6 +844,15 @@
}
return Error::NONE;
}
+#else
+Error Composer::setLayerInfo(Display display, Layer layer, uint32_t, uint32_t) {
+ if (mIsUsingVrComposer) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ }
+ return Error::NONE;
+}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Error Composer::execute()
{
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index c4e952b..9f6cac2 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -23,7 +23,9 @@
#include <utility>
#include <vector>
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
+#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/composer/2.3/IComposer.h>
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
@@ -38,7 +40,9 @@
namespace Hwc2 {
-using frameworks::vr::composer::V1_0::IVrComposerClient;
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
+using frameworks::vr::composer::V2_0::IVrComposerClient;
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
namespace types = hardware::graphics::common;
@@ -418,6 +422,7 @@
Error setDisplayBrightness(Display display, float brightness) override;
private:
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
class CommandWriter : public CommandWriterBase {
public:
explicit CommandWriter(uint32_t initialMaxSize);
@@ -433,6 +438,13 @@
void writeBufferMetadata(
const IVrComposerClient::BufferMetadata& metadata);
};
+#else
+ class CommandWriter : public CommandWriterBase {
+ public:
+ explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {}
+ ~CommandWriter() override {}
+ };
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
// Many public functions above simply write a command into the command
// queue to batch the calls. validateDisplay and presentDisplay will call
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
new file mode 100644
index 0000000..006dbfe
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "FrameTracer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "FrameTracer.h"
+
+#include <android-base/stringprintf.h>
+
+#include <algorithm>
+#include <mutex>
+
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::FrameTracer::FrameTracerDataSource);
+
+namespace android {
+
+void FrameTracer::initialize() {
+ std::call_once(mInitializationFlag, [this]() {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kSystemBackend;
+ perfetto::Tracing::Initialize(args);
+ registerDataSource();
+ });
+}
+
+void FrameTracer::registerDataSource() {
+ perfetto::DataSourceDescriptor dsd;
+ dsd.set_name(kFrameTracerDataSource);
+ FrameTracerDataSource::Register(dsd);
+}
+
+void FrameTracer::traceNewLayer(int32_t layerID, const std::string& layerName) {
+ FrameTracerDataSource::Trace([this, layerID, &layerName](FrameTracerDataSource::TraceContext) {
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ mTraceTracker[layerID].layerName = layerName;
+ }
+ });
+}
+
+void FrameTracer::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ nsecs_t timestamp, FrameEvent::BufferEventType type,
+ nsecs_t duration) {
+ FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type,
+ duration](FrameTracerDataSource::TraceContext ctx) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ return;
+ }
+
+ // Handle any pending fences for this buffer.
+ tracePendingFencesLocked(ctx, layerID, bufferID);
+
+ // Complete current trace.
+ traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
+ });
+}
+
+void FrameTracer::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& fence,
+ FrameEvent::BufferEventType type, nsecs_t startTime) {
+ FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type,
+ startTime](FrameTracerDataSource::TraceContext ctx) {
+ const nsecs_t signalTime = fence->getSignalTime();
+ if (signalTime != Fence::SIGNAL_TIME_INVALID) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ return;
+ }
+
+ // Handle any pending fences for this buffer.
+ tracePendingFencesLocked(ctx, layerID, bufferID);
+
+ if (signalTime != Fence::SIGNAL_TIME_PENDING) {
+ traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime);
+ } else {
+ mTraceTracker[layerID].pendingFences[bufferID].push_back(
+ {.frameNumber = frameNumber,
+ .type = type,
+ .fence = fence,
+ .startTime = startTime});
+ }
+ }
+ });
+}
+
+void FrameTracer::tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx,
+ int32_t layerID, uint64_t bufferID) {
+ if (mTraceTracker[layerID].pendingFences.count(bufferID)) {
+ auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID];
+ for (size_t i = 0; i < pendingFences.size(); ++i) {
+ auto& pendingFence = pendingFences[i];
+
+ nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
+ if (pendingFence.fence && pendingFence.fence->isValid()) {
+ signalTime = pendingFence.fence->getSignalTime();
+ if (signalTime == Fence::SIGNAL_TIME_PENDING) {
+ continue;
+ }
+ }
+
+ if (signalTime != Fence::SIGNAL_TIME_INVALID &&
+ systemTime() - signalTime < kFenceSignallingDeadline) {
+ traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type,
+ pendingFence.startTime, signalTime);
+ }
+
+ pendingFences.erase(pendingFences.begin() + i);
+ --i;
+ }
+ }
+}
+
+void FrameTracer::traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
+ FrameEvent::BufferEventType type, nsecs_t duration) {
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp(timestamp);
+ auto* event = packet->set_graphics_frame_event()->set_buffer_event();
+ event->set_buffer_id(static_cast<uint32_t>(bufferID));
+ event->set_frame_number(frameNumber);
+ event->set_type(type);
+
+ if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
+ !mTraceTracker[layerID].layerName.empty()) {
+ const std::string& layerName = mTraceTracker[layerID].layerName;
+ event->set_layer_name(layerName.c_str(), layerName.size());
+ }
+
+ if (duration > 0) {
+ event->set_duration_ns(duration);
+ }
+}
+
+void FrameTracer::traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber,
+ FrameEvent::BufferEventType type, nsecs_t startTime,
+ nsecs_t endTime) {
+ nsecs_t timestamp = endTime;
+ nsecs_t duration = 0;
+ if (startTime > 0 && startTime < endTime) {
+ timestamp = startTime;
+ duration = endTime - startTime;
+ }
+ traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
+}
+
+void FrameTracer::onDestroy(int32_t layerID) {
+ std::lock_guard<std::mutex> traceLock(mTraceMutex);
+ mTraceTracker.erase(layerID);
+}
+
+std::string FrameTracer::miniDump() {
+ std::string result = "FrameTracer miniDump:\n";
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n",
+ mTraceTracker.size());
+ return result;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.h b/services/surfaceflinger/FrameTracer/FrameTracer.h
new file mode 100644
index 0000000..d4dfab9
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <perfetto/trace/android/graphics_frame_event.pbzero.h>
+#include <perfetto/tracing.h>
+#include <ui/FenceTime.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace android {
+
+class FrameTracer {
+public:
+ class FrameTracerDataSource : public perfetto::DataSource<FrameTracerDataSource> {
+ virtual void OnSetup(const SetupArgs&) override{};
+ virtual void OnStart(const StartArgs&) override{};
+ virtual void OnStop(const StopArgs&) override{};
+ };
+
+ using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
+
+ ~FrameTracer() = default;
+
+ // Sets up the perfetto tracing backend and data source.
+ void initialize();
+ // Registers the data source with the perfetto backend. Called as part of initialize()
+ // and should not be called manually outside of tests. Public to allow for substituting a
+ // perfetto::kInProcessBackend in tests.
+ void registerDataSource();
+ // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or
+ // traceFence() for each layer.
+ void traceNewLayer(int32_t layerID, const std::string& layerName);
+ // Creates a trace point at the timestamp provided.
+ void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
+ FrameEvent::BufferEventType type, nsecs_t duration = 0);
+ // Creates a trace point after the provided fence has been signalled. If a startTime is provided
+ // the trace will have be timestamped from startTime until fence signalling time. If no
+ // startTime is provided, a durationless trace point will be created timestamped at fence
+ // signalling time. If the fence hasn't signalled yet, the trace point will be created the next
+ // time after signalling a trace call for this buffer occurs.
+ void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& fence, FrameEvent::BufferEventType type,
+ nsecs_t startTime = 0);
+
+ // Takes care of cleanup when a layer is destroyed.
+ void onDestroy(int32_t layerID);
+
+ std::string miniDump();
+
+ static constexpr char kFrameTracerDataSource[] = "android.surfaceflinger.frame";
+
+ // The maximum amount of time a fence has to signal before it is discarded.
+ // Used to avoid fences from previous traces generating new trace points in later ones.
+ // Public for testing.
+ static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds
+
+private:
+ struct PendingFence {
+ uint64_t frameNumber;
+ FrameEvent::BufferEventType type;
+ std::shared_ptr<FenceTime> fence;
+ nsecs_t startTime;
+ };
+
+ struct TraceRecord {
+ std::string layerName;
+ using BufferID = uint64_t;
+ std::unordered_map<BufferID, std::vector<PendingFence>> pendingFences;
+ };
+
+ // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates
+ // trace points for them.
+ void tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID);
+ // Creates a trace point by translating a start time and an end time to a timestamp and
+ // duration. If startTime is later than end time it sets end time as the timestamp and the
+ // duration to 0. Used by traceFence().
+ void traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber, FrameEvent::BufferEventType type,
+ nsecs_t startTime, nsecs_t endTime);
+ void traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
+ uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type,
+ nsecs_t duration = 0);
+
+ std::mutex mTraceMutex;
+ std::unordered_map<int32_t, TraceRecord> mTraceTracker;
+ std::once_flag mInitializationFlag;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5121835..5e5302d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -22,6 +22,7 @@
#include "Layer.h"
#include <android-base/stringprintf.h>
+#include <binder/IPCThreadState.h>
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFECompositionState.h>
@@ -57,6 +58,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
+#include "FrameTracer/FrameTracer.h"
#include "LayerProtoHelper.h"
#include "LayerRejecter.h"
#include "MonitoredProducer.h"
@@ -121,7 +123,8 @@
mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType);
-
+ mCallingPid = args.callingPid;
+ mCallingUid = args.callingUid;
mFlinger->onLayerCreated();
}
@@ -135,6 +138,21 @@
mFlinger->onLayerDestroyed(this);
}
+LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+ LayerMetadata metadata)
+ : flinger(flinger),
+ client(client),
+ name(name),
+ w(w),
+ h(h),
+ flags(flags),
+ metadata(std::move(metadata)) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ callingPid = ipc->getCallingPid();
+ callingUid = ipc->getCallingUid();
+}
+
// ---------------------------------------------------------------------------
// callbacks
// ---------------------------------------------------------------------------
@@ -443,10 +461,6 @@
const auto& drawingState{getDrawingState()};
compositionState.forceClientComposition = false;
- // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
- // value recomputed / set every frame.
- compositionState.geomVisibleRegion = visibleRegion;
-
compositionState.isColorspaceAgnostic = isColorSpaceAgnostic();
compositionState.dataspace = mCurrentDataSpace;
compositionState.colorTransform = getColorTransform();
@@ -464,6 +478,21 @@
}
}
+void Layer::latchCursorCompositionState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ // This gives us only the "orientation" component of the transform
+ const State& drawingState{getDrawingState()};
+
+ // Apply the layer's transform, followed by the display's global transform
+ // Here we're guaranteed that the layer's transform preserves rects
+ Rect win = getCroppedBufferSize(drawingState);
+ // Subtract the transparent region and snap to the bounds
+ Rect bounds = reduce(win, getActiveTransparentRegion(drawingState));
+ Rect frame(getTransform().transform(bounds));
+
+ compositionState.cursorFrame = frame;
+}
+
bool Layer::onPreComposition(nsecs_t) {
return false;
}
@@ -481,38 +510,6 @@
return mName.string();
}
-void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
-
- if (!outputLayer->getState().hwc ||
- (*outputLayer->getState().hwc).hwcCompositionType !=
- Hwc2::IComposerClient::Composition::CURSOR) {
- return;
- }
-
- // This gives us only the "orientation" component of the transform
- const State& s(getDrawingState());
-
- // Apply the layer's transform, followed by the display's global transform
- // Here we're guaranteed that the layer's transform preserves rects
- Rect win = getCroppedBufferSize(s);
- // Subtract the transparent region and snap to the bounds
- Rect bounds = reduce(win, getActiveTransparentRegion(s));
- Rect frame(getTransform().transform(bounds));
- frame.intersect(display->getViewport(), &frame);
- auto& displayTransform = display->getTransform();
- auto position = displayTransform.transform(frame);
-
- auto error =
- (*outputLayer->getState().hwc).hwcLayer->setCursorPosition(position.left, position.top);
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set cursor position "
- "to (%d, %d): %s (%d)",
- mName.string(), position.left, position.top, to_string(error).c_str(),
- static_cast<int32_t>(error));
-}
-
// ---------------------------------------------------------------------------
// drawing...
// ---------------------------------------------------------------------------
@@ -584,27 +581,6 @@
return (s.flags & layer_state_t::eLayerSecure);
}
-void Layer::setVisibleRegion(const Region& visibleRegion) {
- // always called from main thread
- this->visibleRegion = visibleRegion;
-}
-
-void Layer::setCoveredRegion(const Region& coveredRegion) {
- // always called from main thread
- this->coveredRegion = coveredRegion;
-}
-
-void Layer::setVisibleNonTransparentRegion(const Region& setVisibleNonTransparentRegion) {
- // always called from main thread
- this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
-}
-
-void Layer::clearVisibilityRegions() {
- visibleRegion.clear();
- visibleNonTransparentRegion.clear();
- coveredRegion.clear();
-}
-
// ----------------------------------------------------------------------------
// transaction
// ----------------------------------------------------------------------------
@@ -1219,7 +1195,8 @@
info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
info.mType = getType();
info.mTransparentRegion = ds.activeTransparentRegion_legacy;
- info.mVisibleRegion = visibleRegion;
+
+ info.mVisibleRegion = debugGetVisibleRegionOnDefaultDisplay();
info.mSurfaceDamageRegion = surfaceDamageRegion;
info.mLayerStack = getLayerStack();
info.mX = ds.active_legacy.transform.tx();
@@ -1340,10 +1317,17 @@
mFrameEventHistory.dump(result);
}
+void Layer::dumpCallingUidPid(std::string& result) const {
+ StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().string(), getType(),
+ mCallingPid, mCallingUid);
+}
+
void Layer::onDisconnect() {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.onDisconnect();
- mFlinger->mTimeStats->onDestroy(getSequence());
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
@@ -1843,7 +1827,7 @@
LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
[&]() { return layerInfo->mutable_position(); });
LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
- LayerProtoHelper::writeToProto(visibleRegion,
+ LayerProtoHelper::writeToProto(debugGetVisibleRegionOnDefaultDisplay(),
[&]() { return layerInfo->mutable_visible_region(); });
LayerProtoHelper::writeToProto(surfaceDamageRegion,
[&]() { return layerInfo->mutable_damage_region(); });
@@ -1946,7 +1930,7 @@
InputWindowInfo info = mDrawingState.inputInfo;
if (info.displayId == ADISPLAY_ID_NONE) {
- info.displayId = mDrawingState.layerStack;
+ info.displayId = getLayerStack();
}
ui::Transform t = getTransform();
@@ -2020,6 +2004,20 @@
return display->getCompositionDisplay()->getOutputLayerForLayer(getCompositionLayer().get());
}
+Region Layer::debugGetVisibleRegionOnDefaultDisplay() const {
+ sp<DisplayDevice> displayDevice = mFlinger->getDefaultDisplayDeviceLocked();
+ if (displayDevice == nullptr) {
+ return {};
+ }
+
+ auto outputLayer = findOutputLayerForDisplay(displayDevice);
+ if (outputLayer == nullptr) {
+ return {};
+ }
+
+ return outputLayer->getState().visibleRegion;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index aa3970e..1486efe 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -80,9 +80,7 @@
struct LayerCreationArgs {
LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
- uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata)
- : flinger(flinger), client(client), name(name), w(w), h(h), flags(flags),
- metadata(std::move(metadata)) {}
+ uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata);
SurfaceFlinger* flinger;
const sp<Client>& client;
@@ -91,17 +89,15 @@
uint32_t h;
uint32_t flags;
LayerMetadata metadata;
+ pid_t callingPid;
+ uid_t callingUid;
};
-class Layer : public virtual compositionengine::LayerFE {
+class Layer : public compositionengine::LayerFE {
static std::atomic<int32_t> sSequence;
public:
mutable bool contentDirty{false};
- // regions below are in window-manager space
- Region visibleRegion;
- Region coveredRegion;
- Region visibleNonTransparentRegion;
Region surfaceDamageRegion;
// Layer serial number. This gives layers an explicit ordering, so we
@@ -476,6 +472,7 @@
bool onPreComposition(nsecs_t) override;
void latchCompositionState(compositionengine::LayerFECompositionState&,
bool includeGeometry) const override;
+ void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override;
std::optional<renderengine::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
@@ -493,7 +490,6 @@
Hwc2::IComposerClient::Composition getCompositionType(
const sp<const DisplayDevice>& display) const;
bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
- void updateCursorPosition(const sp<const DisplayDevice>& display);
virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
virtual void setTransformHint(uint32_t /*orientation*/) const { }
@@ -519,30 +515,6 @@
uint32_t doTransaction(uint32_t transactionFlags);
/*
- * setVisibleRegion - called to set the new visible region. This gives
- * a chance to update the new visible region or record the fact it changed.
- */
- void setVisibleRegion(const Region& visibleRegion);
-
- /*
- * setCoveredRegion - called when the covered region changes. The covered
- * region corresponds to any area of the surface that is covered
- * (transparently or not) by another surface.
- */
- void setCoveredRegion(const Region& coveredRegion);
-
- /*
- * setVisibleNonTransparentRegion - called when the visible and
- * non-transparent region changes.
- */
- void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion);
-
- /*
- * Clear the visible, covered, and non-transparent regions.
- */
- void clearVisibilityRegions();
-
- /*
* latchBuffer - called each time the screen is redrawn and returns whether
* the visible regions need to be recomputed (this is a fairly heavy
* operation, so this should be set only if needed). Typically this is used
@@ -608,6 +580,7 @@
void miniDump(std::string& result, const sp<DisplayDevice>& display) const;
void dumpFrameStats(std::string& result) const;
void dumpFrameEvents(std::string& result);
+ void dumpCallingUidPid(std::string& result) const;
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
@@ -684,6 +657,8 @@
compositionengine::OutputLayer* findOutputLayerForDisplay(
const sp<const DisplayDevice>& display) const;
+ Region debugGetVisibleRegionOnDefaultDisplay() const;
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
@@ -932,6 +907,11 @@
bool mGetHandleCalled = false;
void removeRemoteSyncPoints();
+
+ // Tracks the process and user id of the caller when creating this layer
+ // to help debugging.
+ pid_t mCallingPid;
+ uid_t mCallingUid;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 8d9357a..eb52d3f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -512,6 +512,7 @@
}
// Content detection is on, find the appropriate refresh rate with minimal error
+ // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs)
const float rate = static_cast<float>(mFeatures.contentRefreshRate);
auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
mRefreshRateConfigs.getRefreshRates().cend(),
@@ -541,6 +542,11 @@
return currRefreshRateType;
}
+Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ return mFeatures.refreshRateType;
+}
+
void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
std::lock_guard<std::mutex> lock(mCallbackLock);
if (mChangeRefreshRateCallback) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index c15f793..34e527c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -127,6 +127,9 @@
void dump(std::string&) const;
void dump(ConnectionHandle, std::string&) const;
+ // Get the appropriate refresh type for current conditions.
+ RefreshRateType getPreferredRefreshRateType();
+
private:
friend class TestableScheduler;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dd0890c..3498419 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -98,6 +98,7 @@
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "Effects/Daltonizer.h"
+#include "FrameTracer/FrameTracer.h"
#include "RegionSamplingThread.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/DispSyncSource.h"
@@ -239,11 +240,11 @@
std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
switch(displayColorSetting) {
- case DisplayColorSetting::MANAGED:
+ case DisplayColorSetting::kManaged:
return std::string("Managed");
- case DisplayColorSetting::UNMANAGED:
+ case DisplayColorSetting::kUnmanaged:
return std::string("Unmanaged");
- case DisplayColorSetting::ENHANCED:
+ case DisplayColorSetting::kEnhanced:
return std::string("Enhanced");
default:
return std::string("Unknown ") +
@@ -257,6 +258,7 @@
: mFactory(factory),
mInterceptor(mFactory.createSurfaceInterceptor(this)),
mTimeStats(mFactory.createTimeStats()),
+ mFrameTracer(std::make_unique<FrameTracer>()),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
mPhaseOffsets(mFactory.createPhaseOffsets()) {}
@@ -513,7 +515,7 @@
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
- mTimeStats->initializeTracing();
+ mFrameTracer->initialize();
// wait patiently for the window manager death
const String16 name("window");
@@ -1133,9 +1135,10 @@
ALOGW("Attempt to set active color mode %s (%d) for virtual display",
decodeColorMode(mode).c_str(), mode);
} else {
- display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC,
- Dataspace::UNKNOWN);
+ display->getCompositionDisplay()->setColorProfile(
+ compositionengine::Output::ColorProfile{mode, Dataspace::UNKNOWN,
+ RenderIntent::COLORIMETRIC,
+ Dataspace::UNKNOWN});
}
}));
@@ -1788,6 +1791,20 @@
if (compositionLayer) refreshArgs.layers.push_back(compositionLayer);
});
refreshArgs.repaintEverything = mRepaintEverything.exchange(false);
+ refreshArgs.outputColorSetting = useColorManagement
+ ? mDisplayColorSetting
+ : compositionengine::OutputColorSetting::kUnmanaged;
+ refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace;
+ refreshArgs.forceOutputColorMode = mForceColorMode;
+ refreshArgs.updatingGeometryThisFrame = mGeometryInvalid;
+
+ if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
+ refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix;
+ mDrawingState.colorMatrixChanged = false;
+ }
+
+ refreshArgs.devOptForceClientComposition = mDebugDisableHWC || mDebugRegion;
+
if (mDebugRegion != 0) {
refreshArgs.devOptFlashDirtyRegionsDelay =
std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0);
@@ -1795,14 +1812,10 @@
mCompositionEngine->preComposition(refreshArgs);
rebuildLayerStacks();
- calculateWorkingSet();
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- display->beginFrame();
- display->prepareFrame();
- display->devOptRepaintFlash(refreshArgs);
- doComposition(displayDevice, refreshArgs.repaintEverything);
- }
+ refreshArgs.updatingGeometryThisFrame = mGeometryInvalid; // Can be set by rebuildLayerStacks()
+ mCompositionEngine->present(refreshArgs);
+
+ mGeometryInvalid = false;
postFrame();
postComposition();
@@ -1851,74 +1864,6 @@
return refreshNeeded;
}
-void SurfaceFlinger::calculateWorkingSet() {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
- const bool updatingGeometryThisFrame = mGeometryInvalid;
- mGeometryInvalid = false;
-
- // Latch the frontend layer composition state for each layer being
- // composed.
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- for (auto& layer : display->getOutputLayersOrderedByZ()) {
- layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
- updatingGeometryThisFrame);
- }
- }
-
- if (CC_UNLIKELY(updatingGeometryThisFrame)) {
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- uint32_t zOrder = 0;
-
- for (auto& layer : display->getOutputLayersOrderedByZ()) {
- // Assign a simple Z order sequence to each visible layer.
- layer->editState().z = zOrder++;
- }
- }
- }
-
- // Determine the color configuration of each output
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
-
- ColorMode colorMode = ColorMode::NATIVE;
- Dataspace dataspace = Dataspace::UNKNOWN;
- RenderIntent renderIntent = RenderIntent::COLORIMETRIC;
- if (useColorManagement) {
- pickColorMode(displayDevice, &colorMode, &dataspace, &renderIntent);
- }
- display->setColorMode(colorMode, dataspace, renderIntent, mColorSpaceAgnosticDataspace);
- }
-
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
-
- for (auto& layer : display->getOutputLayersOrderedByZ()) {
- if (mDebugDisableHWC || mDebugRegion) {
- layer->editState().forceClientComposition = true;
- }
-
- // Update the composition state of the output layer, as needed
- // recomputing it from the state given by the front-end layer.
- layer->updateCompositionState(updatingGeometryThisFrame);
-
- // Send the updated state to the HWC, if appropriate.
- layer->writeStateToHWC(updatingGeometryThisFrame);
- }
- }
-
- if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- display->setColorTransform(mDrawingState.colorMatrix);
- }
- mDrawingState.colorMatrixChanged = false;
- }
-}
-
void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
@@ -2142,6 +2087,12 @@
ATRACE_NAME("rebuildLayerStacks VR Dirty");
invalidateHwcGeometry();
+ std::vector<sp<compositionengine::LayerFE>> layersWithQueuedFrames;
+ layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
+ for (sp<Layer> layer : mLayersWithQueuedFrames) {
+ layersWithQueuedFrames.push_back(layer);
+ }
+
for (const auto& pair : mDisplays) {
const auto& displayDevice = pair.second;
auto display = displayDevice->getCompositionDisplay();
@@ -2149,65 +2100,45 @@
Region opaqueRegion;
Region dirtyRegion;
compositionengine::Output::OutputLayers layersSortedByZ;
- compositionengine::Output::ReleasedLayers releasedLayers;
- Vector<sp<Layer>> deprecated_layersSortedByZ;
const ui::Transform& tr = displayState.transform;
const Rect bounds = displayState.bounds;
- if (displayState.isEnabled) {
- computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
-
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- auto compositionLayer = layer->getCompositionLayer();
- if (compositionLayer == nullptr) {
- return;
- }
-
- const auto displayId = displayDevice->getId();
- sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
- LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
-
- bool needsOutputLayer = false;
-
- if (display->belongsInOutput(layer->getLayerStack(),
- layer->getPrimaryDisplayOnly())) {
- Region drawRegion(tr.transform(
- layer->visibleNonTransparentRegion));
- drawRegion.andSelf(bounds);
- if (!drawRegion.isEmpty()) {
- needsOutputLayer = true;
- }
- }
-
- if (needsOutputLayer) {
- layersSortedByZ.emplace_back(
- display->getOrCreateOutputLayer(displayId, compositionLayer,
- layerFE));
- deprecated_layersSortedByZ.add(layer);
-
- auto& outputLayerState = layersSortedByZ.back()->editState();
- outputLayerState.visibleRegion =
- tr.transform(layer->visibleRegion.intersect(displayState.viewport));
- } else if (displayId) {
- // For layers that are being removed from a HWC display,
- // and that have queued frames, add them to a a list of
- // released layers so we can properly set a fence.
- bool hasExistingOutputLayer =
- display->getOutputLayerForLayer(compositionLayer.get()) != nullptr;
- bool hasQueuedFrames = std::find(mLayersWithQueuedFrames.cbegin(),
- mLayersWithQueuedFrames.cend(),
- layer) != mLayersWithQueuedFrames.cend();
-
- if (hasExistingOutputLayer && hasQueuedFrames) {
- releasedLayers.push_back(layer);
- }
- }
- });
+ if (!displayState.isEnabled) {
+ continue;
}
- display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
- display->setReleasedLayers(std::move(releasedLayers));
+ computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion, layersSortedByZ);
- displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ);
+ // computeVisibleRegions walks the layers in reverse-Z order. Reverse
+ // to get a back-to-front ordering.
+ std::reverse(layersSortedByZ.begin(), layersSortedByZ.end());
+
+ display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
+
+ compositionengine::Output::ReleasedLayers releasedLayers;
+ if (displayDevice->getId() && !layersWithQueuedFrames.empty()) {
+ // For layers that are being removed from a HWC display,
+ // and that have queued frames, add them to a a list of
+ // released layers so we can properly set a fence.
+
+ // Any non-null entries in the current list of layers are layers
+ // that are no longer going to be visible
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ if (!layer) {
+ continue;
+ }
+
+ sp<compositionengine::LayerFE> layerFE(&layer->getLayerFE());
+ const bool hasQueuedFrames =
+ std::find(layersWithQueuedFrames.cbegin(),
+ layersWithQueuedFrames.cend(),
+ layerFE) != layersWithQueuedFrames.cend();
+
+ if (hasQueuedFrames) {
+ releasedLayers.emplace_back(layerFE);
+ }
+ }
+ }
+ display->setReleasedLayers(std::move(releasedLayers));
Region undefinedRegion{bounds};
undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
@@ -2218,129 +2149,6 @@
}
}
-// Returns a data space that fits all visible layers. The returned data space
-// can only be one of
-// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
-// - Dataspace::DISPLAY_P3
-// - Dataspace::DISPLAY_BT2020
-// The returned HDR data space is one of
-// - Dataspace::UNKNOWN
-// - Dataspace::BT2020_HLG
-// - Dataspace::BT2020_PQ
-Dataspace SurfaceFlinger::getBestDataspace(const sp<DisplayDevice>& display,
- Dataspace* outHdrDataSpace,
- bool* outIsHdrClientComposition) const {
- Dataspace bestDataSpace = Dataspace::V0_SRGB;
- *outHdrDataSpace = Dataspace::UNKNOWN;
-
- for (const auto& layer : display->getVisibleLayersSortedByZ()) {
- switch (layer->getDataSpace()) {
- case Dataspace::V0_SCRGB:
- case Dataspace::V0_SCRGB_LINEAR:
- case Dataspace::BT2020:
- case Dataspace::BT2020_ITU:
- case Dataspace::BT2020_LINEAR:
- case Dataspace::DISPLAY_BT2020:
- bestDataSpace = Dataspace::DISPLAY_BT2020;
- break;
- case Dataspace::DISPLAY_P3:
- bestDataSpace = Dataspace::DISPLAY_P3;
- break;
- case Dataspace::BT2020_PQ:
- case Dataspace::BT2020_ITU_PQ:
- bestDataSpace = Dataspace::DISPLAY_P3;
- *outHdrDataSpace = Dataspace::BT2020_PQ;
- *outIsHdrClientComposition =
- layer->getCompositionLayer()->getState().frontEnd.forceClientComposition;
- break;
- case Dataspace::BT2020_HLG:
- case Dataspace::BT2020_ITU_HLG:
- bestDataSpace = Dataspace::DISPLAY_P3;
- // When there's mixed PQ content and HLG content, we set the HDR
- // data space to be BT2020_PQ and convert HLG to PQ.
- if (*outHdrDataSpace == Dataspace::UNKNOWN) {
- *outHdrDataSpace = Dataspace::BT2020_HLG;
- }
- break;
- default:
- break;
- }
- }
-
- return bestDataSpace;
-}
-
-// Pick the ColorMode / Dataspace for the display device.
-void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& display, ColorMode* outMode,
- Dataspace* outDataSpace, RenderIntent* outRenderIntent) const {
- if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
- *outMode = ColorMode::NATIVE;
- *outDataSpace = Dataspace::UNKNOWN;
- *outRenderIntent = RenderIntent::COLORIMETRIC;
- return;
- }
-
- Dataspace hdrDataSpace;
- bool isHdrClientComposition = false;
- Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace, &isHdrClientComposition);
-
- auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();
-
- switch (mForceColorMode) {
- case ColorMode::SRGB:
- bestDataSpace = Dataspace::V0_SRGB;
- break;
- case ColorMode::DISPLAY_P3:
- bestDataSpace = Dataspace::DISPLAY_P3;
- break;
- default:
- break;
- }
-
- // respect hdrDataSpace only when there is no legacy HDR support
- const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
- !profile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition;
- if (isHdr) {
- bestDataSpace = hdrDataSpace;
- }
-
- RenderIntent intent;
- switch (mDisplayColorSetting) {
- case DisplayColorSetting::MANAGED:
- case DisplayColorSetting::UNMANAGED:
- intent = isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;
- break;
- case DisplayColorSetting::ENHANCED:
- intent = isHdr ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::ENHANCE;
- break;
- default: // vendor display color setting
- intent = static_cast<RenderIntent>(mDisplayColorSetting);
- break;
- }
-
- profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
-}
-
-void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
- ATRACE_CALL();
- ALOGV("doComposition");
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- if (displayState.isEnabled) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
-
- // repaint the framebuffer (if needed)
- doDisplayComposition(displayDevice, dirtyRegion);
-
- display->editState().dirtyRegion.clear();
- display->getRenderSurface()->flip();
- }
- displayDevice->getCompositionDisplay()->postFramebuffer();
-}
-
void SurfaceFlinger::postFrame()
{
// |mStateLock| not needed as we are on the main thread
@@ -2488,8 +2296,10 @@
defaultColorMode = ColorMode::SRGB;
defaultDataSpace = Dataspace::V0_SRGB;
}
- display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN);
+ display->getCompositionDisplay()->setColorProfile(
+ compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace,
+ RenderIntent::COLORIMETRIC,
+ Dataspace::UNKNOWN});
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
@@ -2835,45 +2645,43 @@
void SurfaceFlinger::updateCursorAsync()
{
- for (const auto& [token, display] : mDisplays) {
- if (!display->getId()) {
- continue;
- }
-
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
- layer->updateCursorPosition(display);
+ compositionengine::CompositionRefreshArgs refreshArgs;
+ for (const auto& [_, display] : mDisplays) {
+ if (display->getId()) {
+ refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
}
+
+ mCompositionEngine->updateCursorAsync(refreshArgs);
}
void SurfaceFlinger::commitTransaction()
{
- if (!mLayersPendingRemoval.isEmpty()) {
- // Notify removed layers now that they can't be drawn from
- for (const auto& l : mLayersPendingRemoval) {
- recordBufferingStats(l->getName().string(),
- l->getOccupancyHistory(true));
-
- // Ensure any buffers set to display on any children are released.
- if (l->isRemovedFromCurrentState()) {
- l->latchAndReleaseBuffer();
- }
-
- // If the layer has been removed and has no parent, then it will not be reachable
- // when traversing layers on screen. Add the layer to the offscreenLayers set to
- // ensure we can copy its current to drawing state.
- if (!l->getParent()) {
- mOffscreenLayers.emplace(l.get());
- }
- }
- mLayersPendingRemoval.clear();
- }
-
- // If this transaction is part of a window animation then the next frame
- // we composite should be considered an animation as well.
- mAnimCompositionPending = mAnimTransactionPending;
-
withTracingLock([&]() {
+ if (!mLayersPendingRemoval.isEmpty()) {
+ // Notify removed layers now that they can't be drawn from
+ for (const auto& l : mLayersPendingRemoval) {
+ recordBufferingStats(l->getName().string(), l->getOccupancyHistory(true));
+
+ // Ensure any buffers set to display on any children are released.
+ if (l->isRemovedFromCurrentState()) {
+ l->latchAndReleaseBuffer();
+ }
+
+ // If the layer has been removed and has no parent, then it will not be reachable
+ // when traversing layers on screen. Add the layer to the offscreenLayers set to
+ // ensure we can copy its current to drawing state.
+ if (!l->getParent()) {
+ mOffscreenLayers.emplace(l.get());
+ }
+ }
+ mLayersPendingRemoval.clear();
+ }
+
+ // If this transaction is part of a window animation then the next frame
+ // we composite should be considered an animation as well.
+ mAnimCompositionPending = mAnimTransactionPending;
+
mDrawingState = mCurrentState;
// clear the "changed" flags in current state
mCurrentState.colorMatrixChanged = false;
@@ -2928,8 +2736,10 @@
}
}
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
- Region& outDirtyRegion, Region& outOpaqueRegion) {
+void SurfaceFlinger::computeVisibleRegions(
+ const sp<const DisplayDevice>& displayDevice, Region& outDirtyRegion,
+ Region& outOpaqueRegion,
+ std::vector<std::unique_ptr<compositionengine::OutputLayer>>& outLayersSortedByZ) {
ATRACE_CALL();
ALOGV("computeVisibleRegions");
@@ -2942,6 +2752,11 @@
outDirtyRegion.clear();
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer == nullptr) {
+ return;
+ }
+
// start with the whole surface at its current location
const Layer::State& s(layer->getDrawingState());
@@ -2979,7 +2794,6 @@
*/
Region transparentRegion;
-
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
const bool translucent = !layer->isOpaque(s);
@@ -3012,7 +2826,6 @@
}
if (visibleRegion.isEmpty()) {
- layer->clearVisibilityRegions();
return;
}
@@ -3025,12 +2838,21 @@
// subtract the opaque region covered by the layers above us
visibleRegion.subtractSelf(aboveOpaqueLayers);
+ // Get coverage information for the layer as previously displayed
+ auto prevOutputLayer = display->getOutputLayerForLayer(compositionLayer.get());
+ // TODO(b/121291683): Define this as a constant in Region.h
+ const Region kEmptyRegion;
+ const Region& oldVisibleRegion =
+ prevOutputLayer ? prevOutputLayer->getState().visibleRegion : kEmptyRegion;
+ const Region& oldCoveredRegion =
+ prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion;
+
// compute this layer's dirty region
if (layer->contentDirty) {
// we need to invalidate the whole region
dirty = visibleRegion;
// as well, as the old visible region
- dirty.orSelf(layer->visibleRegion);
+ dirty.orSelf(oldVisibleRegion);
layer->contentDirty = false;
} else {
/* compute the exposed region:
@@ -3046,8 +2868,6 @@
* exposed because of a resize.
*/
const Region newExposed = visibleRegion - coveredRegion;
- const Region oldVisibleRegion = layer->visibleRegion;
- const Region oldCoveredRegion = layer->coveredRegion;
const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
}
@@ -3059,11 +2879,30 @@
// Update aboveOpaqueLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
- // Store the visible region in screen space
- layer->setVisibleRegion(visibleRegion);
- layer->setCoveredRegion(coveredRegion);
- layer->setVisibleNonTransparentRegion(
- visibleRegion.subtract(transparentRegion));
+ // Compute the visible non-transparent region
+ Region visibleNonTransparentRegion = visibleRegion.subtract(transparentRegion);
+
+ // Setup an output layer for this output if the layer is visible on this
+ // output
+ const auto& displayState = display->getState();
+ Region drawRegion(displayState.transform.transform(visibleNonTransparentRegion));
+ drawRegion.andSelf(displayState.bounds);
+ if (drawRegion.isEmpty()) {
+ return;
+ }
+
+ const auto displayId = displayDevice->getId();
+ sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
+ LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
+
+ outLayersSortedByZ.emplace_back(
+ display->getOrCreateOutputLayer(displayId, compositionLayer, layerFE));
+ auto& outputLayerState = outLayersSortedByZ.back()->editState();
+ outputLayerState.visibleRegion = std::move(visibleRegion);
+ outputLayerState.visibleNonTransparentRegion = std::move(visibleNonTransparentRegion);
+ outputLayerState.coveredRegion = std::move(coveredRegion);
+ outputLayerState.outputSpaceVisibleRegion = displayState.transform.transform(
+ outputLayerState.visibleRegion.intersect(displayState.viewport));
});
outOpaqueRegion = aboveOpaqueLayers;
@@ -3162,26 +3001,6 @@
mGeometryInvalid = true;
}
-void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
- const Region& inDirtyRegion) {
- auto display = displayDevice->getCompositionDisplay();
- // We only need to actually compose the display if:
- // 1) It is being handled by hardware composer, which may need this to
- // keep its virtual display state machine in sync, or
- // 2) There is work to be done (the dirty region isn't empty)
- if (!displayDevice->getId() && inDirtyRegion.isEmpty()) {
- ALOGV("Skipping display composition");
- return;
- }
-
- ALOGV("doDisplayComposition");
- base::unique_fd readyFence;
- if (!display->composeSurfaces(Region::INVALID_REGION, &readyFence)) return;
-
- // swap buffers (presentation)
- display->getRenderSurface()->queueBuffer(std::move(readyFence));
-}
-
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
@@ -4262,9 +4081,11 @@
if (asProto) {
result.append(layersProto.SerializeAsString());
} else {
+ // Dump info that we need to access from the main thread
const auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
result.append(LayerProtoParser::layerTreeToString(layerTree));
result.append("\n");
+ dumpOffscreenLayers(result);
}
}
}
@@ -4522,12 +4343,54 @@
return layersProto;
}
+void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags) const {
+ // Add a fake invisible root layer to the proto output and parent all the offscreen layers to
+ // it.
+ LayerProto* rootProto = layersProto.add_layers();
+ const int32_t offscreenRootLayerId = INT32_MAX - 2;
+ rootProto->set_id(offscreenRootLayerId);
+ rootProto->set_name("Offscreen Root");
+
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ // Add layer as child of the fake root
+ rootProto->add_children(offscreenLayer->sequence);
+
+ // Add layer
+ LayerProto* layerProto = layersProto.add_layers();
+ offscreenLayer->writeToProtoDrawingState(layerProto, traceFlags);
+ offscreenLayer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing,
+ traceFlags);
+ layerProto->set_parent(offscreenRootLayerId);
+
+ // Add children
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (layer == offscreenLayer) {
+ return;
+ }
+ LayerProto* childProto = layersProto.add_layers();
+ layer->writeToProtoDrawingState(childProto, traceFlags);
+ layer->writeToProtoCommonState(childProto, LayerVector::StateSet::Drawing, traceFlags);
+ });
+ }
+}
+
LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
LayersProto layersProto;
postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); }));
return layersProto;
}
+void SurfaceFlinger::dumpOffscreenLayers(std::string& result) {
+ result.append("Offscreen Layers:\n");
+ postMessageSync(new LambdaMessage([&]() {
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ layer->dumpCallingUidPid(result);
+ });
+ }
+ }));
+}
+
void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
@@ -5067,13 +4930,13 @@
DisplayColorSetting setting = static_cast<DisplayColorSetting>(data.readInt32());
switch (setting) {
- case DisplayColorSetting::MANAGED:
+ case DisplayColorSetting::kManaged:
reply->writeBool(useColorManagement);
break;
- case DisplayColorSetting::UNMANAGED:
+ case DisplayColorSetting::kUnmanaged:
reply->writeBool(true);
break;
- case DisplayColorSetting::ENHANCED:
+ case DisplayColorSetting::kEnhanced:
reply->writeBool(display->hasRenderIntent(RenderIntent::ENHANCE));
break;
default: // vendor display color setting
@@ -5737,25 +5600,47 @@
}
}
+void SurfaceFlinger::setPreferredDisplayConfig() {
+ const auto& type = mScheduler->getPreferredRefreshRateType();
+ const auto& config = mRefreshRateConfigs.getRefreshRate(type);
+ if (config && isDisplayConfigAllowed(config->configId)) {
+ ALOGV("switching to Scheduler preferred config %d", config->configId);
+ setDesiredActiveConfig({type, config->configId, Scheduler::ConfigEvent::Changed});
+ } else {
+ // Set the highest allowed config by iterating backwards on available refresh rates
+ const auto& refreshRates = mRefreshRateConfigs.getRefreshRates();
+ for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
+ if (iter->second && isDisplayConfigAllowed(iter->second->configId)) {
+ ALOGV("switching to allowed config %d", iter->second->configId);
+ setDesiredActiveConfig({iter->first, iter->second->configId,
+ Scheduler::ConfigEvent::Changed});
+ }
+ }
+ }
+}
+
void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
const std::vector<int32_t>& allowedConfigs) {
if (!display->isPrimary()) {
return;
}
- ALOGV("Updating allowed configs");
- mAllowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(), allowedConfigs.end());
-
- // Set the highest allowed config by iterating backwards on available refresh rates
- const auto& refreshRates = mRefreshRateConfigs.getRefreshRates();
- for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
- if (iter->second && isDisplayConfigAllowed(iter->second->configId)) {
- ALOGV("switching to config %d", iter->second->configId);
- setDesiredActiveConfig(
- {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed});
- break;
- }
+ const auto allowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(),
+ allowedConfigs.end());
+ if (allowedDisplayConfigs == mAllowedDisplayConfigs) {
+ return;
}
+
+ ALOGV("Updating allowed configs");
+ mAllowedDisplayConfigs = std::move(allowedDisplayConfigs);
+
+ // 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.
+ // Giving current ActiveConfig so that most other listeners would just drop the event
+ mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
+ display->getActiveConfig());
+
+ setPreferredDisplayConfig();
}
status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bc57284..f220c26 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -23,6 +23,7 @@
*/
#include <android-base/thread_annotations.h>
+#include <compositionengine/OutputColorSetting.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <gui/BufferQueue.h>
@@ -94,9 +95,13 @@
class RefreshRateOverlay;
class RegionSamplingThread;
class TimeStats;
+class FrameTracer;
namespace compositionengine {
class DisplaySurface;
+class OutputLayer;
+
+struct CompositionRefreshArgs;
} // namespace compositionengine
namespace renderengine {
@@ -116,11 +121,7 @@
eTransactionMask = 0x1f,
};
-enum class DisplayColorSetting : int32_t {
- MANAGED = 0,
- UNMANAGED = 1,
- ENHANCED = 2,
-};
+using DisplayColorSetting = compositionengine::OutputColorSetting;
class SurfaceFlingerBE
{
@@ -528,6 +529,9 @@
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
+ // Query the Scheduler or allowed display configs list for a matching config, and set it
+ void setPreferredDisplayConfig() REQUIRES(mStateLock);
+
// called on the main thread in response to setAllowedDisplayConfigs()
void setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
const std::vector<int32_t>& allowedConfigs)
@@ -741,8 +745,9 @@
* Compositing
*/
void invalidateHwcGeometry();
- void computeVisibleRegions(const sp<const DisplayDevice>& display, Region& dirtyRegion,
- Region& opaqueRegion);
+ void computeVisibleRegions(
+ const sp<const DisplayDevice>& display, Region& dirtyRegion, Region& opaqueRegion,
+ std::vector<std::unique_ptr<compositionengine::OutputLayer>>& outputLayers);
void postComposition();
void getCompositorTiming(CompositorTiming* compositorTiming);
@@ -752,19 +757,6 @@
nsecs_t compositeToPresentLatency);
void rebuildLayerStacks();
- ui::Dataspace getBestDataspace(const sp<DisplayDevice>& display, ui::Dataspace* outHdrDataSpace,
- bool* outIsHdrClientComposition) const;
-
- // Returns the appropriate ColorMode, Dataspace and RenderIntent for the
- // DisplayDevice. The function only returns the supported ColorMode,
- // Dataspace and RenderIntent.
- void pickColorMode(const sp<DisplayDevice>& display, ui::ColorMode* outMode,
- ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const;
-
- void calculateWorkingSet();
- void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
- void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
-
void postFrame();
/* ------------------------------------------------------------------------
@@ -875,8 +867,11 @@
void dumpDisplayIdentificationData(std::string& result) const;
void dumpWideColorInfo(std::string& result) const;
LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ void dumpOffscreenLayersProto(LayersProto& layersProto,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
EXCLUDES(mStateLock);
+ void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock);
void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
bool isLayerTripleBufferingDisabled() const {
@@ -995,6 +990,7 @@
bool mTracingEnabled = false;
bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
const std::shared_ptr<TimeStats> mTimeStats;
+ const std::unique_ptr<FrameTracer> mFrameTracer;
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
std::atomic<uint32_t> mHwcFrameMissedCount = 0;
@@ -1073,7 +1069,7 @@
static bool useVrFlinger;
std::thread::id mMainThreadId = std::this_thread::get_id();
- DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED;
+ DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::kEnhanced;
// Color mode forced by setting persist.sys.sf.color_mode, it must:
// 1. not be NATIVE color mode, NATIVE color mode means no forced color mode;
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 9053f2c..eb26cd0 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -163,6 +163,7 @@
entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry.set_where(where);
LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
+ mFlinger.dumpOffscreenLayersProto(layers);
entry.mutable_layers()->Swap(&layers);
return entry;
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 9e1d503..2080a38 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -2,12 +2,9 @@
name: "libtimestats",
defaults: ["surfaceflinger_defaults"],
srcs: [
- "TimeStats.cpp"
+ "TimeStats.cpp",
],
export_include_dirs: ["."],
- static_libs: [
- "libperfetto_client_experimental",
- ],
shared_libs: [
"libtimestats_proto",
"libui",
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index b66e4cf..b01fa81 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -30,141 +30,10 @@
#include <algorithm>
#include <regex>
-PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::impl::TimeStats::TimeStatsDataSource);
-
namespace android {
namespace impl {
-void TimeStats::initializeTracing() {
- perfetto::TracingInitArgs args;
- args.backends = perfetto::kSystemBackend;
- perfetto::Tracing::Initialize(args);
- registerTracingDataSource();
-}
-
-void TimeStats::registerTracingDataSource() {
- perfetto::DataSourceDescriptor dsd;
- dsd.set_name(kTimeStatsDataSource);
- TimeStatsDataSource::Register(dsd);
-}
-
-void TimeStats::traceNewLayer(int32_t layerID, const std::string& layerName) {
- TimeStatsDataSource::Trace([this, layerID, &layerName](TimeStatsDataSource::TraceContext) {
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- mTraceTracker[layerID].layerName = layerName;
- }
- });
-}
-
-void TimeStats::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration) {
- TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type,
- duration](TimeStatsDataSource::TraceContext ctx) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- return;
- }
-
- // Handle any pending fences for this buffer.
- tracePendingFencesLocked(ctx, layerID, bufferID);
-
- // Complete current trace.
- traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
- });
-}
-
-void TimeStats::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence,
- FrameEvent::BufferEventType type, nsecs_t startTime) {
- TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type,
- startTime](TimeStatsDataSource::TraceContext ctx) {
- const nsecs_t signalTime = fence->getSignalTime();
- if (signalTime != Fence::SIGNAL_TIME_INVALID) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- return;
- }
-
- // Handle any pending fences for this buffer.
- tracePendingFencesLocked(ctx, layerID, bufferID);
-
- if (signalTime != Fence::SIGNAL_TIME_PENDING) {
- traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime);
- } else {
- mTraceTracker[layerID].pendingFences[bufferID].push_back(
- {.frameNumber = frameNumber,
- .type = type,
- .fence = fence,
- .startTime = startTime});
- }
- }
- });
-}
-
-void TimeStats::tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID) {
- if (mTraceTracker[layerID].pendingFences.count(bufferID)) {
- auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID];
- for (size_t i = 0; i < pendingFences.size(); ++i) {
- auto& pendingFence = pendingFences[i];
-
- nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
- if (pendingFence.fence && pendingFence.fence->isValid()) {
- signalTime = pendingFence.fence->getSignalTime();
- if (signalTime == Fence::SIGNAL_TIME_PENDING) {
- continue;
- }
- }
-
- if (signalTime != Fence::SIGNAL_TIME_INVALID &&
- systemTime() - signalTime < kFenceSignallingDeadline) {
- traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type,
- pendingFence.startTime, signalTime);
- }
-
- pendingFences.erase(pendingFences.begin() + i);
- --i;
- }
- }
-}
-
-void TimeStats::traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
- FrameEvent::BufferEventType type, nsecs_t duration) {
- auto packet = ctx.NewTracePacket();
- packet->set_timestamp(timestamp);
- auto* event = packet->set_graphics_frame_event()->set_buffer_event();
- event->set_buffer_id(static_cast<uint32_t>(bufferID));
- event->set_frame_number(frameNumber);
- event->set_type(type);
-
- if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
- !mTraceTracker[layerID].layerName.empty()) {
- const std::string& layerName = mTraceTracker[layerID].layerName;
- event->set_layer_name(layerName.c_str(), layerName.size());
- }
-
- if (duration > 0) {
- event->set_duration_ns(duration);
- }
-}
-
-void TimeStats::traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID, uint64_t frameNumber,
- FrameEvent::BufferEventType type, nsecs_t startTime,
- nsecs_t endTime) {
- nsecs_t timestamp = endTime;
- nsecs_t duration = 0;
- if (startTime > 0 && startTime < endTime) {
- timestamp = startTime;
- duration = endTime - startTime;
- }
- traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
-}
-
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
ATRACE_CALL();
@@ -207,8 +76,6 @@
mTimeStatsTracker.size());
android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n",
mTimeStats.stats.size());
- android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n",
- mTraceTracker.size());
return result;
}
@@ -542,15 +409,8 @@
void TimeStats::onDestroy(int32_t layerID) {
ATRACE_CALL();
ALOGV("[%d]-onDestroy", layerID);
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStatsTracker.erase(layerID);
- }
-
- {
- std::lock_guard<std::mutex> traceLock(mTraceMutex);
- mTraceTracker.erase(layerID);
- }
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStatsTracker.erase(layerID);
}
void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 470137a..9ebc1ad 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -17,8 +17,6 @@
#pragma once
#include <hardware/hwcomposer_defs.h>
-#include <perfetto/trace/android/graphics_frame_event.pbzero.h>
-#include <perfetto/tracing.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
#include <ui/FenceTime.h>
@@ -36,32 +34,8 @@
class TimeStats {
public:
- using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
-
virtual ~TimeStats() = default;
- // Sets up the perfetto tracing backend and data source.
- virtual void initializeTracing() = 0;
- // Registers the data source with the perfetto backend. Called as part of initializeTracing()
- // and should not be called manually outside of tests. Public to allow for substituting a
- // perfetto::kInProcessBackend in tests.
- virtual void registerTracingDataSource() = 0;
- // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or
- // traceFence() for each layer.
- virtual void traceNewLayer(int32_t layerID, const std::string& layerName) = 0;
- // Creates a trace point at the timestamp provided.
- virtual void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration = 0) = 0;
- // Creates a trace point after the provided fence has been signalled. If a startTime is provided
- // the trace will have be timestamped from startTime until fence signalling time. If no
- // startTime is provided, a durationless trace point will be created timestamped at fence
- // signalling time. If the fence hasn't signalled yet, the trace point will be created the next
- // time after signalling a trace call for this buffer occurs.
- virtual void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence,
- FrameEvent::BufferEventType type, nsecs_t startTime = 0) = 0;
-
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
virtual std::string miniDump() = 0;
@@ -89,13 +63,6 @@
// Source of truth is RefrehRateStats.
virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
-
- static constexpr char kTimeStatsDataSource[] = "android.surfaceflinger.timestats";
-
- // The maximum amount of time a fence has to signal before it is discarded.
- // Used to avoid fence's from previous traces generating new trace points in later ones.
- // Public for testing.
- static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds
};
namespace impl {
@@ -117,13 +84,6 @@
std::shared_ptr<FenceTime> presentFence;
};
- struct PendingFence {
- uint64_t frameNumber;
- FrameEvent::BufferEventType type;
- std::shared_ptr<FenceTime> fence;
- nsecs_t startTime;
- };
-
struct LayerRecord {
std::string layerName;
// This is the index in timeRecords, at which the timestamps for that
@@ -135,12 +95,6 @@
std::deque<TimeRecord> timeRecords;
};
- struct TraceRecord {
- std::string layerName;
- using BufferID = uint64_t;
- std::unordered_map<BufferID, std::vector<PendingFence>> pendingFences;
- };
-
struct PowerTime {
int32_t powerMode = HWC_POWER_MODE_OFF;
nsecs_t prevTime = 0;
@@ -152,23 +106,8 @@
};
public:
- class TimeStatsDataSource : public perfetto::DataSource<TimeStatsDataSource> {
- virtual void OnSetup(const SetupArgs&) override{};
- virtual void OnStart(const StartArgs&) override { ALOGV("TimeStats trace started"); };
- virtual void OnStop(const StopArgs&) override { ALOGV("TimeStats trace stopped"); };
- };
-
TimeStats() = default;
- void initializeTracing() override;
- void registerTracingDataSource() override;
- void traceNewLayer(int32_t layerID, const std::string& layerName) override;
- void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
- FrameEvent::BufferEventType type, nsecs_t duration = 0) override;
- void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence, FrameEvent::BufferEventType type,
- nsecs_t startTime = 0) override;
-
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
std::string miniDump() override;
@@ -200,20 +139,6 @@
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
- // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates
- // trace points for them.
- void tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID);
- // Creates a trace point by translating a start time and an end time to a timestamp and
- // duration. If startTime is later than end time it sets end time as the timestamp and the
- // duration to 0. Used by traceFence().
- void traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
- uint64_t frameNumber, FrameEvent::BufferEventType type, nsecs_t startTime,
- nsecs_t endTime);
- void traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
- uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration = 0);
-
bool recordReadyLocked(int32_t layerID, TimeRecord* timeRecord);
void flushAvailableRecordsToStatsLocked(int32_t layerID);
void flushPowerTimeLocked();
@@ -232,9 +157,6 @@
PowerTime mPowerTime;
GlobalRecord mGlobalRecord;
- std::mutex mTraceMutex;
- std::unordered_map<int32_t, TraceRecord> mTraceTracker;
-
static const size_t MAX_NUM_LAYER_RECORDS = 200;
static const size_t MAX_NUM_LAYER_STATS = 200;
};
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 57851bc..3e29016 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -33,6 +33,7 @@
"libutils",
],
static_libs: [
+ "libcompositionengine",
"libgmock",
"libperfetto_client_experimental",
"librenderengine",
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 0eedf9b..8d98af6 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -51,6 +51,7 @@
"RefreshRateStatsTest.cpp",
"RegionSamplingTest.cpp",
"TimeStatsTest.cpp",
+ "FrameTracerTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
@@ -63,6 +64,7 @@
"mock/MockNativeWindowSurface.cpp",
"mock/MockSurfaceInterceptor.cpp",
"mock/MockTimeStats.cpp",
+ "mock/MockFrameTracer.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 2e64a78..9e4d57e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -614,6 +614,12 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so gtet the back layer.
+ if (layerSettings.empty()) {
+ ADD_FAILURE() << "layerSettings was not expected to be empty in "
+ "setupREBufferCompositionCommonCallExpectations "
+ "verification lambda";
+ return NO_ERROR;
+ }
renderengine::LayerSettings layer = layerSettings.back();
EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
@@ -657,6 +663,12 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
+ if (layerSettings.empty()) {
+ ADD_FAILURE()
+ << "layerSettings was not expected to be empty in "
+ "setupREColorCompositionCallExpectations verification lambda";
+ return NO_ERROR;
+ }
renderengine::LayerSettings layer = layerSettings.back();
EXPECT_THAT(layer.source.buffer.buffer, IsNull());
EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
@@ -727,6 +739,12 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
+ if (layerSettings.empty()) {
+ ADD_FAILURE() << "layerSettings was not expected to be empty in "
+ "setupInsecureREBufferCompositionCommonCallExpectations "
+ "verification lambda";
+ return NO_ERROR;
+ }
renderengine::LayerSettings layer = layerSettings.back();
EXPECT_THAT(layer.source.buffer.buffer, IsNull());
EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
@@ -786,7 +804,6 @@
layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform());
- layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
return layer;
}
@@ -801,13 +818,13 @@
layer->getCompositionLayer(),
layer));
+ outputLayers.back()->editState().visibleRegion = Region(Rect(0, 0, 100, 100));
+ outputLayers.back()->editState().outputSpaceVisibleRegion = Region(Rect(0, 0, 100, 100));
+
test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
Mock::VerifyAndClear(test->mComposer);
- Vector<sp<Layer>> layers;
- layers.add(layer);
- test->mDisplay->setVisibleLayersSortedByZ(layers);
test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
}
@@ -1096,8 +1113,6 @@
for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
hwcDisplay->mutableLayers().clear();
}
-
- test->mDisplay->setVisibleLayersSortedByZ(Vector<sp<android::Layer>>());
}
};
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index c858cc0..fcce57b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -149,7 +149,7 @@
// Default to no wide color display support configured
mFlinger.mutableHasWideColorDisplay() = false;
mFlinger.mutableUseColorManagement() = false;
- mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
// Default to using HWC virtual displays
mFlinger.mutableUseHwcVirtualDisplays() = true;
@@ -598,7 +598,7 @@
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableHasWideColorDisplay() = false;
test->mFlinger.mutableUseColorManagement() = false;
- test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
@@ -618,7 +618,7 @@
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableUseColorManagement() = true;
test->mFlinger.mutableHasWideColorDisplay() = true;
- test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
new file mode 100644
index 0000000..b5af591
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <FrameTracer/FrameTracer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <perfetto/trace/trace.pb.h>
+
+#include "libsurfaceflinger_unittest_main.h"
+
+using namespace google::protobuf;
+
+namespace android {
+namespace {
+
+class FrameTracerTest : public testing::Test {
+public:
+ FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ // Need to initialize tracing in process for testing, and only once per test suite.
+ static bool wasInitialized = false;
+ if (!wasInitialized) {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kInProcessBackend;
+ perfetto::Tracing::Initialize(args);
+ wasInitialized = true;
+ }
+ }
+
+ ~FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void SetUp() override {
+ mFrameTracer = std::make_unique<FrameTracer>();
+ mFrameTracer->registerDataSource();
+ }
+
+ void TearDown() override { mFrameTracer.reset(); }
+
+ // Each tracing session can be used for a single block of Start -> Stop.
+ static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name(FrameTracer::kFrameTracerDataSource);
+
+ auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+ tracingSession->Setup(cfg);
+ return tracingSession;
+ }
+
+ std::unique_ptr<FrameTracer> mFrameTracer;
+ FenceToFenceTimeMap fenceFactory;
+};
+
+TEST_F(FrameTracerTest, traceNewLayerStartsTrackingLayerWhenTracing) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ tracingSession->StopBlocking();
+}
+
+TEST_F(FrameTracerTest, onDestroyRemovesTheTrackedLayer) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const int32_t secondLayerID = 6;
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceNewLayer(secondLayerID, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 2\n");
+ tracingSession->StopBlocking();
+
+ mFrameTracer->onDestroy(layerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(layerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(secondLayerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+}
+
+TEST_F(FrameTracerTest, canTraceAfterAddingLayer) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 1;
+ const uint32_t bufferID = 2;
+ const uint64_t frameNumber = 3;
+ const nsecs_t timestamp = 4;
+ const nsecs_t duration = 5;
+ const auto type = FrameTracer::FrameEvent::POST;
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+
+ mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+ }
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 1);
+
+ const auto& packet = trace.packet().Get(0);
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ ASSERT_TRUE(buffer_event.has_duration_ns());
+ EXPECT_EQ(buffer_event.duration_ns(), duration);
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ // Trace.
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
+ // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+ }
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
+ const nsecs_t timestamp = systemTime();
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above.
+
+ const auto& packet = trace.packet().Get(1);
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ EXPECT_FALSE(buffer_event.has_duration_ns());
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 + 100000;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 + 100000;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2);
+
+ const auto& packet1 = trace.packet().Get(0);
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), signalTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+
+ const auto& packet2 = trace.packet().Get(1);
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), signalTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+}
+
+TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t signalTime = systemTime() - FrameTracer::kFenceSignallingDeadline;
+
+ auto tracingSession = getTracingSessionForTest();
+ auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence, type);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
+ // Create extra trace packet to trigger and finalize any previous fence packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+}
+
+TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t duration = 1234;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 - duration;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 - duration;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2);
+
+ const auto& packet1 = trace.packet().Get(0);
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), startTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event1.duration_ns(), duration);
+
+ const auto& packet2 = trace.packet().Get(1);
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), startTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event2.duration_ns(), duration);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index f01e603..ffacbfe 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -20,8 +20,8 @@
#include <TimeStats/TimeStats.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+
#include <log/log.h>
-#include <perfetto/trace/trace.pb.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -109,15 +109,6 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
-
- // Need to initialize tracing in process for testing, and only once per test suite.
- static bool wasInitialized = false;
- if (!wasInitialized) {
- perfetto::TracingInitArgs args;
- args.backends = perfetto::kInProcessBackend;
- perfetto::Tracing::Initialize(args);
- wasInitialized = true;
- }
}
~TimeStatsTest() {
@@ -126,13 +117,6 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
- void SetUp() override {
- mTimeStats = std::make_unique<impl::TimeStats>();
- mTimeStats->registerTracingDataSource();
- }
-
- void TearDown() override { mTimeStats.reset(); }
-
std::string inputCommand(InputCommand cmd, bool useProto);
void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts);
@@ -147,22 +131,8 @@
}
}
- // Each tracing session can be used for a single block of Start -> Stop.
- static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
- perfetto::TraceConfig cfg;
- cfg.set_duration_ms(500);
- cfg.add_buffers()->set_size_kb(1024);
- auto* ds_cfg = cfg.add_data_sources()->mutable_config();
- ds_cfg->set_name(TimeStats::kTimeStatsDataSource);
-
- auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
- tracingSession->Setup(cfg);
- return tracingSession;
- }
-
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats;
- FenceToFenceTimeMap fenceFactory;
+ std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -239,330 +209,6 @@
return distr(mRandomEngine);
}
-TEST_F(TimeStatsTest, traceNewLayerStartsTrackingLayerWhenTracing) {
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- mTimeStats->traceNewLayer(layerID, layerName);
-
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
- mTimeStats->traceNewLayer(layerID, layerName);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- tracingSession->StopBlocking();
-}
-
-TEST_F(TimeStatsTest, onDestroyRemovesTheTrackedLayer) {
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const int32_t secondLayerID = 6;
-
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceNewLayer(secondLayerID, layerName);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 2\n");
- tracingSession->StopBlocking();
-
- mTimeStats->onDestroy(layerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- mTimeStats->onDestroy(layerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- mTimeStats->onDestroy(secondLayerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-}
-
-TEST_F(TimeStatsTest, canTraceAfterAddingLayer) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 1;
- const uint32_t bufferID = 2;
- const uint64_t frameNumber = 3;
- const nsecs_t timestamp = 4;
- const nsecs_t duration = 5;
- const auto type = TimeStats::FrameEvent::POST;
-
- {
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
-
- mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
- // Create second trace packet to finalize the previous one.
- mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
- }
-
- {
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
-
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
- // Create second trace packet to finalize the previous one.
- mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 1);
-
- const auto& packet = trace.packet().Get(0);
- ASSERT_TRUE(packet.has_timestamp());
- EXPECT_EQ(packet.timestamp(), timestamp);
- ASSERT_TRUE(packet.has_graphics_frame_event());
- const auto& frame_event = packet.graphics_frame_event();
- ASSERT_TRUE(frame_event.has_buffer_event());
- const auto& buffer_event = frame_event.buffer_event();
- ASSERT_TRUE(buffer_event.has_buffer_id());
- EXPECT_EQ(buffer_event.buffer_id(), bufferID);
- ASSERT_TRUE(buffer_event.has_frame_number());
- EXPECT_EQ(buffer_event.frame_number(), frameNumber);
- ASSERT_TRUE(buffer_event.has_type());
- EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
- ASSERT_TRUE(buffer_event.has_duration_ns());
- EXPECT_EQ(buffer_event.duration_ns(), duration);
- }
-}
-
-TEST_F(TimeStatsTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
-
- {
- auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- // Trace.
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
- // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
- }
-
- {
- auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
- const nsecs_t timestamp = systemTime();
- fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above.
-
- const auto& packet = trace.packet().Get(1);
- ASSERT_TRUE(packet.has_timestamp());
- EXPECT_EQ(packet.timestamp(), timestamp);
- ASSERT_TRUE(packet.has_graphics_frame_event());
- const auto& frame_event = packet.graphics_frame_event();
- ASSERT_TRUE(frame_event.has_buffer_event());
- const auto& buffer_event = frame_event.buffer_event();
- ASSERT_TRUE(buffer_event.has_buffer_id());
- EXPECT_EQ(buffer_event.buffer_id(), bufferID);
- ASSERT_TRUE(buffer_event.has_frame_number());
- EXPECT_EQ(buffer_event.frame_number(), frameNumber);
- ASSERT_TRUE(buffer_event.has_type());
- EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
- EXPECT_FALSE(buffer_event.has_duration_ns());
- }
-}
-
-TEST_F(TimeStatsTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
-
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
-
- // traceFence called after fence signalled.
- const nsecs_t signalTime1 = systemTime();
- const nsecs_t startTime1 = signalTime1 + 100000;
- auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
-
- // traceFence called before fence signalled.
- const nsecs_t signalTime2 = systemTime();
- const nsecs_t startTime2 = signalTime2 + 100000;
- auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
-
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2);
-
- const auto& packet1 = trace.packet().Get(0);
- ASSERT_TRUE(packet1.has_timestamp());
- EXPECT_EQ(packet1.timestamp(), signalTime1);
- ASSERT_TRUE(packet1.has_graphics_frame_event());
- ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
- ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
-
- const auto& packet2 = trace.packet().Get(1);
- ASSERT_TRUE(packet2.has_timestamp());
- EXPECT_EQ(packet2.timestamp(), signalTime2);
- ASSERT_TRUE(packet2.has_graphics_frame_event());
- ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
- ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
-}
-
-TEST_F(TimeStatsTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
- const nsecs_t signalTime = systemTime() - TimeStats::kFenceSignallingDeadline;
-
- auto tracingSession = getTracingSessionForTest();
- auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence, type);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
- // Create extra trace packet to trigger and finalize any previous fence packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
-}
-
-TEST_F(TimeStatsTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
- const nsecs_t duration = 1234;
-
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
-
- // traceFence called after fence signalled.
- const nsecs_t signalTime1 = systemTime();
- const nsecs_t startTime1 = signalTime1 - duration;
- auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
-
- // traceFence called before fence signalled.
- const nsecs_t signalTime2 = systemTime();
- const nsecs_t startTime2 = signalTime2 - duration;
- auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
-
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2);
-
- const auto& packet1 = trace.packet().Get(0);
- ASSERT_TRUE(packet1.has_timestamp());
- EXPECT_EQ(packet1.timestamp(), startTime1);
- ASSERT_TRUE(packet1.has_graphics_frame_event());
- ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
- ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
- const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
- EXPECT_EQ(buffer_event1.duration_ns(), duration);
-
- const auto& packet2 = trace.packet().Get(1);
- ASSERT_TRUE(packet2.has_timestamp());
- EXPECT_EQ(packet2.timestamp(), startTime2);
- ASSERT_TRUE(packet2.has_graphics_frame_event());
- ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
- ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
- const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
- EXPECT_EQ(buffer_event2.duration_ns(), duration);
-}
-
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
new file mode 100644
index 0000000..358dfdb
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mock/MockFrameTracer.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+FrameTracer::FrameTracer() = default;
+FrameTracer::~FrameTracer() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
new file mode 100644
index 0000000..f768b81
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "FrameTracer/FrameTracer.h"
+
+namespace android {
+namespace mock {
+
+class FrameTracer : public android::FrameTracer {
+public:
+ FrameTracer();
+ ~FrameTracer();
+
+ MOCK_METHOD0(initialize, void());
+ MOCK_METHOD0(registerDataSource, void());
+ MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
+ MOCK_METHOD6(traceTimestamp,
+ void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD6(traceFence,
+ void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
+ FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD0(miniDump, std::string());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 542c70a..b1634a8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -28,14 +28,6 @@
TimeStats();
~TimeStats() override;
- MOCK_METHOD0(initializeTracing, void());
- MOCK_METHOD0(registerTracingDataSource, void());
- MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
- MOCK_METHOD6(traceTimestamp,
- void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
- MOCK_METHOD6(traceFence,
- void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
- FrameEvent::BufferEventType, nsecs_t));
MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
MOCK_METHOD0(isEnabled, bool());
MOCK_METHOD0(miniDump, std::string());
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 0e5faf4..4e461f9 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -12,8 +12,10 @@
],
shared_libs: [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.1-resources",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
@@ -35,11 +37,11 @@
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
- "android.hardware.graphics.composer@2.1-hal",
+ "android.hardware.graphics.composer@2.3-hal",
],
export_header_lib_headers: [
- "android.hardware.graphics.composer@2.1-hal",
+ "android.hardware.graphics.composer@2.3-hal",
],
export_static_lib_headers: [
@@ -47,8 +49,10 @@
],
export_shared_lib_headers: [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
],
export_include_dirs: ["."],
@@ -105,8 +109,8 @@
"libvr_hwc-binder",
],
shared_libs: [
- "android.frameworks.vr.composer@1.0",
- "android.hardware.graphics.composer@2.1",
+ "android.frameworks.vr.composer@2.0",
+ "android.hardware.graphics.composer@2.3",
"libbase",
"libbinder",
"liblog",
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 786d5fa..36f6b32 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
+#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
#include <hardware/gralloc.h>
#include <hardware/gralloc1.h>
#include <log/log.h>
@@ -27,8 +27,7 @@
namespace android {
namespace dvr {
-using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::frameworks::vr::composer::V1_0::IVrComposerClient;
+using android::frameworks::vr::composer::V2_0::IVrComposerClient;
VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
: ComposerClient(&hal), mVrHal(hal) {
@@ -51,7 +50,8 @@
VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
bool VrComposerClient::VrCommandEngine::executeCommand(
- IComposerClient::Command command, uint16_t length) {
+ hardware::graphics::composer::V2_1::IComposerClient::Command command,
+ uint16_t length) {
IVrComposerClient::VrCommand vrCommand =
static_cast<IVrComposerClient::VrCommand>(command);
switch (vrCommand) {
@@ -107,12 +107,14 @@
IVrComposerClient::BufferMetadata
VrComposerClient::VrCommandEngine::readBufferMetadata() {
IVrComposerClient::BufferMetadata metadata = {
- .width = read(),
- .height = read(),
- .stride = read(),
- .layerCount = read(),
- .format = static_cast<PixelFormat>(readSigned()),
- .usage = read64(),
+ .width = read(),
+ .height = read(),
+ .stride = read(),
+ .layerCount = read(),
+ .format =
+ static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(
+ readSigned()),
+ .usage = read64(),
};
return metadata;
}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 0b7ce5e..1b2b5f4 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -17,10 +17,12 @@
#ifndef ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
-#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerClient.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
namespace android {
namespace dvr {
@@ -28,8 +30,8 @@
class VrHwc;
using hardware::graphics::composer::V2_1::hal::ComposerCommandEngine;
-using hardware::graphics::composer::V2_1::hal::ComposerHal;
-using hardware::graphics::composer::V2_1::hal::detail::ComposerClientImpl;
+using hardware::graphics::composer::V2_3::hal::ComposerHal;
+using hardware::graphics::composer::V2_3::hal::detail::ComposerClientImpl;
using ComposerClient = ComposerClientImpl<IVrComposerClient, ComposerHal>;
@@ -44,8 +46,9 @@
explicit VrCommandEngine(VrComposerClient& client);
~VrCommandEngine() override;
- bool executeCommand(IComposerClient::Command command,
- uint16_t length) override;
+ bool executeCommand(
+ hardware::graphics::composer::V2_1::IComposerClient::Command command,
+ uint16_t length) override;
private:
bool executeSetLayerInfo(uint16_t length);
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 7323277..e530b16 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -27,7 +27,7 @@
#include "vr_composer_client.h"
using namespace android::hardware::graphics::common::V1_0;
-using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_3;
using android::base::StringPrintf;
using android::hardware::hidl_handle;
@@ -36,12 +36,12 @@
using android::hardware::Return;
using android::hardware::Void;
+namespace types = android::hardware::graphics::common;
+
namespace android {
namespace dvr {
namespace {
-using android::hardware::graphics::common::V1_0::PixelFormat;
-
const Display kDefaultDisplayId = 1;
const Config kDefaultConfigId = 1;
@@ -269,7 +269,8 @@
// onHotplug() call, so it's important to release mutex_ here.
lock.unlock();
event_callback_->onHotplug(kDefaultDisplayId,
- IComposerCallback::Connection::CONNECTED);
+ hardware::graphics::composer::V2_1::
+ IComposerCallback::Connection::CONNECTED);
lock.lock();
UpdateVsyncCallbackEnabledLocked();
}
@@ -282,15 +283,6 @@
uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
-Error VrHwc::createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat* format, Display* outDisplay) {
- *format = PixelFormat::RGBA_8888;
- *outDisplay = display_count_;
- displays_[display_count_].reset(new HwcDisplay(width, height));
- display_count_++;
- return Error::NONE;
-}
-
Error VrHwc::destroyVirtualDisplay(Display display) {
std::lock_guard<std::mutex> guard(mutex_);
if (display == kDefaultDisplayId || displays_.erase(display) == 0)
@@ -332,24 +324,6 @@
return Error::NONE;
}
-Error VrHwc::getClientTargetSupport(Display display, uint32_t /* width */,
- uint32_t /* height */,
- PixelFormat /* format */,
- Dataspace /* dataspace */) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
- return Error::BAD_DISPLAY;
-
- return Error::NONE;
-}
-
-Error VrHwc::getColorModes(Display /* display */,
- hidl_vec<ColorMode>* outModes) {
- std::vector<ColorMode> color_modes(1, ColorMode::NATIVE);
- *outModes = hidl_vec<ColorMode>(color_modes);
- return Error::NONE;
-}
-
Error VrHwc::getDisplayAttribute(Display display, Config config,
IComposerClient::Attribute attribute,
int32_t* outValue) {
@@ -441,17 +415,6 @@
return Error::NONE;
}
-Error VrHwc::getHdrCapabilities(Display /* display */,
- hidl_vec<Hdr>* /* outTypes */,
- float* outMaxLuminance,
- float* outMaxAverageLuminance,
- float* outMinLuminance) {
- *outMaxLuminance = 0;
- *outMaxAverageLuminance = 0;
- *outMinLuminance = 0;
- return Error::NONE;
-}
-
Error VrHwc::setActiveConfig(Display display, Config config) {
std::lock_guard<std::mutex> guard(mutex_);
auto display_ptr = FindDisplay(display);
@@ -464,47 +427,6 @@
return Error::NONE;
}
-Error VrHwc::setColorMode(Display display, ColorMode mode) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3)
- return Error::BAD_PARAMETER;
-
- display_ptr->set_color_mode(mode);
- return Error::NONE;
-}
-
-Error VrHwc::setPowerMode(Display display, IComposerClient::PowerMode mode) {
- bool dozeSupported = false;
-
- Error dozeSupportError = getDozeSupport(display, &dozeSupported);
-
- if (dozeSupportError != Error::NONE)
- return dozeSupportError;
-
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- if (mode < IComposerClient::PowerMode::OFF ||
- mode > IComposerClient::PowerMode::DOZE_SUSPEND) {
- return Error::BAD_PARAMETER;
- }
-
- if (!dozeSupported &&
- (mode == IComposerClient::PowerMode::DOZE ||
- mode == IComposerClient::PowerMode::DOZE_SUSPEND)) {
- return Error::UNSUPPORTED;
- }
-
- display_ptr->set_power_mode(mode);
- return Error::NONE;
-}
-
Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
std::lock_guard<std::mutex> guard(mutex_);
auto display_ptr = FindDisplay(display);
@@ -956,6 +878,23 @@
return Void();
}
+Return<void> VrHwc::createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) {
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ Error status = Error::NONE;
+ sp<VrComposerClient> client;
+ if (!client_.promote().get()) {
+ client = new VrComposerClient(*this);
+ } else {
+ ALOGE("Already have a client");
+ status = Error::NO_RESOURCES;
+ }
+
+ client_ = client;
+ hidl_cb(status, client);
+ return Void();
+}
+
void VrHwc::ForceDisplaysRefresh() {
std::lock_guard<std::mutex> guard(mutex_);
if (event_callback_ != nullptr) {
@@ -1044,5 +983,196 @@
callback_ = callback;
}
+// composer::V2_2::ComposerHal
+Error VrHwc::setReadbackBuffer(Display display,
+ const native_handle_t* bufferHandle,
+ android::base::unique_fd fenceFd) {
+ return Error::NONE;
+}
+
+Error VrHwc::getReadbackBufferFence(Display display,
+ android::base::unique_fd* outFenceFd) {
+ return Error::NONE;
+}
+
+Error VrHwc::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
+ types::V1_1::PixelFormat* format,
+ Display* outDisplay) {
+ *format = types::V1_1::PixelFormat::RGBA_8888;
+ *outDisplay = display_count_;
+ displays_[display_count_].reset(new HwcDisplay(width, height));
+ display_count_++;
+ return Error::NONE;
+}
+
+Error VrHwc::setPowerMode_2_2(Display display,
+ IComposerClient::PowerMode mode) {
+ bool dozeSupported = false;
+
+ Error dozeSupportError = getDozeSupport(display, &dozeSupported);
+
+ if (dozeSupportError != Error::NONE)
+ return dozeSupportError;
+
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
+
+ if (mode < IComposerClient::PowerMode::OFF ||
+ mode > IComposerClient::PowerMode::DOZE_SUSPEND) {
+ return Error::BAD_PARAMETER;
+ }
+
+ if (!dozeSupported && (mode == IComposerClient::PowerMode::DOZE ||
+ mode == IComposerClient::PowerMode::DOZE_SUSPEND)) {
+ return Error::UNSUPPORTED;
+ }
+
+ display_ptr->set_power_mode(mode);
+ return Error::NONE;
+}
+
+Error VrHwc::setLayerFloatColor(Display display, Layer layer,
+ IComposerClient::FloatColor color) {
+ return Error::NONE;
+}
+
+Error VrHwc::getRenderIntents(Display display, types::V1_1::ColorMode mode,
+ std::vector<RenderIntent>* outIntents) {
+ return Error::NONE;
+}
+
+std::array<float, 16> VrHwc::getDataspaceSaturationMatrix(
+ types::V1_1::Dataspace dataspace) {
+ return {};
+}
+
+// composer::V2_3::ComposerHal
+Error VrHwc::getHdrCapabilities_2_3(Display /*display*/,
+ hidl_vec<Hdr>* /*outTypes*/,
+ float* outMaxLuminance,
+ float* outMaxAverageLuminance,
+ float* outMinLuminance) {
+ *outMaxLuminance = 0;
+ *outMaxAverageLuminance = 0;
+ *outMinLuminance = 0;
+ return Error::NONE;
+}
+
+Error VrHwc::setLayerPerFrameMetadata_2_3(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadata>& metadata) {
+ return Error::NONE;
+}
+
+Error VrHwc::getPerFrameMetadataKeys_2_3(
+ Display display,
+ std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
+ return Error::NONE;
+}
+
+Error VrHwc::setColorMode_2_3(Display display, ColorMode mode,
+ RenderIntent intent) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
+
+ if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3)
+ return Error::BAD_PARAMETER;
+
+ display_ptr->set_color_mode(mode);
+ return Error::NONE;
+}
+
+Error VrHwc::getRenderIntents_2_3(Display display, ColorMode mode,
+ std::vector<RenderIntent>* outIntents) {
+ return Error::NONE;
+}
+
+Error VrHwc::getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) {
+ return Error::NONE;
+}
+
+Error VrHwc::getClientTargetSupport_2_3(Display display, uint32_t width,
+ uint32_t height, PixelFormat format,
+ Dataspace dataspace) {
+ return Error::NONE;
+}
+
+Error VrHwc::getReadbackBufferAttributes_2_3(Display display,
+ PixelFormat* outFormat,
+ Dataspace* outDataspace) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) {
+ int error = 0;
+ auto display_client = display::DisplayClient::Create(&error);
+ if (!display_client) {
+ ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+ error);
+ return Error::BAD_CONFIG;
+ }
+ auto edid_data = display_client->GetConfigurationData(
+ display::ConfigFileType::kDeviceEdid);
+ auto display_identification_port =
+ display_client->GetDisplayIdentificationPort();
+ *outPort = display_identification_port.get();
+
+ std::copy(edid_data.get().begin(), edid_data.get().end(),
+ std::back_inserter(*outData));
+ return Error::NONE;
+}
+
+Error VrHwc::setLayerColorTransform(Display display, Layer layer,
+ const float* matrix) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayedContentSamplingAttributes(
+ Display display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
+ return Error::NONE;
+}
+
+Error VrHwc::setDisplayedContentSamplingEnabled(
+ Display display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayedContentSample(Display display, uint64_t maxFrames,
+ uint64_t timestamp, uint64_t& frameCount,
+ hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayCapabilities(
+ Display display,
+ std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
+ return Error::NONE;
+}
+
+Error VrHwc::setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayBrightnessSupport(Display display, bool* outSupport) {
+ return Error::NONE;
+}
+
+Error VrHwc::setDisplayBrightness(Display display, float brightness) {
+ return Error::NONE;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index 15358c5..3e3a630 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -17,9 +17,9 @@
#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H
#include <android-base/unique_fd.h>
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
-#include <composer-hal/2.1/ComposerHal.h>
+#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <composer-hal/2.3/ComposerHal.h>
#include <private/dvr/vsync_service.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -28,15 +28,21 @@
#include <mutex>
#include <unordered_map>
-using namespace android::frameworks::vr::composer::V1_0;
+using namespace android::frameworks::vr::composer::V2_0;
using namespace android::hardware::graphics::common::V1_0;
-using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_3;
+using android::hardware::hidl_bitfield;
using android::hardware::hidl_handle;
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::Void;
+using android::hardware::graphics::composer::V2_1::Config;
+using android::hardware::graphics::composer::V2_1::Display;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_3::IComposerClient;
namespace android {
@@ -46,16 +52,23 @@
class VrComposerClient;
-using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::hardware::graphics::composer::V2_1::hal::ComposerHal;
+using android::hardware::graphics::composer::V2_3::hal::ComposerHal;
+
+namespace types = android::hardware::graphics::common;
+
+using types::V1_1::RenderIntent;
+using types::V1_2::ColorMode;
+using types::V1_2::Dataspace;
+using types::V1_2::Hdr;
+using types::V1_2::PixelFormat;
class ComposerView {
public:
struct ComposerLayer {
- using Recti = hardware::graphics::composer::V2_1::IComposerClient::Rect;
- using Rectf = hardware::graphics::composer::V2_1::IComposerClient::FRect;
+ using Recti = hardware::graphics::composer::V2_3::IComposerClient::Rect;
+ using Rectf = hardware::graphics::composer::V2_3::IComposerClient::FRect;
using BlendMode =
- hardware::graphics::composer::V2_1::IComposerClient::BlendMode;
+ hardware::graphics::composer::V2_3::IComposerClient::BlendMode;
Layer id;
sp<GraphicBuffer> buffer;
@@ -111,7 +124,7 @@
struct HwcLayer {
using Composition =
- hardware::graphics::composer::V2_1::IComposerClient::Composition;
+ hardware::graphics::composer::V2_3::IComposerClient::Composition;
explicit HwcLayer(Layer new_id) { info.id = new_id; }
@@ -205,90 +218,148 @@
Display display, Layer layer,
const IVrComposerClient::BufferMetadata& metadata);
- // ComposerHal
+ // composer::V2_1::ComposerHal
bool hasCapability(hwc2_capability_t capability) override;
std::string dumpDebugInfo() override { return {}; }
- void registerEventCallback(EventCallback* callback) override;
+
+ void registerEventCallback(ComposerHal::EventCallback* callback) override;
void unregisterEventCallback() override;
uint32_t getMaxVirtualDisplayCount() override;
- Error createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat* format, Display* outDisplay) override;
Error destroyVirtualDisplay(Display display) override;
Error createLayer(Display display, Layer* outLayer) override;
Error destroyLayer(Display display, Layer layer) override;
Error getActiveConfig(Display display, Config* outConfig) override;
- Error getClientTargetSupport(Display display,
- uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace) override;
- Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override;
Error getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute, int32_t* outValue) override;
+ IComposerClient::Attribute attribute,
+ int32_t* outValue) override;
Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
Error getDisplayName(Display display, hidl_string* outName) override;
Error getDisplayType(Display display,
- IComposerClient::DisplayType* outType) override;
+ IComposerClient::DisplayType* outType) override;
Error getDozeSupport(Display display, bool* outSupport) override;
- Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
- float* outMaxLuminance, float* outMaxAverageLuminance,
- float* outMinLuminance) override;
Error setActiveConfig(Display display, Config config) override;
- Error setColorMode(Display display, ColorMode mode) override;
- Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
Error setColorTransform(Display display, const float* matrix,
- int32_t hint) override;
+ int32_t hint) override;
Error setClientTarget(Display display, buffer_handle_t target,
- int32_t acquireFence, int32_t dataspace,
- const std::vector<hwc_rect_t>& damage) override;
+ int32_t acquireFence, int32_t dataspace,
+ const std::vector<hwc_rect_t>& damage) override;
Error setOutputBuffer(Display display, buffer_handle_t buffer,
- int32_t releaseFence) override;
- Error validateDisplay(Display display,
- std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks) override;
+ int32_t releaseFence) override;
+ Error validateDisplay(
+ Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks) override;
Error acceptDisplayChanges(Display display) override;
Error presentDisplay(Display display, int32_t* outPresentFence,
- std::vector<Layer>* outLayers,
- std::vector<int32_t>* outReleaseFences) override;
+ std::vector<Layer>* outLayers,
+ std::vector<int32_t>* outReleaseFences) override;
- Error setLayerCursorPosition(Display display, Layer layer,
- int32_t x, int32_t y) override;
- Error setLayerBuffer(Display display, Layer layer,
- buffer_handle_t buffer, int32_t acquireFence) override;
+ Error setLayerCursorPosition(Display display, Layer layer, int32_t x,
+ int32_t y) override;
+ Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+ int32_t acquireFence) override;
Error setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage) override;
+ const std::vector<hwc_rect_t>& damage) override;
Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
Error setLayerColor(Display display, Layer layer,
- IComposerClient::Color color) override;
+ IComposerClient::Color color) override;
Error setLayerCompositionType(Display display, Layer layer,
- int32_t type) override;
+ int32_t type) override;
Error setLayerDataspace(Display display, Layer layer,
- int32_t dataspace) override;
+ int32_t dataspace) override;
Error setLayerDisplayFrame(Display display, Layer layer,
- const hwc_rect_t& frame) override;
+ const hwc_rect_t& frame) override;
Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
Error setLayerSidebandStream(Display display, Layer layer,
- buffer_handle_t stream) override;
+ buffer_handle_t stream) override;
Error setLayerSourceCrop(Display display, Layer layer,
- const hwc_frect_t& crop) override;
+ const hwc_frect_t& crop) override;
Error setLayerTransform(Display display, Layer layer,
- int32_t transform) override;
+ int32_t transform) override;
Error setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible) override;
+ const std::vector<hwc_rect_t>& visible) override;
Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+ // composer::V2_2::ComposerHal
+ Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
+ android::base::unique_fd fenceFd) override;
+ Error getReadbackBufferFence(Display display,
+ android::base::unique_fd* outFenceFd) override;
+ Error createVirtualDisplay_2_2(uint32_t width, uint32_t height,
+ types::V1_1::PixelFormat* format,
+ Display* outDisplay) override;
+ Error setPowerMode_2_2(Display display,
+ IComposerClient::PowerMode mode) override;
+ Error setLayerFloatColor(Display display, Layer layer,
+ IComposerClient::FloatColor color) override;
+ Error getRenderIntents(Display display, types::V1_1::ColorMode mode,
+ std::vector<RenderIntent>* outIntents) override;
+ std::array<float, 16> getDataspaceSaturationMatrix(
+ types::V1_1::Dataspace dataspace) override;
+
+ // composer::V2_3::ComposerHal
+ Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes,
+ float* outMaxLuminance,
+ float* outMaxAverageLuminance,
+ float* outMinLuminance) override;
+ Error setLayerPerFrameMetadata_2_3(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadata>& metadata) override;
+ Error getPerFrameMetadataKeys_2_3(
+ Display display,
+ std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override;
+ Error setColorMode_2_3(Display display, ColorMode mode,
+ RenderIntent intent) override;
+ Error getRenderIntents_2_3(Display display, ColorMode mode,
+ std::vector<RenderIntent>* outIntents) override;
+ Error getColorModes_2_3(Display display,
+ hidl_vec<ColorMode>* outModes) override;
+ Error getClientTargetSupport_2_3(Display display, uint32_t width,
+ uint32_t height, PixelFormat format,
+ Dataspace dataspace) override;
+ Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace) override;
+ Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) override;
+ Error setLayerColorTransform(Display display, Layer layer,
+ const float* matrix) override;
+ Error getDisplayedContentSamplingAttributes(
+ Display display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask)
+ override;
+ Error setDisplayedContentSamplingEnabled(
+ Display display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) override;
+ Error getDisplayedContentSample(
+ Display display, uint64_t maxFrames, uint64_t timestamp,
+ uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) override;
+ Error getDisplayCapabilities(Display display,
+ std::vector<IComposerClient::DisplayCapability>*
+ outCapabilities) override;
+ Error setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) override;
+ Error getDisplayBrightnessSupport(Display display, bool* outSupport) override;
+ Error setDisplayBrightness(Display display, float brightness) override;
+
// IComposer:
Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
Return<void> createClient(createClient_cb hidl_cb) override;
+ Return<void> createClient_2_3(
+ IComposer::createClient_2_3_cb hidl_cb) override;
// ComposerView:
void ForceDisplaysRefresh() override;