Merge branch 'dev/11/fp3/security-aosp-rvc-release' into int/11/fp3
* dev/11/fp3/security-aosp-rvc-release:
Add removeInstanceForPackageMethod to SensorManager
Remove some new memory leaks from SensorManager
Check for malformed Sensor Flattenable
Change-Id: Id873c4e1808ce47981aa38a63ead30e2c16f553b
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index a427c8d..8a7504f 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -427,7 +427,7 @@
<< strerror(errno) << std::endl;
status = -errno;
break;
- } else if (rc == 0) {
+ } else if (rc == 0 || time_left_ms() == 0) {
status = TIMED_OUT;
break;
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b9c1add..01eb3fe 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -940,6 +940,33 @@
auto scope_guard = android::base::make_scope_guard(deleter);
+ if (storageFlags & FLAG_STORAGE_DE) {
+ auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
+ auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
+ auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
+ snapshotId, package_name);
+
+ int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+ if (rc != 0) {
+ return error(rc, "Failed to create folder " + to);
+ }
+
+ rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+ if (rc != 0) {
+ return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+ }
+
+ // Check if we have data to copy.
+ if (access(from.c_str(), F_OK) == 0) {
+ rc = copy_directory_recursive(from.c_str(), to.c_str());
+ }
+ if (rc != 0) {
+ res = error(rc, "Failed copying " + from + " to " + to);
+ clear_de_on_exit = true;
+ return res;
+ }
+ }
+
// The app may not have any data at all, in which case it's OK to skip here.
auto from_ce = create_data_user_ce_package_path(volume_uuid, user, package_name);
if (access(from_ce.c_str(), F_OK) != 0) {
@@ -965,30 +992,6 @@
LOG(WARNING) << "Failed to clear code_cache of app " << packageName;
}
- if (storageFlags & FLAG_STORAGE_DE) {
- auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
- auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
- auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
- snapshotId, package_name);
-
- int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
- if (rc != 0) {
- return error(rc, "Failed to create folder " + to);
- }
-
- rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
- if (rc != 0) {
- return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
- }
-
- rc = copy_directory_recursive(from.c_str(), to.c_str());
- if (rc != 0) {
- res = error(rc, "Failed copying " + from + " to " + to);
- clear_de_on_exit = true;
- return res;
- }
- }
-
if (storageFlags & FLAG_STORAGE_CE) {
auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
index e080291..6027139 100644
--- a/cmds/installd/QuotaUtils.cpp
+++ b/cmds/installd/QuotaUtils.cpp
@@ -35,7 +35,7 @@
/* Map of all quota mounts from target to source */
std::unordered_map<std::string, std::string> mQuotaReverseMounts;
-std::string& FindQuotaDeviceForUuid(const std::string& uuid) {
+std::string FindQuotaDeviceForUuid(const std::string& uuid) {
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str());
return mQuotaReverseMounts[path];
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 1f9892a..e80c321 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -213,17 +213,18 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- auto entry = mNameToService.emplace(name, Service {
+ // Overwrite the old service if it exists
+ mNameToService[name] = Service {
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
.debugPid = ctx.debugPid,
- });
+ };
auto it = mNameToRegistrationCallback.find(name);
if (it != mNameToRegistrationCallback.end()) {
for (const sp<IServiceCallback>& cb : it->second) {
- entry.first->second.guaranteeClient = true;
+ mNameToService[name].guaranteeClient = true;
// permission checked in registerForNotifications
cb->onRegistration(name, binder);
}
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 25245be..fb9f9df 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -135,6 +135,26 @@
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
}
+TEST(AddService, OverwriteExistingService) {
+ auto sm = getPermissiveServiceManager();
+ sp<IBinder> serviceA = getBinder();
+ EXPECT_TRUE(sm->addService("foo", serviceA, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ sp<IBinder> outA;
+ EXPECT_TRUE(sm->getService("foo", &outA).isOk());
+ EXPECT_EQ(serviceA, outA);
+
+ // serviceA should be overwritten by serviceB
+ sp<IBinder> serviceB = getBinder();
+ EXPECT_TRUE(sm->addService("foo", serviceB, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ sp<IBinder> outB;
+ EXPECT_TRUE(sm->getService("foo", &outB).isOk());
+ EXPECT_EQ(serviceB, outB);
+}
+
TEST(AddService, NoPermissions) {
std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 50f117d..6ffb947 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -38,7 +38,6 @@
<!-- basic system services -->
<feature name="android.software.connectionservice" />
<feature name="android.software.voice_recognizers" notLowRam="true" />
- <feature name="android.software.backup" />
<feature name="android.software.home_screen" />
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 7ca9031..f5324d1 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -367,7 +367,8 @@
* Other errors probably indicate that the channel is broken.
*/
status_t consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime,
- uint32_t* outSeq, InputEvent** outEvent);
+ uint32_t* outSeq, InputEvent** outEvent,
+ int* motionEventType, int* touchMoveNumber, bool* flag);
/* Sends a finished signal to the publisher to inform it that the message
* with the specified sequence number has finished being process and whether
@@ -412,6 +413,8 @@
int32_t getPendingBatchSource() const;
private:
+ int mTouchMoveCounter = 0;
+
// True if touch resampling is enabled.
const bool mResampleTouch;
@@ -529,7 +532,9 @@
Vector<SeqChain> mSeqChains;
status_t consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
+ int* touchMoveNumber);
+
status_t consumeSamples(InputEventFactoryInterface* factory,
Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 258a4e3..80aa891 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -22,6 +22,8 @@
cc_library_headers {
name: "libarect_headers",
+ // TODO(b/153609531): remove when no longer needed.
+ native_bridge_supported: true,
export_include_dirs: ["include"],
}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index e0fb543..6ca3b16 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -24,6 +24,7 @@
#include <binder/IShellCallback.h>
#include <binder/Parcel.h>
+#include <linux/sched.h>
#include <stdio.h>
namespace android {
@@ -133,6 +134,8 @@
// unlocked objects
bool mRequestingSid = false;
sp<IBinder> mExtension;
+ int mPolicy = SCHED_NORMAL;
+ int mPriority = 0;
// for below objects
Mutex mLock;
@@ -279,6 +282,47 @@
return e->mExtension;
}
+void BBinder::setMinSchedulerPolicy(int policy, int priority) {
+ switch (policy) {
+ case SCHED_NORMAL:
+ LOG_ALWAYS_FATAL_IF(priority < -20 || priority > 19, "Invalid priority for SCHED_NORMAL: %d", priority);
+ break;
+ case SCHED_RR:
+ case SCHED_FIFO:
+ LOG_ALWAYS_FATAL_IF(priority < 1 || priority > 99, "Invalid priority for sched %d: %d", policy, priority);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unrecognized scheduling policy: %d", policy);
+ }
+
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ if (e == nullptr) {
+ // Avoid allocations if called with default.
+ if (policy == SCHED_NORMAL && priority == 0) {
+ return;
+ }
+
+ e = getOrCreateExtras();
+ if (!e) return; // out of memory
+ }
+
+ e->mPolicy = policy;
+ e->mPriority = priority;
+}
+
+int BBinder::getMinSchedulerPolicy() {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+ if (e == nullptr) return SCHED_NORMAL;
+ return e->mPolicy;
+}
+
+int BBinder::getMinSchedulerPriority() {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+ if (e == nullptr) return 0;
+ return e->mPriority;
+}
+
pid_t BBinder::getDebugPid() {
return getpid();
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index d67ce15..847b73a 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -860,6 +860,10 @@
err = FAILED_TRANSACTION;
goto finish;
+ case BR_FROZEN_REPLY:
+ err = FAILED_TRANSACTION;
+ goto finish;
+
case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
@@ -1316,6 +1320,42 @@
}
}
+status_t IPCThreadState::getProcessFreezeInfo(pid_t pid, bool *sync_received, bool *async_received)
+{
+ int ret = 0;
+ binder_frozen_status_info info;
+ info.pid = pid;
+
+#if defined(__ANDROID__)
+ if (ioctl(self()->mProcess->mDriverFD, BINDER_GET_FROZEN_INFO, &info) < 0)
+ ret = -errno;
+#endif
+ *sync_received = info.sync_recv;
+ *async_received = info.async_recv;
+
+ return ret;
+}
+
+status_t IPCThreadState::freeze(pid_t pid, bool enable, uint32_t timeout_ms) {
+ struct binder_freeze_info info;
+ int ret = 0;
+
+ info.pid = pid;
+ info.enable = enable;
+ info.timeout_ms = timeout_ms;
+
+
+#if defined(__ANDROID__)
+ if (ioctl(self()->mProcess->mDriverFD, BINDER_FREEZE, &info) < 0)
+ ret = -errno;
+#endif
+
+ //
+ // ret==-EAGAIN indicates that transactions have not drained.
+ // Call again to poll for completion.
+ //
+ return ret;
+}
void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data,
size_t /*dataSize*/,
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index efcc042..f790b88 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <linux/sched.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
@@ -188,16 +189,18 @@
return OK;
}
+static constexpr inline int schedPolicyMask(int policy, int priority) {
+ return (priority & FLAT_BINDER_FLAG_PRIORITY_MASK) | ((policy & 3) << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT);
+}
+
status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
flat_binder_object obj;
+ obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
- /* minimum priority for all nodes is nice 0 */
- obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
- } else {
- /* minimum priority for all nodes is MAX_NICE(19) */
- obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ int schedBits = 0;
+ if (!IPCThreadState::self()->backgroundSchedulingDisabled()) {
+ schedBits = schedPolicyMask(SCHED_NORMAL, 19);
}
if (binder != nullptr) {
@@ -213,6 +216,13 @@
obj.handle = handle;
obj.cookie = 0;
} else {
+ int policy = local->getMinSchedulerPolicy();
+ int priority = local->getMinSchedulerPriority();
+
+ if (policy != 0 || priority != 0) {
+ // override value, since it is set explicitly
+ schedBits = schedPolicyMask(policy, priority);
+ }
if (local->isRequestingSid()) {
obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
}
@@ -226,6 +236,8 @@
obj.cookie = 0;
}
+ obj.flags |= schedBits;
+
return finishFlattenBinder(binder, obj);
}
@@ -2468,7 +2480,7 @@
releaseObjects();
- if (data) {
+ if (data || desired == 0) {
LOG_ALLOC("Parcel %p: restart from %zu to %zu capacity", this, mDataCapacity, desired);
pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
gParcelGlobalAllocSize += desired;
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 6afcd77..d93935a 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -131,7 +131,11 @@
OP_DEPRECATED_1 = 96,
OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97,
OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98,
- _NUM_OP = 99
+ OP_NO_ISOLATED_STORAGE = 99,
+ OP_PHONE_CALL_MICROPHONE = 100,
+ OP_PHONE_CALL_CAMERA = 101,
+ OP_RECORD_AUDIO_HOTWORD = 102,
+ _NUM_OP = 103
};
AppOpsManager();
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 74e52db..4cf0515 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -72,6 +72,25 @@
// This must be called before the object is sent to another process. Not thread safe.
void setExtension(const sp<IBinder>& extension);
+ // This must be called before the object is sent to another process. Not thread safe.
+ //
+ // This function will abort if improper parameters are set. This is like
+ // sched_setscheduler. However, it sets the minimum scheduling policy
+ // only for the duration that this specific binder object is handling the
+ // call in a threadpool. By default, this API is set to SCHED_NORMAL/0. In
+ // this case, the scheduling priority will not actually be modified from
+ // binder defaults. See also IPCThreadState::disableBackgroundScheduling.
+ //
+ // Appropriate values are:
+ // SCHED_NORMAL: -20 <= priority <= 19
+ // SCHED_RR/SCHED_FIFO: 1 <= priority <= 99
+ __attribute__((weak))
+ void setMinSchedulerPolicy(int policy, int priority);
+ __attribute__((weak))
+ int getMinSchedulerPolicy();
+ __attribute__((weak))
+ int getMinSchedulerPriority();
+
pid_t getDebugPid();
protected:
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 4818889..8ac7165 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -34,7 +34,26 @@
public:
static IPCThreadState* self();
static IPCThreadState* selfOrNull(); // self(), but won't instantiate
-
+
+ // Freeze or unfreeze the binder interface to a specific process. When freezing, this method
+ // will block up to timeout_ms to process pending transactions directed to pid. Unfreeze
+ // is immediate. Transactions to processes frozen via this method won't be delivered and the
+ // driver will return BR_FROZEN_REPLY to the client sending them. After unfreeze,
+ // transactions will be delivered normally.
+ //
+ // pid: id for the process for which the binder interface is to be frozen
+ // enable: freeze (true) or unfreeze (false)
+ // timeout_ms: maximum time this function is allowed to block the caller waiting for pending
+ // binder transactions to be processed.
+ //
+ // returns: 0 in case of success, a value < 0 in case of error
+ __attribute__((weak))
+ static status_t freeze(pid_t pid, bool enabled, uint32_t timeout_ms);
+
+ // Provide information about the state of a frozen process
+ __attribute__((weak))
+ static status_t getProcessFreezeInfo(pid_t pid, bool *sync_received,
+ bool *async_received);
sp<ProcessState> process();
status_t clearLastError();
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index c22be9f..7be8f7b 100644
--- a/libs/binder/include/private/binder/binder_module.h
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -36,6 +36,60 @@
#include <sys/ioctl.h>
#include <linux/android/binder.h>
+#ifndef BR_FROZEN_REPLY
+// Temporary definition of BR_FROZEN_REPLY. For production
+// this will come from UAPI binder.h
+#define BR_FROZEN_REPLY _IO('r', 18)
+#endif //BR_FROZEN_REPLY
+
+#ifndef BINDER_FREEZE
+/*
+ * Temporary definitions for freeze support. For the final version
+ * these will be defined in the UAPI binder.h file from upstream kernel.
+ */
+#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info)
+
+struct binder_freeze_info {
+ //
+ // Group-leader PID of process to be frozen
+ //
+ uint32_t pid;
+ //
+ // Enable(1) / Disable(0) freeze for given PID
+ //
+ uint32_t enable;
+ //
+ // Timeout to wait for transactions to drain.
+ // 0: don't wait (ioctl will return EAGAIN if not drained)
+ // N: number of ms to wait
+ uint32_t timeout_ms;
+};
+#endif //BINDER_FREEZE
+
+#ifndef BINDER_GET_FROZEN_INFO
+
+#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info)
+
+struct binder_frozen_status_info {
+ //
+ // Group-leader PID of process to be queried
+ //
+ __u32 pid;
+ //
+ // Indicates whether the process has received any sync calls since last
+ // freeze (cleared at freeze/unfreeze)
+ //
+ __u32 sync_recv;
+ //
+ // Indicates whether the process has received any async calls since last
+ // freeze (cleared at freeze/unfreeze)
+ //
+ __u32 async_recv;
+};
+#endif //BINDER_GET_FROZEN_INFO
+
+
+
#ifdef __cplusplus
} // namespace android
#endif
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index b37b688..9caad45 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -16,6 +16,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <fstream>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
@@ -50,6 +51,9 @@
static char *binderserversuffix;
static char binderserverarg[] = "--binderserver";
+static constexpr int kSchedPolicy = SCHED_RR;
+static constexpr int kSchedPriority = 7;
+
static String16 binderLibTestServiceName = String16("test.binderLib");
enum BinderLibTestTranscationCode {
@@ -75,6 +79,9 @@
BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION,
+ BINDER_LIB_TEST_GET_SCHEDULING_POLICY,
+ BINDER_LIB_TEST_NOP_TRANSACTION_WAIT,
+ BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_ECHO_VECTOR,
BINDER_LIB_TEST_REJECT_OBJECTS,
};
@@ -395,6 +402,49 @@
EXPECT_EQ(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, Freeze) {
+ status_t ret;
+ Parcel data, reply, replypid;
+ std::ifstream freezer_file("/sys/fs/cgroup/freezer/cgroup.freeze");
+
+ //Pass test on devices where the freezer is not supported
+ if (freezer_file.fail()) {
+ GTEST_SKIP();
+ return;
+ }
+
+ std::string freezer_enabled;
+ std::getline(freezer_file, freezer_enabled);
+
+ //Pass test on devices where the freezer is disabled
+ if (freezer_enabled != "1") {
+ GTEST_SKIP();
+ return;
+ }
+
+ ret = m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid);
+ int32_t pid = replypid.readInt32();
+ EXPECT_EQ(NO_ERROR, ret);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY));
+ }
+ EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
+ EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 1, 1000));
+ EXPECT_EQ(FAILED_TRANSACTION, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
+
+ bool sync_received, async_received;
+
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->getProcessFreezeInfo(pid, &sync_received,
+ &async_received));
+
+ EXPECT_EQ(sync_received, 1);
+ EXPECT_EQ(async_received, 0);
+
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 0, 0));
+ EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
+}
+
TEST_F(BinderLibTest, SetError) {
int32_t testValue[] = { 0, -123, 123 };
for (size_t i = 0; i < ARRAY_SIZE(testValue); i++) {
@@ -1015,6 +1065,22 @@
EXPECT_EQ(NO_ERROR, ret2);
}
+TEST_F(BinderLibTest, SchedPolicySet) {
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+
+ Parcel data, reply;
+ status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
+ EXPECT_EQ(NO_ERROR, ret);
+
+ int policy = reply.readInt32();
+ int priority = reply.readInt32();
+
+ EXPECT_EQ(kSchedPolicy, policy & (~SCHED_RESET_ON_FORK));
+ EXPECT_EQ(kSchedPriority, priority);
+}
+
+
TEST_F(BinderLibTest, VectorSent) {
Parcel data, reply;
sp<IBinder> server = addServer();
@@ -1197,6 +1263,12 @@
pthread_mutex_unlock(&m_serverWaitMutex);
return ret;
}
+ case BINDER_LIB_TEST_GETPID:
+ reply->writeInt32(getpid());
+ return NO_ERROR;
+ case BINDER_LIB_TEST_NOP_TRANSACTION_WAIT:
+ usleep(5000);
+ return NO_ERROR;
case BINDER_LIB_TEST_NOP_TRANSACTION:
return NO_ERROR;
case BINDER_LIB_TEST_DELAYED_CALL_BACK: {
@@ -1371,6 +1443,16 @@
reply->writeInt32(IPCThreadState::self()->getCallingWorkSourceUid());
return NO_ERROR;
}
+ case BINDER_LIB_TEST_GET_SCHEDULING_POLICY: {
+ int policy = 0;
+ sched_param param;
+ if (0 != pthread_getschedparam(pthread_self(), &policy, ¶m)) {
+ return UNKNOWN_ERROR;
+ }
+ reply->writeInt32(policy);
+ reply->writeInt32(param.sched_priority);
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_ECHO_VECTOR: {
std::vector<uint64_t> vector;
auto err = data.readUint64Vector(&vector);
@@ -1407,6 +1489,8 @@
{
sp<BinderLibTestService> testService = new BinderLibTestService(index);
+ testService->setMinSchedulerPolicy(kSchedPolicy, kSchedPriority);
+
/*
* Normally would also contain functionality as well, but we are only
* testing the extension mechanism.
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 6ec1f47..516b080 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -38,12 +38,8 @@
],
}
-cc_library_shared {
- name: "libgui",
- vendor_available: false,
- vndk: {
- enabled: true,
- },
+cc_defaults {
+ name: "libgui_defaults",
double_loadable: true,
defaults: ["libgui_bufferqueue-defaults"],
@@ -273,4 +269,19 @@
],
}
+cc_library_shared {
+ name: "libgui",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ defaults: ["libgui_defaults"]
+}
+
+cc_library_shared {
+ name: "libgui_vendor",
+ vendor: true,
+ defaults: ["libgui_defaults"]
+}
+
subdirs = ["tests"]
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index ef7a6f5..351af65 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -86,6 +86,10 @@
mReceiveFd = std::move(receiveFd);
}
+void BitTube::setSendFd(base::unique_fd&& sendFd) {
+ mSendFd = std::move(sendFd);
+}
+
ssize_t BitTube::write(void const* vaddr, size_t size) {
ssize_t err, len;
do {
@@ -115,6 +119,11 @@
status_t result = reply->writeDupFileDescriptor(mReceiveFd);
mReceiveFd.reset();
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply->writeDupFileDescriptor(mSendFd);
+ mSendFd.reset();
return result;
}
@@ -126,6 +135,13 @@
ALOGE("BitTube::readFromParcel: can't dup file descriptor (%s)", strerror(error));
return -error;
}
+ mSendFd.reset(dup(parcel->readFileDescriptor()));
+ if (mSendFd < 0) {
+ mSendFd.reset();
+ int error = errno;
+ ALOGE("BitTube::readFromParcel: can't dup file descriptor (%s)", strerror(error));
+ return -error;
+ }
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index da6143c..5e55d6b 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -17,6 +17,7 @@
#include <inttypes.h>
#include <pwd.h>
#include <sys/types.h>
+#include <cutils/properties.h>
#define LOG_TAG "BufferQueueConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -71,7 +72,9 @@
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
mCore(core),
mSlots(core->mSlots),
- mConsumerName() {}
+ mConsumerName() {
+ mPreRendering = property_get_bool("ro.vendor.perf.scroll_opt", false);
+}
BufferQueueConsumer::~BufferQueueConsumer() {}
@@ -136,7 +139,21 @@
// the timestamps are being auto-generated by Surface. If the app isn't
// generating timestamps explicitly, it probably doesn't want frames to
// be discarded based on them.
- while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+ while (mCore->mQueue.size() > 1 && (!mCore->mQueue[0].mIsAutoTimestamp
+ || mPreRendering)) {
+ if (mPreRendering) {
+ // pre-rendering feature is enabled
+ const BufferItem& latestItem(mCore->mQueue[mCore->mQueue.size()-1]);
+ if (!mCore->mQueue[0].mIsAutoTimestamp &&
+ latestItem.mIsAutoTimestamp) {
+ break;
+ }
+ if (mCore->mQueue[0].mIsAutoTimestamp &&
+ mCore->mQueue[1].mIsAutoTimestamp) {
+ break;
+ }
+ }
+
const BufferItem& bufferItem(mCore->mQueue[1]);
// If dropping entry[0] would leave us with a buffer that the
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index b33bc9e..682fe91 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -89,12 +89,8 @@
return OK;
}
-void DisplayEventDispatcher::requestLatestConfig() {
- status_t status = mReceiver.requestLatestConfig();
- if (status) {
- ALOGW("Failed enable config events, status=%d", status);
- return;
- }
+void DisplayEventDispatcher::injectEvent(const DisplayEventReceiver::Event& event) {
+ mReceiver.sendEvents(&event, 1);
}
int DisplayEventDispatcher::getFd() const {
@@ -157,6 +153,9 @@
dispatchConfigChanged(ev.header.timestamp, ev.header.displayId,
ev.config.configId, ev.config.vsyncPeriod);
break;
+ case DisplayEventReceiver::DISPLAY_EVENT_NULL:
+ dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
+ break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
break;
@@ -168,4 +167,5 @@
}
return gotVsync;
}
+
} // namespace android
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 1fed509..f2b0962 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -79,14 +79,6 @@
return NO_INIT;
}
-status_t DisplayEventReceiver::requestLatestConfig() {
- if (mEventConnection != nullptr) {
- mEventConnection->requestLatestConfig();
- return NO_ERROR;
- }
- return NO_INIT;
-}
-
ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
size_t count) {
return DisplayEventReceiver::getEvents(mDataChannel.get(), events, count);
@@ -98,6 +90,10 @@
return gui::BitTube::recvObjects(dataChannel, events, count);
}
+ssize_t DisplayEventReceiver::sendEvents(Event const* events, size_t count) {
+ return DisplayEventReceiver::sendEvents(mDataChannel.get(), events, count);
+}
+
ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
Event const* events, size_t count)
{
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index e2ea3f9..b2a5f6b 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -382,6 +382,10 @@
newTimestamps.requestedPresentTime = newEntry.requestedPresentTime;
newTimestamps.acquireFence = newEntry.acquireFence;
newTimestamps.valid = true;
+ if (mQueueOffset >= MAX_FRAME_HISTORY) {
+ ALOGE_IF(mProducerWantsEvents, "addQueue: QueueOffset is out of bound");
+ return;
+ }
mFrames[mQueueOffset] = newTimestamps;
// Note: We avoid sending the acquire fence back to the caller since
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index aa74bfd..c0e246f 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -26,8 +26,7 @@
STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
SET_VSYNC_RATE,
REQUEST_NEXT_VSYNC,
- REQUEST_LATEST_CONFIG,
- LAST = REQUEST_LATEST_CONFIG,
+ LAST = REQUEST_NEXT_VSYNC,
};
} // Anonymous namespace
@@ -54,11 +53,6 @@
callRemoteAsync<decltype(&IDisplayEventConnection::requestNextVsync)>(
Tag::REQUEST_NEXT_VSYNC);
}
-
- void requestLatestConfig() override {
- callRemoteAsync<decltype(&IDisplayEventConnection::requestLatestConfig)>(
- Tag::REQUEST_LATEST_CONFIG);
- }
};
// Out-of-line virtual method definition to trigger vtable emission in this translation unit (see
@@ -80,8 +74,6 @@
return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
case Tag::REQUEST_NEXT_VSYNC:
return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
- case Tag::REQUEST_LATEST_CONFIG:
- return callLocalAsync(data, reply, &IDisplayEventConnection::requestLatestConfig);
}
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index cf269b3..4477740 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -155,6 +155,16 @@
return mNextFrameNumber;
}
+bool Surface::isBufferAccumulated() const {
+ Mutex::Autolock lock(mMutex);
+ return mIsBufferAccumulated;
+}
+
+void Surface::setPresentTimeMode(int mode) {
+ Mutex::Autolock lock(mMutex);
+ mPresentTimeMode = mode;
+}
+
String8 Surface::getConsumerName() const {
return mGraphicBufferProducer->getConsumerName();
}
@@ -732,6 +742,8 @@
mSharedBufferHasBeenQueued = false;
}
+ mDequeuedSlots.insert(buf);
+
return OK;
}
@@ -760,6 +772,8 @@
mSharedBufferHasBeenQueued = true;
}
+ mDequeuedSlots.erase(i);
+
return OK;
}
@@ -895,6 +909,8 @@
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
+ mDequeuedSlots.erase(i);
+
if (mEnableFrameTimestamps) {
mFrameEventHistory->applyDelta(output.frameTimestamps);
// Update timestamps with the local acquire fence.
@@ -921,6 +937,7 @@
}
mConsumerRunningBehind = (output.numPendingBuffers >= 2);
+ mIsBufferAccumulated = mConsumerRunningBehind;
if (!mConnectedToCpu) {
// Clear surface damage back to full-buffer
@@ -970,6 +987,9 @@
{ // scope for the lock
Mutex::Autolock lock(mMutex);
switch (what) {
+ case NATIVE_WINDOW_PRESENT_TIME_MODE:
+ *value = mPresentTimeMode;
+ return NO_ERROR;
case NATIVE_WINDOW_FORMAT:
if (mReqFormat) {
*value = static_cast<int>(mReqFormat);
@@ -1660,6 +1680,7 @@
mRemovedBuffers.push_back(mSlots[attachedSlot].buffer);
}
mSlots[attachedSlot].buffer = graphicBuffer;
+ mDequeuedSlots.insert(attachedSlot);
return NO_ERROR;
}
@@ -1926,6 +1947,10 @@
}
void Surface::freeAllBuffers() {
+ if (!mDequeuedSlots.empty()) {
+ ALOGE("%s: %zu buffers were freed while being dequeued!",
+ __FUNCTION__, mDequeuedSlots.size());
+ }
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].buffer = nullptr;
}
@@ -1947,6 +1972,10 @@
ALOGW("%s: Discarded slot %d doesn't contain buffer!", __FUNCTION__, i);
continue;
}
+ // Don't flush currently dequeued buffers
+ if (mDequeuedSlots.count(i) > 0) {
+ continue;
+ }
outBuffers->push_back(mSlots[i].buffer);
mSlots[i].buffer = nullptr;
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index a332a1f..8f0ebc7 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -39,6 +39,8 @@
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
+#include "dlfcn.h"
+
namespace android {
// ============================================================================
@@ -195,6 +197,5 @@
handle.get(), interface_cast<IGraphicBufferProducer>(gbp),
transformHint);
}
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index 7db69ec..7fb5b8d 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -184,6 +184,9 @@
// It's updated during setConsumerName.
String8 mConsumerName;
+ // Value used to show whether pre-rendering feature is enabled or not
+ bool mPreRendering;
+
}; // class BufferQueueConsumer
} // namespace android
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index f210c34..eb5b004 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -31,7 +31,7 @@
status_t initialize();
void dispose();
status_t scheduleVsync();
- void requestLatestConfig();
+ void injectEvent(const DisplayEventReceiver::Event& event);
int getFd() const;
virtual int handleEvent(int receiveFd, int events, void* data);
@@ -48,6 +48,9 @@
bool connected) = 0;
virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
int32_t configId, nsecs_t vsyncPeriod) = 0;
+ // AChoreographer-specific hook for processing null-events so that looper
+ // can be properly poked.
+ virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
uint32_t* outCount);
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 8d49184..0e10d1a 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -53,6 +53,7 @@
DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'),
+ DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
};
struct Event {
@@ -130,6 +131,7 @@
* sendEvents write events to the queue and returns how many events were
* written.
*/
+ ssize_t sendEvents(Event const* events, size_t count);
static ssize_t sendEvents(gui::BitTube* dataChannel, Event const* events, size_t count);
/*
@@ -146,12 +148,6 @@
*/
status_t requestNextVsync();
- /*
- * requestLatestConfig() force-requests the current config for the primary
- * display.
- */
- status_t requestLatestConfig();
-
private:
sp<IDisplayEventConnection> mEventConnection;
std::unique_ptr<gui::BitTube> mDataChannel;
diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
index 674aafd..cff22a3 100644
--- a/libs/gui/include/gui/IDisplayEventConnection.h
+++ b/libs/gui/include/gui/IDisplayEventConnection.h
@@ -51,11 +51,6 @@
* requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
*/
virtual void requestNextVsync() = 0; // Asynchronous
-
- /*
- * requestLatestConfig() requests the config for the primary display.
- */
- virtual void requestLatestConfig() = 0; // Asynchronous
};
class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index d58e019..1132ec9 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -27,6 +27,7 @@
METADATA_WINDOW_TYPE = 2,
METADATA_TASK_ID = 3,
METADATA_MOUSE_CURSOR = 4,
+ METADATA_WINDOW_TYPE_DONT_SCREENSHOT = 5,
};
struct LayerMetadata : public Parcelable {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 49c83da..083f36c 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -30,6 +30,7 @@
#include <utils/RefBase.h>
#include <shared_mutex>
+#include <unordered_set>
namespace android {
@@ -132,6 +133,9 @@
// See IGraphicBufferProducer::getNextFrameNumber
uint64_t getNextFrameNumber() const;
+ bool isBufferAccumulated() const;
+ void setPresentTimeMode(int mode);
+
/* Set the scaling mode to be used with a Surface.
* See NATIVE_WINDOW_SET_SCALING_MODE and its parameters
* in <system/window.h>. */
@@ -530,6 +534,9 @@
uint64_t mNextFrameNumber = 1;
uint64_t mLastFrameNumber = 0;
+ bool mIsBufferAccumulated = false;
+ int mPresentTimeMode = -1;
+
// Mutable because ANativeWindow::query needs this class const.
mutable bool mQueriedSupportedTimestamps;
mutable bool mFrameTimestampsSupportsPresent;
@@ -543,8 +550,15 @@
int mMaxBufferCount;
sp<IProducerListener> mListenerProxy;
+
+ // Get and flush the buffers of given slots, if the buffer in the slot
+ // is currently dequeued then it won't be flushed and won't be returned
+ // in outBuffers.
status_t getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots,
std::vector<sp<GraphicBuffer>>* outBuffers);
+
+ // Buffers that are successfully dequeued/attached and handed to clients
+ std::unordered_set<int> mDequeuedSlots;
};
} // namespace android
diff --git a/libs/gui/include/private/gui/BitTube.h b/libs/gui/include/private/gui/BitTube.h
index 13c0162..8048518 100644
--- a/libs/gui/include/private/gui/BitTube.h
+++ b/libs/gui/include/private/gui/BitTube.h
@@ -58,6 +58,9 @@
// resets this BitTube's receive file descriptor to receiveFd
void setReceiveFd(base::unique_fd&& receiveFd);
+ // resets this BitTube's send file descriptor to sendFd
+ void setSendFd(base::unique_fd&& sendFd);
+
// send objects (sized blobs). All objects are guaranteed to be written or the call fails.
template <typename T>
static ssize_t sendObjects(BitTube* tube, T const* events, size_t count) {
@@ -85,7 +88,7 @@
// the message, excess data is silently discarded.
ssize_t read(void* vaddr, size_t size);
- base::unique_fd mSendFd;
+ mutable base::unique_fd mSendFd;
mutable base::unique_fd mReceiveFd;
static ssize_t sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index e3f4798..8623bf7 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -152,7 +152,11 @@
InputEvent *ev;
uint32_t seqId;
- status_t consumed = mInputConsumer->consume(&mInputEventFactory, true, -1, &seqId, &ev);
+ int motionEventType;
+ int touchMoveNumber;
+ bool flag;
+ status_t consumed = mInputConsumer->consume(&mInputEventFactory, true, -1, &seqId, &ev,
+ &motionEventType, &touchMoveNumber, &flag);
if (consumed != OK) {
return nullptr;
}
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 11af23e..7b8dfb0 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -609,7 +609,8 @@
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
+ int* motionEventType, int* touchMoveNumber, bool* flag) {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
mChannel->getName().c_str(), toString(consumeBatches), frameTime);
@@ -628,10 +629,20 @@
} else {
// Receive a fresh message.
status_t result = mChannel->receiveMessage(&mMsg);
+ if (result == 0) {
+ if ((mMsg.body.motion.action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_MOVE){
+ mTouchMoveCounter++;
+ } else {
+ mTouchMoveCounter = 0;
+ }
+ *flag = true;
+ }
+ *motionEventType = mMsg.body.motion.action & AMOTION_EVENT_ACTION_MASK;
+ *touchMoveNumber = mTouchMoveCounter;
if (result) {
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
- result = consumeBatch(factory, frameTime, outSeq, outEvent);
+ result = consumeBatch(factory, frameTime, outSeq, outEvent, touchMoveNumber);
if (*outEvent) {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -748,7 +759,7 @@
}
status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int* touchMoveNumber) {
status_t result;
for (size_t i = mBatches.size(); i > 0; ) {
i--;
@@ -760,7 +771,7 @@
}
nsecs_t sampleTime = frameTime;
- if (mResampleTouch) {
+ if (mResampleTouch && (*touchMoveNumber != 1)) {
sampleTime -= RESAMPLE_LATENCY;
}
ssize_t split = findSampleNoLaterThan(batch, sampleTime);
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 8e2eec8..3f41b52 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -97,7 +97,11 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ int motionEventType;
+ int touchMoveNumber;
+ bool flag;
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+ &motionEventType, &touchMoveNumber, &flag);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -196,7 +200,11 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ int motionEventType;
+ int touchMoveNumber;
+ bool flag;
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+ &motionEventType, &touchMoveNumber, &flag);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -290,7 +298,11 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ int motionEventType;
+ int touchMoveNumber;
+ bool flag;
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+ &motionEventType, &touchMoveNumber, &flag);
ASSERT_EQ(OK, status) << "consumer consume should return OK";
ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index e458b2e..f6a95ce 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -136,6 +136,7 @@
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
nsecs_t vsyncPeriod) override;
+ void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override;
void scheduleCallbacks();
@@ -170,7 +171,7 @@
Choreographer::Choreographer(const sp<Looper>& looper)
: DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp,
- ISurfaceComposer::ConfigChanged::eConfigChangedDispatch),
+ ISurfaceComposer::ConfigChanged::eConfigChangedSuppress),
mLooper(looper),
mThreadId(std::this_thread::get_id()) {
std::lock_guard<std::mutex> _l(gChoreographers.lock);
@@ -294,8 +295,14 @@
} else {
// If the looper thread is detached from Choreographer, then refresh rate
// changes will be handled in AChoreographer_handlePendingEvents, so we
- // need to redispatch a config from SF
- requestLatestConfig();
+ // need to wake up the looper thread by writing to the write-end of the
+ // socket the looper is listening on.
+ // Fortunately, these events are small so sending packets across the
+ // socket should be atomic across processes.
+ DisplayEventReceiver::Event event;
+ event.header = DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
+ PhysicalDisplayId(0), systemTime()};
+ injectEvent(event);
}
}
@@ -374,28 +381,15 @@
// displays. When multi-display choreographer is properly supported, then
// PhysicalDisplayId should no longer be ignored.
void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, int32_t configId,
- nsecs_t vsyncPeriod) {
+ nsecs_t) {
ALOGV("choreographer %p ~ received config change event "
"(displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%d).",
this, displayId, configId);
+}
- const nsecs_t lastPeriod = mLatestVsyncPeriod;
- std::vector<RefreshRateCallback> callbacks{};
- {
- std::lock_guard<std::mutex> _l{mLock};
- for (auto& cb : mRefreshRateCallbacks) {
- callbacks.push_back(cb);
- cb.firstCallbackFired = true;
- }
- }
-
- for (auto& cb : callbacks) {
- if (!cb.firstCallbackFired || (vsyncPeriod > 0 && vsyncPeriod != lastPeriod)) {
- cb.callback(vsyncPeriod, cb.data);
- }
- }
-
- mLatestVsyncPeriod = vsyncPeriod;
+void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) {
+ ALOGV("choreographer %p ~ received null event.", this);
+ handleRefreshRateUpdates();
}
void Choreographer::handleMessage(const Message& message) {
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index b78fc5d..3644f24 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -63,6 +63,9 @@
/* attributes queriable with query() */
enum {
+ /* Get the mode whether to set present time when queueBuffer */
+ NATIVE_WINDOW_PRESENT_TIME_MODE = -1,
+
NATIVE_WINDOW_WIDTH = 0,
NATIVE_WINDOW_HEIGHT = 1,
NATIVE_WINDOW_FORMAT = 2,
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 92e7e71..0285c2f 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -409,6 +409,23 @@
mImageManager = std::make_unique<ImageManager>(this);
mImageManager->initThread();
mDrawingBuffer = createFramebuffer();
+ sp<GraphicBuffer> buf =
+ new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, "placeholder");
+
+ const status_t err = buf->initCheck();
+ if (err != OK) {
+ ALOGE("Error allocating placeholder buffer: %d", err);
+ return;
+ }
+ mPlaceholderBuffer = buf.get();
+ EGLint attributes[] = {
+ EGL_NONE,
+ };
+ mPlaceholderImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ mPlaceholderBuffer, attributes);
+ ALOGE_IF(mPlaceholderImage == EGL_NO_IMAGE_KHR, "Failed to create placeholder image: %#x",
+ eglGetError());
}
GLESRenderEngine::~GLESRenderEngine() {
@@ -423,6 +440,7 @@
eglDestroyImageKHR(mEGLDisplay, expired);
DEBUG_EGL_IMAGE_TRACKER_DESTROY();
}
+ eglDestroyImageKHR(mEGLDisplay, mPlaceholderImage);
mImageCache.clear();
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mEGLDisplay);
@@ -589,6 +607,9 @@
}
void GLESRenderEngine::deleteTextures(size_t count, uint32_t const* names) {
+ for (int i = 0; i < count; ++i) {
+ mTextureView.erase(names[i]);
+ }
glDeleteTextures(count, names);
}
@@ -646,6 +667,7 @@
}
bindExternalTextureImage(texName, *cachedImage->second);
+ mTextureView.insert_or_assign(texName, buffer->getId());
}
// Wait for the new buffer to be ready.
@@ -887,7 +909,7 @@
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
-bool GLESRenderEngine::cleanupPostRender() {
+bool GLESRenderEngine::cleanupPostRender(CleanupMode mode) {
ATRACE_CALL();
if (mPriorResourcesCleaned ||
@@ -896,6 +918,30 @@
return false;
}
+ // This is a bit of a band-aid fix for FrameCaptureProcessor, as we should
+ // not need to keep memory around if we don't need to do so.
+ if (mode == CleanupMode::CLEAN_ALL) {
+ // TODO: SurfaceFlinger memory utilization may benefit from resetting
+ // texture bindings as well. Assess if it does and there's no performance regression
+ // when rebinding the same image data to the same texture, and if so then its mode
+ // behavior can be tweaked.
+ if (mPlaceholderImage != EGL_NO_IMAGE_KHR) {
+ for (auto [textureName, bufferId] : mTextureView) {
+ if (bufferId && mPlaceholderImage != EGL_NO_IMAGE_KHR) {
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureName);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES,
+ static_cast<GLeglImageOES>(mPlaceholderImage));
+ mTextureView[textureName] = std::nullopt;
+ checkErrors();
+ }
+ }
+ }
+ {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ mImageCache.clear();
+ }
+ }
+
// Bind the texture to dummy data so that backing image data can be freed.
GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(getFramebufferForDrawing());
glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer);
@@ -1616,6 +1662,16 @@
return cachedImage != mImageCache.end();
}
+bool GLESRenderEngine::isTextureNameKnownForTesting(uint32_t texName) {
+ const auto& entry = mTextureView.find(texName);
+ return entry != mTextureView.end();
+}
+
+std::optional<uint64_t> GLESRenderEngine::getBufferIdForTextureNameForTesting(uint32_t texName) {
+ const auto& entry = mTextureView.find(texName);
+ return entry != mTextureView.end() ? entry->second : std::nullopt;
+}
+
bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) {
std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(),
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 42b8537..d5254a8 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -75,7 +75,7 @@
const std::vector<const LayerSettings*>& layers,
ANativeWindowBuffer* buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
- bool cleanupPostRender() override;
+ bool cleanupPostRender(CleanupMode mode) override;
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
// Creates an output image for rendering to
@@ -86,6 +86,12 @@
// Test-only methods
// Returns true iff mImageCache contains an image keyed by bufferId
bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex);
+ // Returns true iff texName was previously generated by RenderEngine and was
+ // not destroyed.
+ bool isTextureNameKnownForTesting(uint32_t texName);
+ // Returns the buffer ID of the content bound to texName, or nullopt if no
+ // such mapping exists.
+ std::optional<uint64_t> getBufferIdForTextureNameForTesting(uint32_t texName);
// Returns true iff mFramebufferImageCache contains an image keyed by bufferId
bool isFramebufferImageCachedForTesting(uint64_t bufferId)
EXCLUDES(mFramebufferImageCacheMutex);
@@ -224,6 +230,8 @@
// Cache of GL images that we'll store per GraphicBuffer ID
std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache GUARDED_BY(mRenderingMutex);
+ std::unordered_map<uint32_t, std::optional<uint64_t>> mTextureView;
+
// Mutex guarding rendering operations, so that:
// 1. GL operations aren't interleaved, and
// 2. Internal state related to rendering that is potentially modified by
@@ -237,6 +245,11 @@
// ensure that we align on a word. Allocating 16 bytes will provide a
// guarantee that we don't clobber memory.
uint32_t mPlaceholderDrawBuffer[4];
+ // Placeholder buffer and image, similar to mPlaceholderDrawBuffer, but
+ // instead these are intended for cleaning up texture memory with the
+ // GL_TEXTURE_EXTERNAL_OES target.
+ ANativeWindowBuffer* mPlaceholderBuffer = nullptr;
+ EGLImage mPlaceholderImage = EGL_NO_IMAGE_KHR;
sp<Fence> mLastDrawFence;
// Store a separate boolean checking if prior resources were cleaned up, as
// devices that don't support native sync fences can't rely on a last draw
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index e06e128..a111247 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -111,14 +111,25 @@
// Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
+
+ enum class CleanupMode {
+ CLEAN_OUTPUT_RESOURCES,
+ CLEAN_ALL,
+ };
// Clean-up method that should be called on the main thread after the
// drawFence returned by drawLayers fires. This method will free up
// resources used by the most recently drawn frame. If the frame is still
// being drawn, then this call is silently ignored.
//
+ // If mode is CLEAN_OUTPUT_RESOURCES, then only resources related to the
+ // output framebuffer are cleaned up, including the sibling texture.
+ //
+ // If mode is CLEAN_ALL, then we also cleanup resources related to any input
+ // buffers.
+ //
// Returns true if resources were cleaned up, and false if we didn't need to
// do any work.
- virtual bool cleanupPostRender() = 0;
+ virtual bool cleanupPostRender(CleanupMode mode = CleanupMode::CLEAN_OUTPUT_RESOURCES) = 0;
// queries
virtual size_t getMaxTextureSize() const = 0;
@@ -131,7 +142,7 @@
virtual bool isProtected() const = 0;
virtual bool supportsProtectedContent() const = 0;
virtual bool useProtectedContext(bool useProtectedContext) = 0;
-
+ virtual void setViewportAndProjection(Rect viewPort, Rect sourceCrop) =0;
// Renders layers for a particular display via GPU composition. This method
// should be called for every display that needs to be rendered via the GPU.
// @param display The display-wide settings that should be applied prior to
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index df0f17a..0a80170 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -56,7 +56,9 @@
MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
MOCK_METHOD1(useProtectedContext, bool(bool));
- MOCK_METHOD0(cleanupPostRender, bool());
+ MOCK_METHOD2(setViewportAndProjection,
+ void(Rect, Rect));
+ MOCK_METHOD1(cleanupPostRender, bool(CleanupMode mode));
MOCK_METHOD6(drawLayers,
status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 16a8a0d..f577eb3 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -81,6 +81,7 @@
}
for (uint32_t texName : mTexNames) {
sRE->deleteTextures(1, &texName);
+ EXPECT_FALSE(sRE->isTextureNameKnownForTesting(texName));
}
}
@@ -1424,10 +1425,44 @@
if (fd >= 0) {
sync_wait(fd, -1);
}
-
// Only cleanup the first time.
- EXPECT_TRUE(sRE->cleanupPostRender());
- EXPECT_FALSE(sRE->cleanupPostRender());
+ EXPECT_TRUE(sRE->cleanupPostRender(
+ renderengine::RenderEngine::CleanupMode::CLEAN_OUTPUT_RESOURCES));
+ EXPECT_FALSE(sRE->cleanupPostRender(
+ renderengine::RenderEngine::CleanupMode::CLEAN_OUTPUT_RESOURCES));
+}
+
+TEST_F(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory) {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<const renderengine::LayerSettings*> layers;
+ renderengine::LayerSettings layer;
+ layer.geometry.boundaries = fullscreenRect().toFloatRect();
+ BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+ layer.alpha = 1.0;
+ layers.push_back(&layer);
+
+ base::unique_fd fence;
+ sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true, base::unique_fd(), &fence);
+
+ const int fd = fence.get();
+ if (fd >= 0) {
+ sync_wait(fd, -1);
+ }
+
+ uint64_t bufferId = layer.source.buffer.buffer->getId();
+ uint32_t texName = layer.source.buffer.textureName;
+ EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
+ EXPECT_EQ(bufferId, sRE->getBufferIdForTextureNameForTesting(texName));
+
+ EXPECT_TRUE(sRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL));
+
+ // Now check that our view of memory is good.
+ EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+ EXPECT_EQ(std::nullopt, sRE->getBufferIdForTextureNameForTesting(bufferId));
+ EXPECT_TRUE(sRE->isTextureNameKnownForTesting(texName));
}
} // namespace android
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index 33ab7c4..2d3ef2e 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -32,6 +32,7 @@
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/Trace.h>
+#include <utils/CallStack.h>
namespace android {
@@ -45,12 +46,32 @@
mFenceFd(std::move(fenceFd)) {
}
+static status_t dump(const base::unique_fd &fd) {
+ ATRACE_CALL();
+
+ struct sync_file_info* finfo = sync_file_info(fd);
+ struct sync_fence_info* pinfo = sync_get_fence_info(finfo);
+
+ ALOGE(" ----- Printing sync-points under fence fd:%d status:%d name:%s -----",
+ fd.get(), finfo->status, finfo->name);
+ for (size_t i = 0; i < finfo->num_fences; i++) {
+ ALOGE("status:%d driver:%s obj:%s", pinfo[i].status,
+ pinfo[i].driver_name, pinfo[i].obj_name);
+ }
+
+ return NO_ERROR;
+}
+
status_t Fence::wait(int timeout) {
ATRACE_CALL();
if (mFenceFd == -1) {
return NO_ERROR;
}
int err = sync_wait(mFenceFd, timeout);
+ if (err < 0 && (timeout == TIMEOUT_NEVER || timeout >100)) {
+ ALOGE("ERROR :Fence didnt signal in %dms. Initiating dump", timeout);
+ dump(mFenceFd);
+ }
return err < 0 ? -errno : status_t(NO_ERROR);
}
@@ -64,6 +85,7 @@
if (err < 0 && errno == ETIME) {
ALOGE("waitForever: %s: fence %d didn't signal in %u ms", logname, mFenceFd.get(),
warningTimeout);
+ dump(mFenceFd);
struct sync_file_info* finfo = sync_file_info(mFenceFd);
if (finfo) {
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 040a62b..00fa94d 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -48,6 +48,8 @@
for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) {
bits = bits | bit;
}
+ // TODO(b/72323293, b/72703005): Remove these invalid bits from callers
+ bits = bits | ((1 << 10) | (1 << 13) | (1 << 21) | (1 << 27));
return bits;
}();
return valid10UsageBits;
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
index 882674f..4bba7d4 100644
--- a/libs/ui/Gralloc3.cpp
+++ b/libs/ui/Gralloc3.cpp
@@ -47,6 +47,8 @@
hardware::hidl_enum_range<hardware::graphics::common::V1_2::BufferUsage>()) {
bits = bits | bit;
}
+ // TODO(b/72323293, b/72703005): Remove these invalid bits from callers
+ bits = bits | ((1 << 13) | (1 << 21));
return bits;
}();
return validUsageBits;
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index f799ce4..fa5c099 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -55,6 +55,7 @@
hardware::hidl_enum_range<hardware::graphics::common::V1_2::BufferUsage>()) {
bits = bits | bit;
}
+ bits = bits | ((1 << 10) | (1 << 13) | (1 << 21) | (1 << 27));
return bits;
}();
return validUsageBits;
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 4b19e5e..3347ba6 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -84,12 +84,13 @@
bumpGeneration();
}
-void InputDevice::dump(std::string& dump) {
+void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) {
InputDeviceInfo deviceInfo;
getDeviceInfo(&deviceInfo);
dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
deviceInfo.getDisplayName().c_str());
+ dump += StringPrintf(INDENT "%s", eventHubDevStr.c_str());
dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
dump += StringPrintf(INDENT2 "AssociatedDisplayPort: ");
@@ -101,6 +102,7 @@
dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic));
dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
+ dump += StringPrintf(INDENT2 "ControllerNum: %d\n", deviceInfo.getControllerNumber());
const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
if (!ranges.empty()) {
@@ -200,6 +202,8 @@
// insert the context into the devices set
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
+ // Must change generation to flag this device as changed
+ bumpGeneration();
}
void InputDevice::removeEventHubDevice(int32_t eventHubId) {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 657a134..fc063f9 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -206,6 +206,14 @@
}
mDevices.emplace(eventHubId, device);
+ // Add device to device to EventHub ids map.
+ const auto mapIt = mDeviceToEventHubIdsMap.find(device);
+ if (mapIt == mDeviceToEventHubIdsMap.end()) {
+ std::vector<int32_t> ids = {eventHubId};
+ mDeviceToEventHubIdsMap.emplace(device, ids);
+ } else {
+ mapIt->second.push_back(eventHubId);
+ }
bumpGenerationLocked();
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
@@ -222,6 +230,17 @@
std::shared_ptr<InputDevice> device = std::move(deviceIt->second);
mDevices.erase(deviceIt);
+ // Erase device from device to EventHub ids map.
+ auto mapIt = mDeviceToEventHubIdsMap.find(device);
+ if (mapIt != mDeviceToEventHubIdsMap.end()) {
+ std::vector<int32_t>& eventHubIds = mapIt->second;
+ eventHubIds.erase(std::remove_if(eventHubIds.begin(), eventHubIds.end(),
+ [eventHubId](int32_t eId) { return eId == eventHubId; }),
+ eventHubIds.end());
+ if (eventHubIds.size() == 0) {
+ mDeviceToEventHubIdsMap.erase(mapIt);
+ }
+ }
bumpGenerationLocked();
if (device->isIgnored()) {
@@ -449,8 +468,7 @@
void InputReader::getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices) {
outInputDevices.clear();
- for (auto& devicePair : mDevices) {
- std::shared_ptr<InputDevice>& device = devicePair.second;
+ for (const auto& [device, eventHubIds] : mDeviceToEventHubIdsMap) {
if (!device->isIgnored()) {
InputDeviceInfo info;
device->getDeviceInfo(&info);
@@ -621,11 +639,17 @@
mEventHub->dump(dump);
dump += "\n";
- dump += "Input Reader State:\n";
+ dump += StringPrintf("Input Reader State (Nums of device: %zu):\n",
+ mDeviceToEventHubIdsMap.size());
- for (const auto& devicePair : mDevices) {
- const std::shared_ptr<InputDevice>& device = devicePair.second;
- device->dump(dump);
+ for (const auto& devicePair : mDeviceToEventHubIdsMap) {
+ const std::shared_ptr<InputDevice>& device = devicePair.first;
+ std::string eventHubDevStr = INDENT "EventHub Devices: [ ";
+ for (const auto& eId : devicePair.second) {
+ eventHubDevStr += StringPrintf("%d ", eId);
+ }
+ eventHubDevStr += "] \n";
+ device->dump(dump, eventHubDevStr);
}
dump += INDENT "Configuration:\n";
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 71313fc..a08062a 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -66,7 +66,7 @@
bool isEnabled();
void setEnabled(bool enabled, nsecs_t when);
- void dump(std::string& dump);
+ void dump(std::string& dump, const std::string& eventHubDevStr);
void addEventHubDevice(int32_t eventHubId, bool populateMappers = true);
void removeEventHubDevice(int32_t eventHubId);
void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 693ec30..d46ec1a 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -141,6 +141,11 @@
// to lookup the input device instance from the EventHub device id.
std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices;
+ // An input device contains one or more eventHubId, this map provides a way to lookup the
+ // EventHubIds contained in the input device from the input device instance.
+ std::unordered_map<std::shared_ptr<InputDevice>, std::vector<int32_t> /*eventHubId*/>
+ mDeviceToEventHubIdsMap;
+
// low-level input event decoding and device management
void processEventsLocked(const RawEvent* rawEvents, size_t count);
diff --git a/services/inputflinger/reader/include/TouchVideoDevice.h b/services/inputflinger/reader/include/TouchVideoDevice.h
index 5a32443..7de9b83 100644
--- a/services/inputflinger/reader/include/TouchVideoDevice.h
+++ b/services/inputflinger/reader/include/TouchVideoDevice.h
@@ -102,7 +102,7 @@
* How many buffers to keep for the internal queue. When the internal buffer
* exceeds this capacity, oldest frames will be dropped.
*/
- static constexpr size_t MAX_QUEUE_SIZE = 10;
+ static constexpr size_t MAX_QUEUE_SIZE = 20;
std::vector<TouchVideoFrame> mFrames;
/**
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 6842e6c..fc65a8e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -617,12 +617,15 @@
std::optional<uint32_t> receiveEvent(InputEvent** outEvent = nullptr) {
uint32_t consumeSeq;
InputEvent* event;
+ int motionEventType;
+ int touchMoveNumber;
+ bool flag;
std::chrono::time_point start = std::chrono::steady_clock::now();
status_t status = WOULD_BLOCK;
while (status == WOULD_BLOCK) {
status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq,
- &event);
+ &event, &motionEventType, &touchMoveNumber, &flag);
std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
if (elapsed > 100ms) {
break;
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 8a282e2..e355594 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -153,12 +153,18 @@
SensorDeviceUtils::defaultResolutionForType(sensor.type);
}
- double promotedResolution = sensor.resolution;
- double promotedMaxRange = sensor.maxRange;
- if (fmod(promotedMaxRange, promotedResolution) != 0) {
- ALOGW("%s's max range %f is not a multiple of the resolution %f",
- sensor.name, sensor.maxRange, sensor.resolution);
- SensorDeviceUtils::quantizeValue(&sensor.maxRange, promotedResolution);
+ // Some sensors don't have a default resolution and will be left at 0.
+ // Don't crash in this case since CTS will verify that devices don't go to
+ // production with a resolution of 0.
+ if (sensor.resolution != 0) {
+ double promotedResolution = sensor.resolution;
+ double promotedMaxRange = sensor.maxRange;
+ if (fmod(promotedMaxRange, promotedResolution) != 0) {
+ ALOGW("%s's max range %f is not a multiple of the resolution %f",
+ sensor.name, sensor.maxRange, sensor.resolution);
+ SensorDeviceUtils::quantizeValue(
+ &sensor.maxRange, promotedResolution);
+ }
}
}
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 6c86712..3cccaf9 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -29,6 +29,12 @@
#define UNUSED(x) (void)(x)
namespace android {
+namespace {
+
+// Used as the default value for the target SDK until it's obtained via getTargetSdkVersion.
+constexpr int kTargetSdkUnknown = 0;
+
+} // namespace
SensorService::SensorEventConnection::SensorEventConnection(
const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
@@ -36,9 +42,9 @@
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
- mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false) {
+ mPackageName(packageName), mOpPackageName(opPackageName), mTargetSdk(kTargetSdkUnknown),
+ mDestroyed(false) {
mChannel = new BitTube(mService->mSocketBufferSize);
- mTargetSdk = SensorService::getTargetSdkVersion(opPackageName);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
mTotalAcksNeeded = mTotalAcksReceived = 0;
@@ -439,6 +445,14 @@
bool success = true;
const auto iter = mHandleToAppOp.find(event.sensor);
if (iter != mHandleToAppOp.end()) {
+ if (mTargetSdk == kTargetSdkUnknown) {
+ // getTargetSdkVersion returns -1 if it fails so this operation should only be run once
+ // per connection and then cached. Perform this here as opposed to in the constructor to
+ // avoid log spam for NDK/VNDK clients that don't use sensors guarded with permissions
+ // and pass in invalid op package names.
+ mTargetSdk = SensorService::getTargetSdkVersion(mOpPackageName);
+ }
+
// Special handling for step count/detect backwards compatibility: if the app's target SDK
// is pre-Q, still permit delivering events to the app even if permission isn't granted
// (since this permission was only introduced in Q)
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 60f9cd9..3ca34bb 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -79,6 +79,8 @@
bool SensorService::sHmacGlobalKeyIsValid = false;
std::map<String16, int> SensorService::sPackageTargetVersion;
Mutex SensorService::sPackageTargetVersionLock;
+String16 SensorService::sSensorInterfaceDescriptorPrefix =
+ String16("android.frameworks.sensorservice@");
AppOpsManager SensorService::sAppOpsManager;
#define SENSOR_SERVICE_DIR "/data/system/sensor_service"
@@ -1847,6 +1849,13 @@
}
int SensorService::getTargetSdkVersion(const String16& opPackageName) {
+ // Don't query the SDK version for the ISensorManager descriptor as it doesn't have one. This
+ // descriptor tends to be used for VNDK clients, but can technically be set by anyone so don't
+ // give it elevated privileges.
+ if (opPackageName.startsWith(sSensorInterfaceDescriptorPrefix)) {
+ return -1;
+ }
+
Mutex::Autolock packageLock(sPackageTargetVersionLock);
int targetSdkVersion = -1;
auto entry = sPackageTargetVersion.find(opPackageName);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 3bb8421..052cbfe 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -424,6 +424,7 @@
static AppOpsManager sAppOpsManager;
static std::map<String16, int> sPackageTargetVersion;
static Mutex sPackageTargetVersionLock;
+ static String16 sSensorInterfaceDescriptorPrefix;
};
} // namespace android
diff --git a/services/stats/StatsHal.cpp b/services/stats/StatsHal.cpp
index 80c3b65..ae0a984 100644
--- a/services/stats/StatsHal.cpp
+++ b/services/stats/StatsHal.cpp
@@ -58,7 +58,7 @@
std::vector<int32_t> buckets = chargeCycles.cycleBucket;
int initialSize = buckets.size();
for (int i = 0; i < 10 - initialSize; i++) {
- buckets.push_back(-1); // Push -1 for buckets that do not exist.
+ buckets.push_back(0); // Push 0 for buckets that do not exist.
}
android::util::stats_write(android::util::CHARGE_CYCLES_REPORTED, buckets[0], buckets[1],
buckets[2], buckets[3], buckets[4], buckets[5], buckets[6], buckets[7], buckets[8],
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index a790d0b..22957ca 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,3 +1,30 @@
+soong_config_module_type {
+ name: "libdisplayconfig_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "qtidisplaycommonsys",
+ bool_variables: [
+ "displayconfig_enabled",
+ ],
+ properties: [
+ "cflags",
+ "srcs",
+ "shared_libs",
+ ],
+ }
+
+ libdisplayconfig_cc_defaults {
+ name: "libdisplayconfig_defaults",
+ soong_config_variables: {
+ displayconfig_enabled : {
+ cflags: [
+ "-Wno-unused-parameter",
+ "-DQTI_DISPLAY_CONFIG_ENABLED"
+ ],
+ shared_libs : ["libdisplayconfig.qti"]
+ }
+ }
+ }
+
cc_defaults {
name: "surfaceflinger_defaults",
cflags: [
@@ -11,9 +38,9 @@
],
}
-cc_defaults {
+libdisplayconfig_cc_defaults {
name: "libsurfaceflinger_defaults",
- defaults: ["surfaceflinger_defaults"],
+ defaults: ["surfaceflinger_defaults", "libdisplayconfig_defaults"],
cflags: [
"-DLOG_TAG=\"SurfaceFlinger\"",
"-DGL_GLEXT_PROTOTYPES",
@@ -31,6 +58,7 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
+ "vendor.qti.hardware.display.composer@3.0",
"android.hardware.power@1.0",
"android.hardware.power@1.3",
"android.hardware.power-cpp",
@@ -79,6 +107,7 @@
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
"android.hardware.graphics.composer@2.4-command-buffer",
+ "display_intf_headers",
],
export_static_lib_headers: [
"libcompositionengine",
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 07be791..3f86188 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -34,6 +34,10 @@
#include "Scheduler/LayerHistory.h"
#include "TimeStats/TimeStats.h"
+#include "frame_extn_intf.h"
+#include "smomo_interface.h"
+#include "layer_extn_intf.h"
+
namespace android {
BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
@@ -122,7 +126,18 @@
mFlinger->mTimeStats->incrementBadDesiredPresent(getSequence());
}
- const bool isDue = addedTime < expectedPresentTime;
+ bool isDue = addedTime < expectedPresentTime;
+
+ if (isDue && mFlinger->mSmoMo) {
+ smomo::SmomoBufferStats bufferStats;
+ bufferStats.id = getSequence();
+ bufferStats.queued_frames = getQueuedFrameCount();
+ bufferStats.auto_timestamp = mQueueItems[0].mIsAutoTimestamp;
+ bufferStats.timestamp = mQueueItems[0].mTimestamp;
+ bufferStats.dequeue_latency = 0;
+ isDue = mFlinger->mSmoMo->ShouldPresentNow(bufferStats, expectedPresentTime);
+ }
+
return isDue || !isPlausible;
}
@@ -324,9 +339,6 @@
}
uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId();
- mFlinger->mFrameTracer->traceFence(layerId, bufferID, currentFrameNumber,
- mQueueItems[0].mFenceTime,
- FrameTracer::FrameEvent::ACQUIRE_FENCE);
mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime);
mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime,
FrameTracer::FrameEvent::LATCH);
@@ -393,8 +405,12 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
const int32_t layerId = getSequence();
- mFlinger->mFrameTracer->traceTimestamp(layerId, item.mGraphicBuffer->getId(), item.mFrameNumber,
- systemTime(), FrameTracer::FrameEvent::QUEUE);
+ const uint64_t bufferId = item.mGraphicBuffer->getId();
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(),
+ FrameTracer::FrameEvent::QUEUE);
+ mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber,
+ std::make_shared<FenceTime>(item.mFence),
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
ATRACE_CALL();
// Add this buffer from our internal queue tracker
@@ -430,6 +446,42 @@
mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(), item.mFrameNumber);
+ if (mFlinger->mSmoMo) {
+ smomo::SmomoBufferStats bufferStats;
+ bufferStats.id = getSequence();
+ bufferStats.queued_frames = getQueuedFrameCount();
+ bufferStats.auto_timestamp = item.mIsAutoTimestamp;
+ bufferStats.timestamp = item.mTimestamp;
+ bufferStats.dequeue_latency = 0;
+ mFlinger->mSmoMo->CollectLayerStats(bufferStats);
+ }
+
+ if (mFlinger->mFrameExtn && mFlinger->mDolphinFuncsEnabled) {
+ composer::FrameInfo frameInfo;
+ frameInfo.version.major = (uint8_t)(1);
+ frameInfo.version.minor = (uint8_t)(0);
+ frameInfo.max_queued_frames = mFlinger->mMaxQueuedFrames;
+ frameInfo.num_idle = mFlinger->mNumIdle;
+ frameInfo.max_queued_layer_name = mFlinger->mNameLayerMax;
+ frameInfo.current_timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ frameInfo.previous_timestamp = mLastTimeStamp;
+ frameInfo.vsync_timestamp = mFlinger->mVsyncTimeStamp;
+ frameInfo.refresh_timestamp = mFlinger->mRefreshTimeStamp;
+ frameInfo.ref_latency = mFrameTracker.getPreviousGfxInfo();
+ frameInfo.vsync_period = mFlinger->mVsyncPeriod;
+ frameInfo.transparent_region = !this->isOpaque(mDrawingState);
+ if (frameInfo.transparent_region) {
+ if (this->isLayerFocusedBasedOnPriority(this->getPriority())) {
+ frameInfo.transparent_region = false;
+ }
+ }
+ frameInfo.width = item.mGraphicBuffer->getWidth();
+ frameInfo.height = item.mGraphicBuffer->getHeight();
+ frameInfo.layer_name = this->getName().c_str();
+ mLastTimeStamp = frameInfo.current_timestamp;
+ mFlinger->mFrameExtn->SetFrameInfo(frameInfo);
+ }
+
mFlinger->signalLayerUpdate();
mConsumer->onBufferAvailable(item);
}
@@ -460,8 +512,12 @@
}
const int32_t layerId = getSequence();
- mFlinger->mFrameTracer->traceTimestamp(layerId, item.mGraphicBuffer->getId(), item.mFrameNumber,
- systemTime(), FrameTracer::FrameEvent::QUEUE);
+ const uint64_t bufferId = item.mGraphicBuffer->getId();
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(),
+ FrameTracer::FrameEvent::QUEUE);
+ mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber,
+ std::make_shared<FenceTime>(item.mFence),
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
mConsumer->onBufferAvailable(item);
}
@@ -496,6 +552,10 @@
if (!mFlinger->isLayerTripleBufferingDisabled()) {
mProducer->setMaxDequeuedBufferCount(2);
}
+
+ if (mFlinger->mUseLayerExt && mFlinger->mLayerExt) {
+ mLayerClass = mFlinger->mLayerExt->GetLayerClass(mName);
+ }
}
status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 5ebc22d..315e88b 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -148,6 +148,7 @@
std::atomic<bool> mSidebandStreamChanged{false};
sp<ContentsChangedListener> mContentsChangedListener;
+ nsecs_t mLastTimeStamp = -1;
};
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index b3b9fe5..ff327b8 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -1,9 +1,15 @@
-cc_defaults {
+soong_config_module_type_import {
+ from: "frameworks/native/services/surfaceflinger/Android.bp",
+ module_types: ["libdisplayconfig_cc_defaults"],
+}
+
+libdisplayconfig_cc_defaults {
name: "libcompositionengine_defaults",
- defaults: ["surfaceflinger_defaults"],
+ defaults: ["surfaceflinger_defaults", "libdisplayconfig_defaults"],
cflags: [
"-DLOG_TAG=\"CompositionEngine\"",
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+ "-Wno-unused-private-field",
],
shared_libs: [
"android.frameworks.vr.composer@2.0",
@@ -36,6 +42,7 @@
"android.hardware.graphics.composer@2.3-command-buffer",
"android.hardware.graphics.composer@2.4-command-buffer",
"libsurfaceflinger_headers",
+ "display_intf_headers",
],
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 8a9763b..6ff0f53 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -189,7 +189,13 @@
// The output-independent frame for the cursor
Rect cursorFrame;
+ // layer classification
+ uint32_t layerClass;
+
virtual ~LayerFECompositionState();
+ bool isSecureDisplay{false};
+ bool isSecureCamera{false};
+ bool isScreenshot{false};
// Debugging
virtual void dump(std::string& out) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index baf5258..32bef3b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -149,6 +149,8 @@
Region dirtyRegion;
};
+ bool hasSecureDisplay{false};
+
virtual ~Output();
// Returns true if the output is valid. This is meant to be checked post-
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index f680460..07e83ad 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -98,6 +98,12 @@
// Debugging - gets the page flip count for the RenderSurface
virtual std::uint32_t getPageFlipCount() const = 0;
+ // Called to set the viewport and projection state for rendering into this
+ // surface
+ virtual void setViewportAndProjection() = 0;
+
+ // Called to flip the client target when needed
+ virtual void flipClientTarget(bool flip) = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 7a4f738..0d8de81 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -91,6 +91,8 @@
bool mIsVirtual = false;
std::optional<DisplayId> mId;
Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
+ bool mHasScreenshot = false;
+ DisplayConnectionType mConnectionType = DisplayConnectionType::Internal;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index 2864c10..6932be0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -61,6 +61,8 @@
// buffer) pair. "counter" is a unique value that indicates the last time this slot was updated
// or used and allows us to keep track of the least-recently used buffer.
wp<GraphicBuffer> mBuffers[BufferQueue::NUM_BUFFER_SLOTS];
+ uint32_t mNextSlot = 0;
+ bool mReduceSlotsForWideVideo = false;
};
} // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 5127a6f..e23442d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -68,6 +68,8 @@
void setSizeForTest(const ui::Size&);
sp<GraphicBuffer>& mutableGraphicBufferForTest();
base::unique_fd& mutableBufferReadyForTest();
+ void flipClientTarget(bool flip) override;
+ void setViewportAndProjection() override;
private:
const compositionengine::CompositionEngine& mCompositionEngine;
@@ -80,6 +82,7 @@
const sp<DisplaySurface> mDisplaySurface;
ui::Size mSize;
bool mProtected{false};
+ bool mFlipClientTarget{false};
std::uint32_t mPageFlipCount{0};
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index a0cae6f..581d063 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -41,9 +41,11 @@
MOCK_METHOD2(prepareFrame, void(bool, bool));
MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
MOCK_METHOD1(queueBuffer, void(base::unique_fd));
+ MOCK_METHOD1(flipClientTarget, void(bool flip));
MOCK_METHOD0(onPresentDisplayCompleted, void());
MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
+ MOCK_METHOD0(setViewportAndProjection, void());
MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
};
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index d201104..bc5e1f7 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -20,12 +20,17 @@
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/DisplaySurface.h>
#include <compositionengine/LayerFE.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/DisplayColorProfile.h>
#include <compositionengine/impl/DumpHelpers.h>
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/RenderSurface.h>
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+#include <config/client_interface.h>
+#endif
+
#include <utils/Trace.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -41,6 +46,10 @@
namespace android::compositionengine::impl {
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+::DisplayConfig::ClientInterface *mDisplayConfigIntf = nullptr;
+#endif
+
std::shared_ptr<Display> createDisplay(
const compositionengine::CompositionEngine& compositionEngine,
const compositionengine::DisplayCreationArgs& args) {
@@ -52,6 +61,7 @@
void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) {
mIsVirtual = !args.physical;
mId = args.physical ? std::make_optional(args.physical->id) : std::nullopt;
+ mConnectionType = args.physical ? args.physical->type : DisplayConnectionType::Internal;
mPowerAdvisor = args.powerAdvisor;
editState().isSecure = args.isSecure;
@@ -64,6 +74,15 @@
if (!args.physical && args.useHwcVirtualDisplays) {
mId = maybeAllocateDisplayIdForVirtualDisplay(args.pixels, args.pixelFormat);
}
+
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ int ret = ::DisplayConfig::ClientInterface::Create(args.name, nullptr, &mDisplayConfigIntf);
+ if (ret) {
+ ALOGE("DisplayConfig HIDL not present\n");
+ mDisplayConfigIntf = nullptr;
+ }
+#endif
+
}
std::optional<DisplayId> Display::maybeAllocateDisplayIdForVirtualDisplay(
@@ -194,6 +213,13 @@
ALOGE_IF(!hwcLayer, "Failed to create a HWC layer for a HWC supported display %s",
getName().c_str());
result->setHwcLayer(std::move(hwcLayer));
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ if (layerFE->getCompositionState()->internalOnly && mDisplayConfigIntf) {
+ const auto hwcDisplayId = hwc.fromPhysicalDisplayId(*mId);
+ mDisplayConfigIntf->SetLayerAsMask(static_cast<uint32_t>(*hwcDisplayId),
+ result->getHwcLayer()->getId());
+ }
+#endif
}
return result;
}
@@ -248,6 +274,21 @@
// Get any composition changes requested by the HWC device, and apply them.
std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
+
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ auto layers = getOutputLayersOrderedByZ();
+ bool hasScreenshot = std::any_of(layers.begin(), layers.end(), [](auto* layer) {
+ return layer->getLayerFE().getCompositionState()->isScreenshot;
+ });
+ if ((mIsVirtual || (mConnectionType == DisplayConnectionType::External)) &&
+ (hasScreenshot != mHasScreenshot) && mDisplayConfigIntf) {
+ const auto hwcDisplayId = hwc.fromPhysicalDisplayId(*mId);
+ if (hwcDisplayId) {
+ mDisplayConfigIntf->SetDisplayAnimating(*hwcDisplayId, hasScreenshot);
+ mHasScreenshot = hasScreenshot;
+ }
+ }
+#endif
if (status_t result = hwc.getDeviceCompositionChanges(*mId, anyLayersRequireClientComposition(),
&changes);
result != NO_ERROR) {
@@ -331,7 +372,7 @@
if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
return;
}
- auto outputState = editState();
+ auto &outputState = editState();
outputState.dataspace = clientTargetProperty.dataspace;
getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index cedc333..c3b613a 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -22,28 +22,96 @@
#include <gui/BufferQueue.h>
#include <ui/GraphicBuffer.h>
+#include <cstdlib>
+#include <cutils/properties.h>
+#include <QtiGrallocDefs.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
+constexpr int MAX_VIDEO_WIDTH = 5760;
+constexpr int MAX_VIDEO_HEIGHT = 2160;
+constexpr int MAX_NUM_SLOTS_FOR_WIDE_VIDEOS = 4;
+
namespace android::compositionengine::impl {
HwcBufferCache::HwcBufferCache() {
std::fill(std::begin(mBuffers), std::end(mBuffers), wp<GraphicBuffer>(nullptr));
+ char value[PROPERTY_VALUE_MAX];
+ property_get("vendor.display.reduce_slots_for_wide_video", value, "1");
+ mReduceSlotsForWideVideo = atoi(value);
+}
+
+//TODO: Move to common location
+static bool formatIsYuv(const PixelFormat format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_YCBCR_422_SP:
+ case HAL_PIXEL_FORMAT_YCRCB_420_SP:
+ case HAL_PIXEL_FORMAT_YCBCR_422_I:
+ case HAL_PIXEL_FORMAT_YCBCR_420_888:
+ case HAL_PIXEL_FORMAT_Y8:
+ case HAL_PIXEL_FORMAT_Y16:
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YCBCR_P010:
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ case HAL_PIXEL_FORMAT_NV21_ENCODEABLE:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_444_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_444_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ case HAL_PIXEL_FORMAT_NV21_ZSL:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS:
+ case HAL_PIXEL_FORMAT_NV12_HEIF:
+ case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC:
+ case HAL_PIXEL_FORMAT_YCbCr_420_P010_VENUS:
+ case HAL_PIXEL_FORMAT_CbYCrY_422_I:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT_COMPRESSED:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
+ case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC:
+ return true;
+ default:
+ return false;
+ }
}
void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
sp<GraphicBuffer>* outBuffer) {
// default is 0
+ wp<GraphicBuffer> weakCopy(buffer);
+ uint32_t width = 0;
+ uint32_t height = 0;
+ PixelFormat format = PIXEL_FORMAT_NONE;
+ if (buffer) {
+ width = buffer->getWidth();
+ height = buffer->getHeight();
+ format = buffer->getPixelFormat();
+ }
+ bool widevideo = false;
+ uint32_t numSlots = BufferQueue::NUM_BUFFER_SLOTS;
+
+ // Workaround to reduce slots for 8k buffers
+ if ((width * height > MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT) && mReduceSlotsForWideVideo &&
+ formatIsYuv(format)) {
+ numSlots = MAX_NUM_SLOTS_FOR_WIDE_VIDEOS;
+ widevideo = true;
+ }
if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0 ||
- slot >= BufferQueue::NUM_BUFFER_SLOTS) {
+ slot >= numSlots) {
*outSlot = 0;
+ if (widevideo && slot >= numSlots) {
+ *outSlot = mNextSlot % numSlots;
+ mNextSlot = *outSlot + 1;
+ }
} else {
*outSlot = static_cast<uint32_t>(slot);
}
auto& currentBuffer = mBuffers[*outSlot];
- wp<GraphicBuffer> weakCopy(buffer);
if (currentBuffer == weakCopy) {
// already cached in HWC, skip sending the buffer
*outBuffer = nullptr;
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e8f54f5..8567ac6 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -689,12 +689,23 @@
}
// respect hdrDataSpace only when there is no legacy HDR support
- const bool isHdr = hdrDataSpace != ui::Dataspace::UNKNOWN &&
+ bool isHdr = hdrDataSpace != ui::Dataspace::UNKNOWN &&
!mDisplayColorProfile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition;
+
+ auto layers = getOutputLayersOrderedByZ();
+ bool hasSecureDisplay = std::any_of(layers.begin(), layers.end(), [](auto* layer) {
+ return layer->getLayerFE().getCompositionState()->isSecureDisplay;
+ });
+
if (isHdr) {
bestDataSpace = hdrDataSpace;
}
+ if (hasSecureDisplay) {
+ bestDataSpace = ui::Dataspace::V0_SRGB;
+ isHdr = false;
+ }
+
ui::RenderIntent intent;
switch (refreshArgs.outputColorSetting) {
case OutputColorSetting::kManaged:
@@ -817,24 +828,35 @@
const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
outputState.usesClientComposition};
+ bool hasSecureCamera = false;
+ bool hasSecureDisplay = false;
+ bool needsProtected = false;
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ if (layer->getLayerFE().getCompositionState()->isSecureCamera) {
+ hasSecureCamera = true;
+ }
+ if (layer->getLayerFE().getCompositionState()->isSecureDisplay) {
+ hasSecureDisplay = true;
+ }
+ if (layer->getLayerFE().getCompositionState()->hasProtectedContent) {
+ needsProtected = true;
+ }
+ }
+
auto& renderEngine = getCompositionEngine().getRenderEngine();
- const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
+ const bool supportsProtectedContent = renderEngine.supportsProtectedContent() &&
+ !hasSecureCamera && !hasSecureDisplay &&
+ outputState.isSecure && needsProtected;
// If we the display is secure, protected content support is enabled, and at
// least one layer has protected content, we need to use a secure back
// buffer.
- if (outputState.isSecure && supportsProtectedContent) {
- auto layers = getOutputLayersOrderedByZ();
- bool needsProtected = std::any_of(layers.begin(), layers.end(), [](auto* layer) {
- return layer->getLayerFE().getCompositionState()->hasProtectedContent;
- });
- if (needsProtected != renderEngine.isProtected()) {
- renderEngine.useProtectedContext(needsProtected);
- }
- if (needsProtected != mRenderSurface->isProtected() &&
- needsProtected == renderEngine.isProtected()) {
- mRenderSurface->setProtected(needsProtected);
- }
+ if (supportsProtectedContent != renderEngine.isProtected()) {
+ renderEngine.useProtectedContext(supportsProtectedContent);
+ }
+ if (supportsProtectedContent != mRenderSurface->isProtected() &&
+ supportsProtectedContent == renderEngine.isProtected()) {
+ mRenderSurface->setProtected(supportsProtectedContent);
}
base::unique_fd fd;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 1faf775..8f345bd 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -475,6 +475,12 @@
// Ignored
break;
}
+
+ if (auto error = hwcLayer->setType(outputIndependentState.layerClass);
+ error != hal::Error::NONE) {
+ ALOGE("[%s] Failed to set layer class: %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
}
void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 2773fd3..3cf1438 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -172,7 +172,8 @@
void RenderSurface::queueBuffer(base::unique_fd readyFence) {
auto& state = mDisplay.getState();
- if (state.usesClientComposition || state.flipClientTarget) {
+
+ if (state.usesClientComposition || state.flipClientTarget || mFlipClientTarget) {
// hasFlipClientTargetRequest could return true even if we haven't
// dequeued a buffer before. Try dequeueing one if we don't have a
// buffer ready.
@@ -193,7 +194,8 @@
} else {
status_t result =
mNativeWindow->queueBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(), dup(readyFence));
+ mGraphicBuffer->getNativeBuffer(),
+ mFlipClientTarget ? -1 : dup(readyFence));
if (result != NO_ERROR) {
ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
result);
@@ -203,7 +205,8 @@
LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
} else {
mNativeWindow->cancelBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(), dup(readyFence));
+ mGraphicBuffer->getNativeBuffer(),
+ mFlipClientTarget ? -1 : dup(readyFence));
}
}
@@ -225,6 +228,12 @@
mPageFlipCount++;
}
+void RenderSurface::setViewportAndProjection() {
+ Rect sourceCrop = Rect(mSize);
+ Rect viewPort = Rect(mSize.width, mSize.height);
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ renderEngine.setViewportAndProjection(viewPort, sourceCrop);
+}
void RenderSurface::dump(std::string& out) const {
using android::base::StringAppendF;
@@ -259,5 +268,9 @@
return mGraphicBuffer;
}
+void RenderSurface::flipClientTarget(bool flip) {
+ mFlipClientTarget = flip;
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 09f37fb..29fd4b9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -159,6 +159,7 @@
EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
}
DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index d21b97e..f8c2e3c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -67,6 +67,7 @@
MOCK_METHOD1(setVisibleRegion, Error(const android::Region&));
MOCK_METHOD1(setZOrder, Error(uint32_t));
MOCK_METHOD2(setInfo, Error(uint32_t, uint32_t));
+ MOCK_METHOD1(setType, Error(uint32_t));
MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
MOCK_METHOD3(setLayerGenericMetadata,
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 75a4fec..817de9a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -75,6 +75,7 @@
MOCK_METHOD4(getDisplayedContentSample,
status_t(DisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
MOCK_METHOD2(setDisplayBrightness, std::future<status_t>(DisplayId, float));
+ MOCK_METHOD2(setDisplayElapseTime, status_t(DisplayId, uint64_t));
MOCK_METHOD2(getDisplayBrightnessSupport, status_t(DisplayId, bool*));
MOCK_METHOD2(onHotplug,
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index b738096..d7dff36 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -32,6 +32,7 @@
MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
MOCK_METHOD0(notifyDisplayUpdateImminent, void());
+ MOCK_METHOD0(canNotifyDisplayUpdateImminent, bool());
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 59ed72e..e1989ae 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -2871,6 +2871,7 @@
mOutput.mState.usesClientComposition = false;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -2883,6 +2884,7 @@
mOutput.mState.flipClientTarget = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(mOutputBuffer));
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -2892,6 +2894,7 @@
TEST_F(OutputComposeSurfacesTest, doesMinimalWorkIfDequeueBufferFailsForClientComposition) {
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
@@ -2904,6 +2907,7 @@
mOutput.mState.flipClientTarget = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
@@ -2914,6 +2918,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2936,6 +2941,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2963,6 +2969,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2991,6 +2998,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3019,6 +3027,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3050,6 +3059,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r2}))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r3}));
@@ -3072,6 +3082,7 @@
struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComposeSurfacesTest {
OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3219,6 +3230,8 @@
mOutput.mState.isSecure = false;
mLayer2.mLayerFEState.hasProtectedContent = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
+ EXPECT_CALL(mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
@@ -3311,6 +3324,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 730f297..ce38f25 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -61,7 +61,8 @@
mConnectionType(args.connectionType),
mCompositionDisplay{args.compositionDisplay},
mPhysicalOrientation(args.physicalOrientation),
- mIsPrimary(args.isPrimary) {
+ mIsPrimary(args.isPrimary),
+ mIsPowerModeOverride(false){
mCompositionDisplay->editState().isSecure = args.isSecure;
mCompositionDisplay->createRenderSurface(
compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth(
@@ -142,6 +143,14 @@
return mActiveConfig;
}
+void DisplayDevice::setPowerModeOverrideConfig(bool supported) {
+ mIsPowerModeOverride = supported;
+}
+
+bool DisplayDevice::getPowerModeOverrideConfig() const {
+ return mIsPowerModeOverride;
+}
+
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
return mCompositionDisplay->getState().dataspace;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index cb467ea..49dd910 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -151,6 +151,8 @@
HwcConfigIndexType getActiveConfig() const;
void setActiveConfig(HwcConfigIndexType mode);
+ void setPowerModeOverrideConfig(bool supported);
+ bool getPowerModeOverrideConfig() const;
// release HWC resources (if any) for removable displays
void disconnect();
@@ -182,6 +184,7 @@
// TODO(b/74619554): Remove special cases for primary display.
const bool mIsPrimary;
+ bool mIsPowerModeOverride;
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index a3f1b52..805050d 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -32,12 +32,21 @@
#include <gui/BufferQueue.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/HidlTransportUtils.h>
+#include <vendor/qti/hardware/display/composer/3.0/IQtiComposerClient.h>
+
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+#include <config/client_interface.h>
+namespace DisplayConfig {
+class ClientInterface;
+}
+#endif
namespace android {
using hardware::Return;
using hardware::hidl_vec;
using hardware::hidl_handle;
+using vendor::qti::hardware::display::composer::V3_0::IQtiComposerClient;
namespace Hwc2 {
@@ -117,6 +126,16 @@
namespace impl {
+void Composer::CommandWriter::setLayerType(uint32_t type)
+{
+ constexpr uint16_t kSetLayerTypeLength = 1;
+ beginCommand(static_cast<V2_1::IComposerClient::Command>(
+ IQtiComposerClient::Command::SET_LAYER_TYPE),
+ kSetLayerTypeLength);
+ write(type);
+ endCommand();
+}
+
#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Composer::CommandWriter::CommandWriter(uint32_t initialMaxSize)
: CommandWriterBase(initialMaxSize) {}
@@ -170,6 +189,16 @@
}
#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
+void Composer::CommandWriter::setDisplayElapseTime(uint64_t time)
+{
+ constexpr uint16_t kSetDisplayElapseTimeLength = 2;
+ beginCommand(static_cast<V2_1::IComposerClient::Command>(
+ IQtiComposerClient::Command::SET_DISPLAY_ELAPSE_TIME),
+ kSetDisplayElapseTimeLength);
+ write64(time);
+ endCommand();
+}
+
Composer::Composer(const std::string& serviceName)
: mWriter(kWriterInitialSize),
mIsUsingVrComposer(serviceName == std::string("vr"))
@@ -216,6 +245,29 @@
LOG_ALWAYS_FATAL("failed to create composer client");
}
+ // On successful creation of composer client only AllowIdleFallback
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ if (mClient) {
+ ::DisplayConfig::ClientInterface *mDisplayConfigIntf = nullptr;
+ ::DisplayConfig::ClientInterface::Create("SurfaceFlinger"+std::to_string(0),
+ nullptr, &mDisplayConfigIntf);
+ if (mDisplayConfigIntf) {
+#ifdef DISPLAY_CONFIG_API_LEVEL_2
+ std::string value = "";
+ std::string idle_fallback_prop = "enable_allow_idle_fallback";
+ int ret = mDisplayConfigIntf->GetDebugProperty(idle_fallback_prop, &value);
+ ALOGI("enable_allow_idle_fallback, ret:%d value:%s", ret, value.c_str());
+ if (!ret && (value == "1")) {
+ if(mDisplayConfigIntf->AllowIdleFallback()) {
+ ALOGW("failed to set Idle time");
+ }
+ }
+#endif
+ ::DisplayConfig::ClientInterface::Destroy(mDisplayConfigIntf);
+ }
+ }
+#endif
+
#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
if (mIsUsingVrComposer) {
sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
@@ -642,6 +694,13 @@
return Error::NONE;
}
+Error Composer::setDisplayElapseTime(Display display, uint64_t timeStamp)
+{
+ mWriter.selectDisplay(display);
+ mWriter.setDisplayElapseTime(timeStamp);
+ return Error::NONE;
+}
+
Error Composer::setPowerMode(Display display, IComposerClient::PowerMode mode) {
Return<Error> ret(Error::UNSUPPORTED);
if (mClient_2_2) {
@@ -871,6 +930,19 @@
}
#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
+Error Composer::setLayerType(Display display, Layer layer, uint32_t type)
+{
+ if (mClient_2_4) {
+ if (sp<IQtiComposerClient> qClient = IQtiComposerClient::castFrom(mClient_2_4)) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerType(type);
+ }
+ }
+
+ return Error::NONE;
+}
+
Error Composer::execute()
{
// prepare input command queue
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 00ef782..5408d55 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -189,6 +189,7 @@
const std::vector<IComposerClient::Rect>& visible) = 0;
virtual Error setLayerZOrder(Display display, Layer layer, uint32_t z) = 0;
virtual Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) = 0;
+ virtual Error setLayerType(Display display, Layer layer, uint32_t type) = 0;
// Composer HAL 2.2
virtual Error setLayerPerFrameMetadata(
@@ -242,6 +243,7 @@
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
virtual Error getClientTargetProperty(
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
+ virtual Error setDisplayElapseTime(Display display, uint64_t timeStamp) = 0;
};
namespace impl {
@@ -437,6 +439,7 @@
const std::vector<IComposerClient::Rect>& visible) override;
Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) override;
+ Error setLayerType(Display display, Layer layer, uint32_t type) override;
// Composer HAL 2.2
Error setLayerPerFrameMetadata(
@@ -463,6 +466,7 @@
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
Error setDisplayBrightness(Display display, float brightness) override;
+ Error setDisplayElapseTime(Display display, uint64_t timeStamp) override;
// Composer HAL 2.4
bool isVsyncPeriodSwitchSupported() override { return mClient_2_4 != nullptr; }
@@ -497,10 +501,12 @@
~CommandWriter() override;
void setLayerInfo(uint32_t type, uint32_t appId);
+ void setLayerType(uint32_t type);
void setClientTargetMetadata(
const IVrComposerClient::BufferMetadata& metadata);
void setLayerBufferMetadata(
const IVrComposerClient::BufferMetadata& metadata);
+ void setDisplayElapseTime(uint64_t time);
private:
void writeBufferMetadata(
@@ -511,6 +517,9 @@
public:
explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {}
~CommandWriter() override {}
+
+ void setDisplayElapseTime(uint64_t time);
+ void setLayerType(uint32_t type);
};
#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 08559bd..940437f 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -570,6 +570,12 @@
return static_cast<Error>(intError);
}
+Error Display::setDisplayElapseTime(uint64_t timeStamp)
+{
+ auto intError = mComposer.setDisplayElapseTime(mId, timeStamp);
+ return static_cast<Error>(intError);
+}
+
Error Display::setPowerMode(PowerMode mode)
{
auto intMode = static_cast<Hwc2::IComposerClient::PowerMode>(mode);
@@ -983,6 +989,20 @@
return static_cast<Error>(intError);
}
+Error Layer::setType(uint32_t type)
+{
+ if (type == mType) {
+ return Error::NONE;
+ }
+ auto intError = mComposer.setLayerType(mDisplayId, mId, type);
+ Error error = static_cast<Error>(intError);
+ if (error != Error::NONE) {
+ return error;
+ }
+ mType = type;
+ return error;
+}
+
// Composer HAL 2.3
Error Layer::setColorTransform(const android::mat4& matrix) {
if (matrix == mColorMatrix) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 6819ff4..469baf7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -236,6 +236,7 @@
[[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
[[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty(
hal::ClientTargetProperty* outClientTargetProperty) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setDisplayElapseTime(uint64_t timeStamp) = 0;
};
namespace impl {
@@ -308,6 +309,7 @@
std::vector<hal::ContentType>* outSupportedContentTypes) const override;
hal::Error setContentType(hal::ContentType) override;
hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty) override;
+ hal::Error setDisplayElapseTime(uint64_t timeStamp) override;
// Other Display methods
hal::HWDisplayId getId() const override { return mId; }
@@ -342,7 +344,7 @@
bool mIsConnected = false;
std::unordered_map<hal::HWLayerId, std::unique_ptr<Layer>> mLayers;
- std::unordered_map<hal::HWConfigId, std::shared_ptr<const Config>> mConfigs;
+ std::map<hal::HWConfigId, std::shared_ptr<const Config>> mConfigs;
std::once_flag mDisplayCapabilityQueryFlag;
std::unordered_set<hal::DisplayCapability> mDisplayCapabilities;
@@ -381,6 +383,7 @@
const android::Region& region) = 0;
[[clang::warn_unused_result]] virtual hal::Error setZOrder(uint32_t z) = 0;
[[clang::warn_unused_result]] virtual hal::Error setInfo(uint32_t type, uint32_t appId) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setType(uint32_t type) = 0;
// Composer HAL 2.3
[[clang::warn_unused_result]] virtual hal::Error setColorTransform(
@@ -423,6 +426,7 @@
hal::Error setVisibleRegion(const android::Region& region) override;
hal::Error setZOrder(uint32_t z) override;
hal::Error setInfo(uint32_t type, uint32_t appId) override;
+ hal::Error setType(uint32_t type) override;
// Composer HAL 2.3
hal::Error setColorTransform(const android::mat4& matrix) override;
@@ -449,6 +453,7 @@
android::HdrMetadata mHdrMetadata;
android::mat4 mColorMatrix;
uint32_t mBufferSlot;
+ uint32_t mType{0};
};
} // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 7a2f0f3..910f99d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -381,7 +381,11 @@
? DisplayConnectionType::Internal
: DisplayConnectionType::External;
- RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE);
+ if (error != hal::Error::NONE) {
+ ALOGV("%s failed with error %s", __FUNCTION__, to_string(error).c_str());
+ return FALLBACK_TYPE;
+ }
+
return type;
}
@@ -585,6 +589,7 @@
return NO_ERROR;
}
+ displayData.lastPresentFence = Fence::NO_FENCE;
auto error = hwcDisplay->present(&displayData.lastPresentFence);
RETURN_IF_HWC_ERROR_FOR("present", error, displayId, UNKNOWN_ERROR);
@@ -606,10 +611,6 @@
return INVALID_OPERATION;
}
- if (mode == hal::PowerMode::OFF) {
- setVsyncEnabled(displayId, hal::Vsync::DISABLE);
- }
-
auto& hwcDisplay = displayData.hwcDisplay;
switch (mode) {
case hal::PowerMode::OFF:
@@ -1000,6 +1001,16 @@
return mComposer->getMaxVirtualDisplayCount();
}
+status_t HWComposer::setDisplayElapseTime(DisplayId displayId, uint64_t timeStamp) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto& displayData = mDisplayData[displayId];
+
+ auto error = displayData.hwcDisplay->setDisplayElapseTime(timeStamp);
+ if (error == hal::Error::BAD_PARAMETER) RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return NO_ERROR;
+}
+
} // namespace impl
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index c355ebd..eb90ab2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -223,6 +223,7 @@
virtual std::optional<DisplayId> toPhysicalDisplayId(hal::HWDisplayId hwcDisplayId) const = 0;
virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(DisplayId displayId) const = 0;
+ virtual status_t setDisplayElapseTime(DisplayId displayId, uint64_t timeStamp) = 0;
};
namespace impl {
@@ -319,6 +320,7 @@
bool onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) override;
void setVsyncEnabled(DisplayId displayId, hal::Vsync enabled) override;
+ status_t setDisplayElapseTime(DisplayId displayId, uint64_t timeStamp) override;
nsecs_t getRefreshTimestamp(DisplayId displayId) const override;
bool isConnected(DisplayId displayId) const override;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 4b4c050..4f93996 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -127,6 +127,14 @@
}
}
+bool PowerAdvisor::canNotifyDisplayUpdateImminent() {
+ bool canNotify = mSendUpdateImminent.load();
+ if (mUseUpdateImminentTimer) {
+ mUpdateImminentTimer.reset();
+ }
+ return canNotify;
+}
+
class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
public:
HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 95eb0e2..c94423c 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -34,6 +34,7 @@
virtual void onBootFinished() = 0;
virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
virtual void notifyDisplayUpdateImminent() = 0;
+ virtual bool canNotifyDisplayUpdateImminent() = 0;
};
namespace impl {
@@ -56,6 +57,7 @@
void onBootFinished() override;
void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
void notifyDisplayUpdateImminent() override;
+ bool canNotifyDisplayUpdateImminent() override;
private:
HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index fba3261..aa368f7 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -62,7 +62,7 @@
const sp<IGraphicBufferProducer>& sink,
const sp<IGraphicBufferProducer>& bqProducer,
const sp<IGraphicBufferConsumer>& bqConsumer,
- const std::string& name)
+ const std::string& name, bool secure)
: ConsumerBase(bqConsumer),
mHwc(hwc),
mDisplayId(displayId),
@@ -84,7 +84,9 @@
mDbgState(DBG_STATE_IDLE),
mDbgLastCompositionType(COMPOSITION_UNKNOWN),
mMustRecompose(false),
- mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) {
+ mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv),
+ mSecure(secure),
+ mSinkUsage(0) {
mSource[SOURCE_SINK] = sink;
mSource[SOURCE_SCRATCH] = bqProducer;
@@ -102,6 +104,8 @@
// on usage bits.
int sinkUsage;
sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage);
+ mSinkUsage |= (GRALLOC_USAGE_HW_COMPOSER | sinkUsage);
+ setOutputUsage(mSinkUsage);
if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
int sinkFormat;
sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat);
@@ -130,7 +134,11 @@
}
mMustRecompose = mustRecompose;
-
+ //For WFD use cases we must always set the recompose flag in order
+ //to support pause/resume functionality
+ if (mOutputUsage & GRALLOC_USAGE_HW_VIDEO_ENCODER) {
+ mMustRecompose = true;
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
"Unexpected beginFrame() in %s state", dbgStateStr());
mDbgState = DBG_STATE_BEGUN;
@@ -167,7 +175,7 @@
}
if (mCompositionType != COMPOSITION_GPU &&
- (mOutputFormat != mDefaultOutputFormat || mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) {
+ (mOutputFormat != mDefaultOutputFormat || !(mOutputUsage & GRALLOC_USAGE_HW_COMPOSER))) {
// We must have just switched from GPU-only to MIXED or HWC
// composition. Stop using the format and usage requested by the GPU
// driver; they may be suboptimal when HWC is writing to the output
@@ -179,7 +187,7 @@
// format/usage and get a new buffer when the GPU driver calls
// dequeueBuffer().
mOutputFormat = mDefaultOutputFormat;
- mOutputUsage = GRALLOC_USAGE_HW_COMPOSER;
+ setOutputUsage(GRALLOC_USAGE_HW_COMPOSER);
refreshOutputBuffer();
}
@@ -261,7 +269,7 @@
int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
QueueBufferOutput qbo;
VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
- if (mMustRecompose) {
+ if (retireFence->isValid() && mMustRecompose) {
status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
QueueBufferInput(
systemTime(), false /* isAutoTimestamp */,
@@ -323,7 +331,15 @@
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
- LOG_FATAL_IF(!mDisplayId);
+ LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
+
+ // Exclude video encoder usage flag from scratch buffer usage flags.
+ if (source == SOURCE_SCRATCH) {
+ usage |= GRALLOC_USAGE_HW_FB;
+ usage &= ~(GRALLOC_USAGE_HW_VIDEO_ENCODER);
+ VDS_LOGV("dequeueBuffer(%s): updated scratch buffer usage flags=%#" PRIx64,
+ dbgSourceStr(source), usage);
+ }
status_t result =
mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
@@ -350,11 +366,11 @@
}
}
if (result & BUFFER_NEEDS_REALLOCATION) {
- result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
- if (result < 0) {
+ auto status = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
+ if (status < 0) {
mProducerBuffers[pslot].clear();
mSource[source]->cancelBuffer(*sslot, *fence);
- return result;
+ return status;
}
VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64,
dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
@@ -414,7 +430,7 @@
mSinkBufferWidth, mSinkBufferHeight,
buf->getPixelFormat(), buf->getUsage());
mOutputFormat = format;
- mOutputUsage = usage;
+ setOutputUsage(usage);
result = refreshOutputBuffer();
if (result < 0)
return result;
@@ -695,6 +711,21 @@
}
}
+/* Helper to update the output usage when the display is secure */
+
+void VirtualDisplaySurface::setOutputUsage(uint64_t /*flag*/) {
+
+ mOutputUsage = mSinkUsage;
+ if (mSecure && (mOutputUsage & GRALLOC_USAGE_HW_VIDEO_ENCODER)) {
+ /*TODO: Currently, the framework can only say whether the display
+ * and its subsequent session are secure or not. However, there is
+ * no mechanism to distinguish the different levels of security.
+ * The current solution assumes WV L3 protection.
+ */
+ mOutputUsage |= GRALLOC_USAGE_PROTECTED;
+ }
+}
+
// ---------------------------------------------------------------------------
} // namespace android
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 3cbad8f..337e91e 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -80,7 +80,8 @@
VirtualDisplaySurface(HWComposer& hwc, const std::optional<DisplayId>& displayId,
const sp<IGraphicBufferProducer>& sink,
const sp<IGraphicBufferProducer>& bqProducer,
- const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name);
+ const sp<IGraphicBufferConsumer>& bqConsumer,
+ const std::string& name, bool secure);
//
// DisplaySurface interface
@@ -131,6 +132,7 @@
sp<Fence>* outFence, float outTransformMatrix[16]) override;
virtual status_t getUniqueId(uint64_t* outId) const override;
virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+ virtual void setOutputUsage(uint64_t flag);
//
// Utility methods
@@ -256,6 +258,8 @@
compositionengine::impl::HwcBufferCache mHwcBufferCache;
bool mForceHwcCopy;
+ bool mSecure;
+ int mSinkUsage;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 8ad805b..134bd4b 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -101,6 +101,27 @@
}
}
+nsecs_t FrameTracker::getPreviousGfxInfo() {
+ Mutex::Autolock lock(mMutex);
+ size_t previous = -1;
+ if (mOffset > 0) {
+ previous = (mOffset-1) % NUM_FRAME_RECORDS;
+ } else if (mOffset == 0) {
+ previous = NUM_FRAME_RECORDS - 1;
+ }
+ if (previous >= 0) {
+ nsecs_t desiredPresentTime = mFrameRecords[previous].desiredPresentTime;
+ const std::shared_ptr<FenceTime>& rfence = mFrameRecords[previous].frameReadyFence;
+ if (rfence != nullptr) {
+ nsecs_t frameReadyTime = rfence->getSignalTime();
+ if (desiredPresentTime != INT64_MAX && frameReadyTime != INT64_MAX) {
+ return (frameReadyTime - desiredPresentTime);
+ }
+ }
+ }
+ return INT64_MAX;
+}
+
void FrameTracker::clearStats() {
Mutex::Autolock lock(mMutex);
for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index 35382be..c552620 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -89,6 +89,9 @@
// dumpStats dump appends the current frame display time history to the result string.
void dumpStats(std::string& result) const;
+ //get previous frame gfx info.
+ nsecs_t getPreviousGfxInfo();
+
private:
struct FrameRecord {
FrameRecord() :
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6fe5ce5..9f933d8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -67,9 +67,18 @@
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
+#include "QtiGralloc.h"
+
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+#include <config/client_interface.h>
+namespace DisplayConfig {
+ class ClientInterface;
+}
+#endif
#define DEBUG_RESIZE 0
+using android::hardware::graphics::common::V1_0::BufferUsage;
namespace android {
using base::StringAppendF;
@@ -138,6 +147,8 @@
mCallingPid = args.callingPid;
mCallingUid = args.callingUid;
+ mDontScreenShot = args.metadata.getInt32(METADATA_WINDOW_TYPE_DONT_SCREENSHOT, 0) ?
+ true : false;
}
void Layer::onFirstRef() {
@@ -493,9 +504,13 @@
compositionState->geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse();
compositionState->geomUsesSourceCrop = usesSourceCrop();
compositionState->isSecure = isSecure();
+ compositionState->isSecureDisplay = isSecureDisplay();
+ compositionState->isSecureCamera = isSecureCamera();
+ compositionState->isScreenshot = isScreenshot();
compositionState->type = type;
compositionState->appId = appId;
+ compositionState->layerClass = mLayerClass;
compositionState->metadata.clear();
const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
@@ -772,6 +787,23 @@
return (s.flags & layer_state_t::eLayerSecure);
}
+bool Layer::isSecureDisplay() const {
+ sp<const GraphicBuffer> buffer = getBuffer();
+ return buffer && (buffer->getUsage() & GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY);
+}
+
+bool Layer::isSecureCamera() const {
+ sp<const GraphicBuffer> buffer = getBuffer();
+ bool protected_buffer = buffer && (buffer->getUsage() & BufferUsage::PROTECTED);
+ bool camera_output = buffer && (buffer->getUsage() & BufferUsage::CAMERA_OUTPUT);
+ return protected_buffer && camera_output;
+}
+
+bool Layer::isScreenshot() const {
+ return ((getName().find("ScreenshotSurface") != std::string::npos) ||
+ (getName().find("RotationLayer") != std::string::npos) ||
+ (getName().find("BackColorSurface") != std::string::npos));
+}
// ----------------------------------------------------------------------------
// transaction
// ----------------------------------------------------------------------------
@@ -1333,17 +1365,23 @@
int32_t Layer::getFrameRateSelectionPriority() const {
// Check if layer has priority set.
if (mDrawingState.frameRateSelectionPriority != PRIORITY_UNSET) {
- return mDrawingState.frameRateSelectionPriority;
+ mPriority = mDrawingState.frameRateSelectionPriority;
+ return mPriority;
}
// If not, search whether its parents have it set.
sp<Layer> parent = getParent();
if (parent != nullptr) {
- return parent->getFrameRateSelectionPriority();
+ mPriority = parent->getFrameRateSelectionPriority();
+ return mPriority;
}
return Layer::PRIORITY_UNSET;
}
+int32_t Layer::getPriority() {
+ return mPriority;
+}
+
bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) {
return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
};
@@ -1464,6 +1502,13 @@
void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
ATRACE_CALL();
+ if (mLayerDetached) {
+ // If the layer is detached, then we don't defer this transaction since we will not
+ // commit the pending state while the layer is detached. Adding sync points may cause
+ // the barrier layer to wait for the states to be committed before dequeuing a buffer.
+ return;
+ }
+
mCurrentState.barrierLayer_legacy = barrierLayer;
mCurrentState.frameNumber_legacy = frameNumber;
// We don't set eTransactionNeeded, because just receiving a deferral
@@ -1510,6 +1555,36 @@
if (mPotentialCursor) {
usage |= GraphicBuffer::USAGE_CURSOR;
}
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ if (mDontScreenShot) {
+ // This is a WINDOW_TYPE_DONT_SCREENSHOT "mask" layer which needs to be CPU-read for
+ // special processing and programming of mask h/w IF the feature is supported.
+ static bool rc_supported = false;
+ static int read_rc_supported = true;
+ if (read_rc_supported) {
+ // Do this once per process lifetime.
+ read_rc_supported = false;
+ ::DisplayConfig::ClientInterface *DisplayConfigIntf = nullptr;
+ ::DisplayConfig::ClientInterface::Create("SurfaceFlinger::Layer" + std::to_string(0),
+ nullptr, &DisplayConfigIntf);
+ if (DisplayConfigIntf) {
+ std::string value = "0";
+ std::string rc_prop = "enable_rc_support";
+ int ret = DisplayConfigIntf->GetDebugProperty(rc_prop, &value);
+ ALOGI("enable_rc_support, ret:%d value:%s", ret, value.c_str());
+ if (!ret && (value == "1")) {
+ DisplayConfigIntf->IsRCSupported(0, &rc_supported);
+ }
+ ::DisplayConfig::ClientInterface::Destroy(DisplayConfigIntf);
+ }
+ ALOGI("Mask layers are %sCPU-readable.", rc_supported ? "" : "*NOT* ");
+ }
+ if (rc_supported) {
+ usage |= GraphicBuffer::USAGE_SW_READ_RARELY;
+ usage |= GraphicBuffer::USAGE_SW_WRITE_RARELY;
+ }
+ }
+#endif // QTI_DISPLAY_CONFIG_ENABLED
usage |= GraphicBuffer::USAGE_HW_COMPOSER;
return usage;
}
@@ -1585,6 +1660,7 @@
result.append(" Layer name\n");
result.append(" Z | ");
result.append(" Window Type | ");
+ result.append(" Layer Class | ");
result.append(" Comp Type | ");
result.append(" Transform | ");
result.append(" Disp Frame (LTRB) | ");
@@ -1636,6 +1712,7 @@
StringAppendF(&result, " %10d | ", layerState.z);
}
StringAppendF(&result, " %10d | ", mWindowType);
+ StringAppendF(&result, " %10d | ", mLayerClass);
StringAppendF(&result, "%10s | ", toString(getCompositionType(display)).c_str());
StringAppendF(&result, "%10s | ", toString(outputLayerState.bufferTransform).c_str());
const Rect& frame = outputLayerState.displayFrame;
@@ -2453,14 +2530,36 @@
xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
- layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
+ // inset while protecting from overflow TODO(b/161235021): What is going wrong
+ // in the overflow scenario?
+ {
+ int32_t tmp;
+ if (!__builtin_add_overflow(layerBounds.left, xSurfaceInset, &tmp)) layerBounds.left = tmp;
+ if (!__builtin_sub_overflow(layerBounds.right, xSurfaceInset, &tmp)) layerBounds.right = tmp;
+ if (!__builtin_add_overflow(layerBounds.top, ySurfaceInset, &tmp)) layerBounds.top = tmp;
+ if (!__builtin_sub_overflow(layerBounds.bottom, ySurfaceInset, &tmp)) layerBounds.bottom = tmp;
+ }
// Input coordinate should match the layer bounds.
info.frameLeft = layerBounds.left;
info.frameTop = layerBounds.top;
info.frameRight = layerBounds.right;
info.frameBottom = layerBounds.bottom;
-
+ // validate layer bound before access
+ //layer = #1
+ //layerBounds l = 2147483647 t = -2147483648 r = 2147483647 b = -2147483648
+ //Todo: Need to fix at framework level.
+ if (info.frameLeft > INT16_MAX || info.frameTop > INT16_MAX ||
+ info.frameRight > INT16_MAX || info.frameBottom > INT16_MAX ||
+ info.frameLeft < INT16_MIN || info.frameTop < INT16_MIN ||
+ info.frameRight < INT16_MIN || info.frameBottom < INT16_MIN) {
+ ALOGE("Layer %s left = %d top = %d right = %d bottom = %d", getName().c_str(),
+ info.frameLeft, info.frameTop, info.frameRight, info.frameBottom);
+ info.frameLeft = 0;
+ info.frameTop = 0;
+ info.frameRight = 0;
+ info.frameBottom = 0;
+ }
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6c5d114..1232185 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -418,6 +418,7 @@
// If the variable is not set on the layer, it traverses up the tree to inherit the frame
// rate priority from its parent.
virtual int32_t getFrameRateSelectionPriority() const;
+ int32_t getPriority();
static bool isLayerFocusedBasedOnPriority(int32_t priority);
virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; }
@@ -496,6 +497,10 @@
*/
bool isSecure() const;
+ bool isSecureCamera() const;
+ bool isSecureDisplay() const;
+ bool isScreenshot() const;
+
/*
* isVisible - true if this layer is visible, false otherwise
*/
@@ -978,9 +983,9 @@
*/
virtual bool needsInputInfo() const { return hasInputInfo(); }
-protected:
compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const;
+protected:
bool usingRelativeZ(LayerVector::StateSet stateSet) const;
bool mPremultipliedAlpha{true};
@@ -988,6 +993,7 @@
const std::string mTransactionName{"TX - " + mName};
bool mPrimaryDisplayOnly = false;
+ bool mDontScreenShot = false;
// These are only accessed by the main thread or the tracing thread.
State mDrawingState;
@@ -1010,6 +1016,8 @@
FenceTimeline mAcquireTimeline;
FenceTimeline mReleaseTimeline;
+ uint32_t mLayerClass{0};
+
// main thread
sp<NativeHandle> mSidebandStream;
// False if the buffer and its contents have been previously used for GPU
@@ -1114,6 +1122,8 @@
// shadow radius is the set shadow radius, otherwise its the parent's shadow radius.
float mEffectiveShadowRadius = 0.f;
+ mutable int32_t mPriority = Layer::PRIORITY_UNSET;
+
// Returns true if the layer can draw shadows on its border.
virtual bool canDrawShadows() const { return true; }
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 18a2891..a0441ae 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -58,6 +58,12 @@
PixelFormat format, uint64_t usage,
uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
+ if (mFlinger->mDolphinFuncsEnabled) {
+ sp<Layer> layer = mLayer.promote();
+ if (layer != nullptr) {
+ mFlinger->mDolphinDequeueBuffer(layer->getName().c_str());
+ }
+ }
return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps);
}
@@ -77,6 +83,12 @@
status_t MonitoredProducer::queueBuffer(int slot, const QueueBufferInput& input,
QueueBufferOutput* output) {
+ if (mFlinger->mDolphinFuncsEnabled) {
+ sp<Layer> layer = mLayer.promote();
+ if (layer != nullptr) {
+ mFlinger->mDolphinQueueBuffer(layer->getName().c_str());
+ }
+ }
return mProducer->queueBuffer(slot, input, output);
}
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index ff91bf7..5c2bf61 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -671,7 +671,11 @@
nsecs_t DispSync::getPeriod() {
// lock mutex as mPeriod changes multiple times in updateModelLocked
Mutex::Autolock lock(mMutex);
- return mPeriod;
+ if (mPendingPeriod && !mModelUpdated) {
+ return mPendingPeriod;
+ } else {
+ return mPeriod;
+ }
}
void DispSync::updateModelLocked() {
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 8752b66..62c2066 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -23,6 +23,7 @@
#include "DispSyncSource.h"
#include <android-base/stringprintf.h>
+#include <dlfcn.h>
#include <utils/Trace.h>
#include <mutex>
@@ -39,7 +40,21 @@
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset) {}
+ mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset) {
+ mDolphinHandle = dlopen("libdolphin.so", RTLD_NOW);
+ if (!mDolphinHandle) {
+ ALOGW("Unable to open libdolphin.so: %s.", dlerror());
+ } else {
+ mDolphinCheck = (bool (*) (const char*))dlsym(mDolphinHandle, "dolphinCheck");
+ if (!mDolphinCheck)
+ dlclose(mDolphinHandle);
+ }
+}
+
+DispSyncSource::~DispSyncSource() {
+ if(mDolphinCheck)
+ dlclose(mDolphinHandle);
+}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
@@ -58,6 +73,16 @@
ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err);
}
// ATRACE_INT(mVsyncOnLabel.c_str(), 0);
+ if (mDolphinCheck) {
+ if (mDolphinCheck(mName)) {
+ status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
+ static_cast<DispSync::Callback*>(this),
+ mLastCallbackTime);
+ if (err != NO_ERROR) {
+ ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err);
+ }
+ }
+ }
}
mEnabled = enable;
}
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 2aee3f6..cd54b63 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -28,7 +28,7 @@
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
- ~DispSyncSource() override = default;
+ ~DispSyncSource();
// The following methods are implementation of VSyncSource.
const char* getName() const override { return mName; }
@@ -57,6 +57,8 @@
mutable std::mutex mVsyncMutex;
TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
+ void *mDolphinHandle = nullptr;
+ bool (*mDolphinCheck)(const char* name) = nullptr;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index cf57664..d4ded0a 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -20,6 +20,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <dlfcn.h>
#include <pthread.h>
#include <sched.h>
#include <sys/types.h>
@@ -125,7 +126,7 @@
: resyncCallback(std::move(resyncCallback)),
mConfigChanged(configChanged),
mEventThread(eventThread),
- mChannel(gui::BitTube::DefaultSize) {}
+ mChannel(gui::BitTube(8 * 1024 /* default size is 4KB, double it */)) {}
EventThreadConnection::~EventThreadConnection() {
// do nothing here -- clean-up will happen automatically
@@ -144,6 +145,7 @@
}
outChannel->setReceiveFd(mChannel.moveReceiveFd());
+ outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
return NO_ERROR;
}
@@ -157,11 +159,6 @@
mEventThread->requestNextVsync(this);
}
-void EventThreadConnection::requestLatestConfig() {
- ATRACE_NAME("requestLatestConfig");
- mEventThread->requestLatestConfig(this);
-}
-
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
@@ -198,10 +195,20 @@
}
set_sched_policy(tid, SP_FOREGROUND);
+ mDolphinHandle = dlopen("libdolphin.so", RTLD_NOW);
+ if (!mDolphinHandle) {
+ ALOGW("Unable to open libdolphin.so: %s.", dlerror());
+ } else {
+ mDolphinCheck = (bool (*) (const char*))dlsym(mDolphinHandle, "dolphinCheck");
+ if (!mDolphinCheck)
+ dlclose(mDolphinHandle);
+ }
}
EventThread::~EventThread() {
mVSyncSource->setCallback(nullptr);
+ if(mDolphinCheck)
+ dlclose(mDolphinHandle);
{
std::lock_guard<std::mutex> lock(mMutex);
@@ -274,28 +281,6 @@
}
}
-void EventThread::requestLatestConfig(const sp<EventThreadConnection>& connection) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (connection->mForcedConfigChangeDispatch) {
- return;
- }
- connection->mForcedConfigChangeDispatch = true;
- auto pendingConfigChange =
- std::find_if(std::begin(mPendingEvents), std::end(mPendingEvents),
- [&](const DisplayEventReceiver::Event& event) {
- return event.header.type ==
- DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED;
- });
-
- // If we didn't find a pending config change event, then push out the
- // latest one we've ever seen.
- if (pendingConfigChange == std::end(mPendingEvents)) {
- mPendingEvents.push_back(mLastConfigChangeEvent);
- }
-
- mCondition.notify_all();
-}
-
void EventThread::onScreenReleased() {
std::lock_guard<std::mutex> lock(mMutex);
if (!mVSyncState || mVSyncState->synthetic) {
@@ -371,14 +356,12 @@
mInterceptVSyncsCallback(event->header.timestamp);
}
break;
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
- mLastConfigChangeEvent = *event;
- break;
}
}
bool vsyncRequested = false;
+ int aliveCount = 0;
// Find connections that should consume this event.
auto it = mDisplayEventConnections.begin();
while (it != mDisplayEventConnections.end()) {
@@ -386,11 +369,9 @@
vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
if (event && shouldConsumeEvent(*event, connection)) {
- if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED &&
- connection->mForcedConfigChangeDispatch) {
- connection->mForcedConfigChangeDispatch = false;
- }
consumers.push_back(connection);
+ if (mDolphinCheck)
+ aliveCount++;
}
++it;
@@ -398,6 +379,21 @@
it = mDisplayEventConnections.erase(it);
}
}
+ if (mDolphinCheck) {
+ if (event && aliveCount == 0 && mDolphinCheck(mThreadName)) {
+ auto it = mDisplayEventConnections.begin();
+ while (it != mDisplayEventConnections.end() && aliveCount == 0) {
+ if (const auto connection = it->promote()) {
+ consumers.push_back(connection);
+ aliveCount++;
+ mVSyncSource->setVSyncEnabled(false);
+ ++it;
+ } else {
+ it = mDisplayEventConnections.erase(it);
+ }
+ }
+ }
+ }
if (!consumers.empty()) {
dispatchEvent(*event, consumers);
@@ -465,9 +461,7 @@
return true;
case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
- const bool oneTimeDispatch = connection->mForcedConfigChangeDispatch;
- return oneTimeDispatch ||
- connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
+ return connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
}
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
@@ -490,20 +484,26 @@
void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
const DisplayEventConsumers& consumers) {
+ const uint8_t num_attempts = 3;
for (const auto& consumer : consumers) {
- switch (consumer->postEvent(event)) {
- case NO_ERROR:
- break;
+ bool needs_retry = true;
+ for (uint8_t attempt = 0; needs_retry && (attempt < num_attempts); attempt++) {
+ switch (consumer->postEvent(event)) {
+ case NO_ERROR:
+ needs_retry = false;
+ break;
- case -EAGAIN:
- // TODO: Try again if pipe is full.
- ALOGW("Failed dispatching %s for %s", toString(event).c_str(),
- toString(*consumer).c_str());
- break;
+ case -EAGAIN:
+ ALOGW("Failed dispatching %s for %s. attempt %d", toString(event).c_str(),
+ toString(*consumer).c_str(), attempt+1);
+ needs_retry = true;
+ break;
- default:
- // Treat EPIPE and other errors as fatal.
- removeDisplayEventConnectionLocked(consumer);
+ default:
+ // Treat EPIPE and other errors as fatal.
+ removeDisplayEventConnectionLocked(consumer);
+ needs_retry = false;
+ }
}
}
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 831bf7b..461a26d 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -81,19 +81,13 @@
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t rate) override;
void requestNextVsync() override; // asynchronous
- void requestLatestConfig() override; // asynchronous
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
- ISurfaceComposer::ConfigChanged mConfigChanged =
+ const ISurfaceComposer::ConfigChanged mConfigChanged =
ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;
- // Store whether we need to force dispatching a config change separately -
- // if mConfigChanged ever changes before the config change is dispatched
- // then we still need to propagate an initial config to the app if we
- // haven't already.
- bool mForcedConfigChangeDispatch = false;
private:
virtual void onFirstRef();
@@ -130,10 +124,6 @@
virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
// Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
- // Dispatches the most recent configuration
- // Usage of this method assumes that only the primary internal display
- // supports multiple display configurations.
- virtual void requestLatestConfig(const sp<EventThreadConnection>& connection) = 0;
// Retrieves the number of event connections tracked by this EventThread.
virtual size_t getEventThreadConnectionCount() = 0;
@@ -154,7 +144,6 @@
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
void requestNextVsync(const sp<EventThreadConnection>& connection) override;
- void requestLatestConfig(const sp<EventThreadConnection>& connection) override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
@@ -202,7 +191,6 @@
std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
- DisplayEventReceiver::Event mLastConfigChangeEvent GUARDED_BY(mMutex);
// VSYNC state of connected display.
struct VSyncState {
@@ -232,6 +220,8 @@
State mState GUARDED_BY(mMutex) = State::Idle;
static const char* toCString(State);
+ void *mDolphinHandle = nullptr;
+ bool (*mDolphinCheck)(const char* name) = nullptr;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index 44f20d0..61602d7 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -27,6 +27,7 @@
#undef LOG_TAG
#define LOG_TAG "LayerInfoV2"
+#define MAX_FRAME_TIME 100000000
namespace android::scheduler {
@@ -126,14 +127,19 @@
bool missingPresentTime = false;
int numFrames = 0;
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
+ bool noUpdate = false;
// Ignore frames captured during a config change
if (it->pendingConfigChange || (it + 1)->pendingConfigChange) {
return std::nullopt;
}
-
- totalQueueTimeDeltas +=
- std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod);
- numFrames++;
+ nsecs_t val = std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod);
+ // Only if val < 10,000,000ns (10FPS) add to count.
+ if (val < MAX_FRAME_TIME) {
+ totalQueueTimeDeltas += val;
+ numFrames++;
+ } else {
+ noUpdate = true;
+ }
if (!missingPresentTime && (it->presetTime == 0 || (it + 1)->presetTime == 0)) {
missingPresentTime = true;
@@ -144,9 +150,15 @@
}
continue;
}
-
- totalPresentTimeDeltas +=
- std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
+ // Check threshold here as well
+ val = std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
+ if (val < MAX_FRAME_TIME) {
+ totalPresentTimeDeltas += val;
+ if (noUpdate && !missingPresentTime) {
+ //If queueTime was out of bound but presentTime was in bound, increment numFrames
+ numFrames++;
+ }
+ }
}
// Calculate the average frame time based on presentation timestamps. If those
@@ -157,6 +169,9 @@
// presentation timestamps we look at the queue time to see if the current refresh rate still
// matches the content.
+ if (!numFrames) {
+ return std::nullopt;
+ }
const auto averageFrameTime =
static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) /
numFrames;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 6067e69..e68f03f 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -123,6 +123,7 @@
while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ mFlinger->mVsyncTimeStamp = systemTime(SYSTEM_TIME_MONOTONIC);
mHandler->dispatchInvalidate(buffer[i].vsync.expectedVSyncTimestamp);
break;
}
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index fe2e406..e34f278 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -203,6 +203,23 @@
return getPhaseOffsets(fps, static_cast<nsecs_t>(1e9f / fps));
}
+void PhaseOffsets::UpdateSfOffsets(std::unordered_map<float, int64_t> advancedSfOffsets) {
+ for (auto& item: advancedSfOffsets) {
+ float fps = item.first;
+ auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
+ [&fps](const std::pair<float, Offsets>& candidateFps) {
+ return fpsEqualsWithMargin(fps, candidateFps.first);
+ });
+
+ if (iter != mOffsets.end()) {
+ auto& [early, earlyGl, late] = iter->second;
+ late.sf = item.second;
+ early.sf = item.second;
+ earlyGl.sf = item.second;
+ }
+ }
+}
+
static void validateSysprops() {
const auto validatePropertyBool = [](const char* prop) {
LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
@@ -354,5 +371,9 @@
mAppEarlyGlDuration, mSfEarlyGlDuration);
}
+void PhaseDurations::UpdateSfOffsets(std::unordered_map<float, int64_t> advancedSfOffsets) {
+ ALOGW("UpdateSfOffsets not supported for map with size: %zu", advancedSfOffsets.size());
+}
+
} // namespace impl
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 9ec6d56..b2b25a6 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -41,6 +41,8 @@
virtual void setRefreshRateFps(float fps) = 0;
virtual void dump(std::string& result) const = 0;
+
+ virtual void UpdateSfOffsets(std::unordered_map<float, int64_t> advancedSfOffsets) = 0;
};
namespace impl {
@@ -66,6 +68,9 @@
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
+ // Update the Advanced Sf Offsets for the given refresh rates in mOffsets map.
+ void UpdateSfOffsets(std::unordered_map<float, int64_t> advancedSfOffsets) override;
+
protected:
// Used for unit tests
PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
@@ -86,8 +91,8 @@
const std::optional<nsecs_t> mEarlyAppOffsetNs;
const std::optional<nsecs_t> mEarlyGlAppOffsetNs;
const nsecs_t mThresholdForNextVsync;
- const std::unordered_map<float, Offsets> mOffsets;
+ std::unordered_map<float, Offsets> mOffsets;
std::atomic<float> mRefreshRateFps;
};
@@ -113,6 +118,9 @@
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
+ // Update the Advanced Sf Offsets for the given refresh rates in mOffsets map.
+ void UpdateSfOffsets(std::unordered_map<float, int64_t> advancedSfOffsets) override;
+
protected:
// Used for unit tests
PhaseDurations(const std::vector<float>& refreshRates, float currentFps, nsecs_t sfDuration,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5c0ba01..cca3d57 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -182,29 +182,39 @@
auto vsyncSource = makePrimaryDispSyncSource(connectionName, phaseOffsetNs);
auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
std::move(interceptCallback));
- return createConnection(std::move(eventThread));
+ bool triggerRefresh = !strcmp(connectionName, "app");
+ return createConnection(std::move(eventThread), triggerRefresh);
}
-Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) {
+Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread,
+ bool triggerRefresh) {
const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
auto connection =
- createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
+ createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress,
+ triggerRefresh);
mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
return handle;
}
-sp<EventThreadConnection> Scheduler::createConnectionInternal(
- EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) {
- return eventThread->createEventConnection([&] { resync(); }, configChanged);
+sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
+ ISurfaceComposer::ConfigChanged configChanged, bool triggerRefresh) {
+ // Refresh need to be triggered from app thread alone.
+ // Triggering it from sf connection can result in infinite loop due to requestnextvsync.
+ if (triggerRefresh) {
+ return eventThread->createEventConnection([&] { resyncAndRefresh(); }, configChanged);
+ } else {
+ return eventThread->createEventConnection([&] { resync(); }, configChanged);
+ }
}
-sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- ConnectionHandle handle, ISurfaceComposer::ConfigChanged configChanged) {
+sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(ConnectionHandle handle,
+ ISurfaceComposer::ConfigChanged configChanged, bool triggerRefresh) {
RETURN_IF_INVALID_HANDLE(handle, nullptr);
- return createConnectionInternal(mConnections[handle].thread.get(), configChanged);
+ return createConnectionInternal(mConnections[handle].thread.get(), configChanged,
+ triggerRefresh);
}
sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
@@ -297,7 +307,7 @@
std::make_unique<impl::EventThread>(std::move(vsyncSource),
impl::EventThread::InterceptVSyncsCallback());
- mInjectorConnectionHandle = createConnection(std::move(eventThread));
+ mInjectorConnectionHandle = createConnection(std::move(eventThread), false /* No Refresh */);
}
mInjectVSyncs = enable;
@@ -334,7 +344,7 @@
}
}
-void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
+void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period, bool force_resync) {
{
std::lock_guard<std::mutex> lock(mHWVsyncLock);
if (makeAvailable) {
@@ -350,7 +360,21 @@
return;
}
- setVsyncPeriod(period);
+ setVsyncPeriod(period, force_resync);
+}
+
+void Scheduler::resyncAndRefresh() {
+ resync();
+
+ if (!mDisplayIdle) {
+ return;
+ }
+
+ ATRACE_CALL();
+ const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
+ mSchedulerCallback.repaintEverythingForHWC();
+ resyncToHardwareVsync(true /* makeAvailable */, refreshRate.getVsyncPeriod(), true);
+ mDisplayIdle = false;
}
void Scheduler::resync() {
@@ -364,11 +388,11 @@
}
}
-void Scheduler::setVsyncPeriod(nsecs_t period) {
+void Scheduler::setVsyncPeriod(nsecs_t period, bool force_resync) {
std::lock_guard<std::mutex> lock(mHWVsyncLock);
mPrimaryDispSync->setPeriod(period);
- if (!mPrimaryHWVsyncEnabled) {
+ if (!mPrimaryHWVsyncEnabled || force_resync) {
mPrimaryDispSync->beginResync();
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
@@ -708,4 +732,8 @@
}
}
+void Scheduler::setIdleState() {
+ mDisplayIdle = true;
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 730ea8f..ed735d8 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -87,7 +87,8 @@
impl::EventThread::InterceptVSyncsCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(ConnectionHandle,
- ISurfaceComposer::ConfigChanged);
+ ISurfaceComposer::ConfigChanged,
+ bool triggerRefresh);
sp<EventThreadConnection> getEventConnection(ConnectionHandle);
@@ -119,8 +120,9 @@
// Otherwise, if hardware vsync is not already enabled then this method will
// no-op.
// The period is the vsync period from the current display configuration.
- void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
+ void resyncToHardwareVsync(bool makeAvailable, nsecs_t period, bool force_resync = false);
void resync();
+ void resyncAndRefresh();
// Passes a vsync sample to DispSync. periodFlushed will be true if
// DispSync detected that the vsync period changed, and false otherwise.
@@ -163,6 +165,8 @@
size_t getEventThreadConnectionCount(ConnectionHandle handle);
+ void setIdleState();
+
private:
friend class TestableScheduler;
@@ -180,9 +184,10 @@
std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs);
// Create a connection on the given EventThread.
- ConnectionHandle createConnection(std::unique_ptr<EventThread>);
+ ConnectionHandle createConnection(std::unique_ptr<EventThread>, bool triggerRefresh);
sp<EventThreadConnection> createConnectionInternal(EventThread*,
- ISurfaceComposer::ConfigChanged);
+ ISurfaceComposer::ConfigChanged,
+ bool triggerRefresh);
// Update feature state machine to given state when corresponding timer resets or expires.
void kernelIdleTimerCallback(TimerState);
@@ -194,7 +199,7 @@
template <class T>
bool handleTimerStateChanged(T* currentState, T newState);
- void setVsyncPeriod(nsecs_t period);
+ void setVsyncPeriod(nsecs_t period, bool force_resync = false);
// This function checks whether individual features that are affecting the refresh rate
// selection were initialized, prioritizes them, and calculates the HwcConfigIndexType
@@ -279,6 +284,8 @@
const bool mUseContentDetection;
// This variable indicates whether to use V2 version of the content detection.
const bool mUseContentDetectionV2;
+ // This flag indicates display in idle. Refresh as and when vsync is requested.
+ bool mDisplayIdle;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index a596bce..2a6fd05 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -243,7 +243,8 @@
std::vector<Invocation> invocations;
{
std::lock_guard<decltype(mMutex)> lk(mMutex);
- mLastTimerCallback = mTimeKeeper->now();
+ auto const now = mTimeKeeper->now();
+ mLastTimerCallback = now;
for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
auto& callback = it->second;
auto const wakeupTime = callback->wakeupTime();
@@ -251,7 +252,8 @@
continue;
}
- if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
+ auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
+ if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
callback->executing();
invocations.emplace_back(
Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime});
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index ab5773d..61f3fbb 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -255,21 +255,9 @@
}
}
-bool VSyncPredictor::needsMoreSamples(nsecs_t now) const {
- using namespace std::literals::chrono_literals;
+bool VSyncPredictor::needsMoreSamples() const {
std::lock_guard<std::mutex> lk(mMutex);
- bool needsMoreSamples = true;
- if (mTimestamps.size() >= kMinimumSamplesForPrediction) {
- nsecs_t constexpr aLongTime =
- std::chrono::duration_cast<std::chrono::nanoseconds>(500ms).count();
- if (!(mLastTimestampIndex < 0 || mTimestamps.empty())) {
- auto const lastTimestamp = mTimestamps[mLastTimestampIndex];
- needsMoreSamples = !((lastTimestamp + aLongTime) > now);
- }
- }
-
- ATRACE_INT("VSP-moreSamples", needsMoreSamples);
- return needsMoreSamples;
+ return mTimestamps.size() < kMinimumSamplesForPrediction;
}
void VSyncPredictor::resetModel() {
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 3ca878d..5f3c418 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -52,11 +52,10 @@
*/
void setPeriod(nsecs_t period) final;
- /* Query if the model is in need of more samples to make a prediction at timePoint.
- * \param [in] timePoint The timePoint to inquire of.
+ /* Query if the model is in need of more samples to make a prediction.
* \return True, if model would benefit from more samples, False if not.
*/
- bool needsMoreSamples(nsecs_t timePoint) const;
+ bool needsMoreSamples() const final;
std::tuple<nsecs_t /* slope */, nsecs_t /* intercept */> getVSyncPredictionModel() const;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index c743de0..efa8bab 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -233,6 +233,7 @@
}
void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) {
+ ATRACE_CALL();
mPeriodConfirmationInProgress = true;
mPeriodTransitioningTo = newPeriod;
mMoreSamplesNeeded = true;
@@ -240,8 +241,7 @@
}
void VSyncReactor::endPeriodTransition() {
- setIgnorePresentFencesInternal(false);
- mMoreSamplesNeeded = false;
+ ATRACE_CALL();
mPeriodTransitioningTo.reset();
mPeriodConfirmationInProgress = false;
mLastHwVsync.reset();
@@ -254,6 +254,8 @@
if (!mSupportKernelIdleTimer && period == getPeriod()) {
endPeriodTransition();
+ setIgnorePresentFencesInternal(false);
+ mMoreSamplesNeeded = false;
} else {
startPeriodTransition(period);
}
@@ -303,6 +305,7 @@
std::lock_guard<std::mutex> lk(mMutex);
if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
+ ATRACE_NAME("VSR: period confirmed");
if (mPeriodTransitioningTo) {
mTracker->setPeriod(*mPeriodTransitioningTo);
for (auto& entry : mCallbacks) {
@@ -310,17 +313,29 @@
}
*periodFlushed = true;
}
+
+ if (mLastHwVsync) {
+ mTracker->addVsyncTimestamp(*mLastHwVsync);
+ }
+ mTracker->addVsyncTimestamp(timestamp);
+
endPeriodTransition();
+ mMoreSamplesNeeded = mTracker->needsMoreSamples();
} else if (mPeriodConfirmationInProgress) {
+ ATRACE_NAME("VSR: still confirming period");
mLastHwVsync = timestamp;
mMoreSamplesNeeded = true;
*periodFlushed = false;
} else {
- mMoreSamplesNeeded = false;
+ ATRACE_NAME("VSR: adding sample");
*periodFlushed = false;
+ mTracker->addVsyncTimestamp(timestamp);
+ mMoreSamplesNeeded = mTracker->needsMoreSamples();
}
- mTracker->addVsyncTimestamp(timestamp);
+ if (!mMoreSamplesNeeded) {
+ setIgnorePresentFencesInternal(false);
+ }
return mMoreSamplesNeeded;
}
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 05a6fc3..107c540 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -66,6 +66,8 @@
/* Inform the tracker that the samples it has are not accurate for prediction. */
virtual void resetModel() = 0;
+ virtual bool needsMoreSamples() const = 0;
+
virtual void dump(std::string& result) const = 0;
protected:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 14da0c5..bcd14c0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -65,6 +65,8 @@
#include <renderengine/RenderEngine.h>
#include <statslog.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <fstream>
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayConfig.h>
@@ -126,6 +128,19 @@
#include "TimeStats/TimeStats.h"
#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
+#include <composer_extn_intf.h>
+
+#include "frame_extn_intf.h"
+#include "smomo_interface.h"
+#include "QtiGralloc.h"
+#include "layer_extn_intf.h"
+
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+#include <config/client_interface.h>
+namespace DisplayConfig {
+class ClientInterface;
+}
+#endif
#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
@@ -136,9 +151,20 @@
return (expr); \
}()
-#undef NO_THREAD_SAFETY_ANALYSIS
-#define NO_THREAD_SAFETY_ANALYSIS \
- _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
+// TODO(b/157175504): Restore NO_THREAD_SAFETY_ANALYSIS prohibition and fix all
+// identified issues.
+//#undef NO_THREAD_SAFETY_ANALYSIS
+//#define NO_THREAD_SAFETY_ANALYSIS \
+// _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
+
+composer::ComposerExtnLib composer::ComposerExtnLib::g_composer_ext_lib_;
+
+#ifdef PHASE_OFFSET_EXTN
+struct ComposerExtnIntf {
+ composer::PhaseOffsetExtnIntf *phaseOffsetExtnIntf = nullptr;
+};
+struct ComposerExtnIntf g_comp_ext_intf_;
+#endif
namespace android {
@@ -251,6 +277,20 @@
std::function<void()> mCallback;
};
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+class DisplayConfigCallbackHandler : public ::DisplayConfig::ConfigCallback {
+public:
+ DisplayConfigCallbackHandler(SurfaceFlinger& flinger) : mFlinger(flinger) {
+ }
+ void NotifyIdleStatus(bool is_idle) {
+ ALOGV("received idle notification");
+ ATRACE_CALL();
+ mFlinger.NotifyIdleStatus();
+ }
+ private:
+ SurfaceFlinger& mFlinger;
+};
+#endif
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -279,7 +319,11 @@
Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
bool SurfaceFlinger::useFrameRateApi;
-
+bool SurfaceFlinger::sDirectStreaming;
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+::DisplayConfig::ClientInterface *mDisplayConfigIntf = nullptr;
+DisplayConfigCallbackHandler *mDisplayConfigCallbackhandler = nullptr;
+#endif
std::string getHwcServiceName() {
char value[PROPERTY_VALUE_MAX] = {};
property_get("debug.sf.hwc_service_name", value, "default");
@@ -310,6 +354,84 @@
SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
+bool SmomoWrapper::init() {
+ mSmoMoLibHandle = dlopen(SMOMO_LIBRARY_NAME, RTLD_NOW);
+ if (!mSmoMoLibHandle) {
+ ALOGE("Unable to open SmoMo lib: %s", dlerror());
+ return false;
+ }
+
+ mSmoMoCreateFunc =
+ reinterpret_cast<CreateSmoMoFuncPtr>(dlsym(mSmoMoLibHandle,
+ CREATE_SMOMO_INTERFACE_NAME));
+ mSmoMoDestroyFunc =
+ reinterpret_cast<DestroySmoMoFuncPtr>(dlsym(mSmoMoLibHandle,
+ DESTROY_SMOMO_INTERFACE_NAME));
+
+ if (!mSmoMoCreateFunc || !mSmoMoDestroyFunc) {
+ ALOGE("Can't load SmoMo symbols: %s", dlerror());
+ dlclose(mSmoMoLibHandle);
+ return false;
+ }
+
+ if (!mSmoMoCreateFunc(SMOMO_VERSION_TAG, &mInst)) {
+ ALOGE("Unable to create SmoMo interface");
+ dlclose(mSmoMoLibHandle);
+ return false;
+ }
+
+ return true;
+}
+
+SmomoWrapper::~SmomoWrapper() {
+ if (mInst) {
+ mSmoMoDestroyFunc(mInst);
+ }
+
+ if (mSmoMoLibHandle) {
+ dlclose(mSmoMoLibHandle);
+ }
+}
+
+bool LayerExtWrapper::init() {
+ mLayerExtLibHandle = dlopen(LAYER_EXTN_LIBRARY_NAME, RTLD_NOW);
+ if (!mLayerExtLibHandle) {
+ ALOGE("Unable to open layer ext lib: %s", dlerror());
+ return false;
+ }
+
+ mLayerExtCreateFunc =
+ reinterpret_cast<CreateLayerExtnFuncPtr>(dlsym(mLayerExtLibHandle,
+ CREATE_LAYER_EXTN_INTERFACE));
+ mLayerExtDestroyFunc =
+ reinterpret_cast<DestroyLayerExtnFuncPtr>(dlsym(mLayerExtLibHandle,
+ DESTROY_LAYER_EXTN_INTERFACE));
+
+ if (!mLayerExtCreateFunc || !mLayerExtDestroyFunc) {
+ ALOGE("Can't load layer ext symbols: %s", dlerror());
+ dlclose(mLayerExtLibHandle);
+ return false;
+ }
+
+ if (!mLayerExtCreateFunc(LAYER_EXTN_VERSION_TAG, &mInst)) {
+ ALOGE("Unable to create layer ext interface");
+ dlclose(mLayerExtLibHandle);
+ return false;
+ }
+
+ return true;
+}
+
+LayerExtWrapper::~LayerExtWrapper() {
+ if (mInst) {
+ mLayerExtDestroyFunc(mInst);
+ }
+
+ if (mLayerExtLibHandle) {
+ dlclose(mLayerExtLibHandle);
+ }
+}
+
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
mInterceptor(mFactory.createSurfaceInterceptor(this)),
@@ -420,6 +542,13 @@
property_get("ro.sf.blurs_are_expensive", value, "0");
mBlursAreExpensive = atoi(value);
+ property_get("vendor.display.enable_fb_scaling", value, "0");
+ mUseFbScaling = atoi(value);
+ ALOGI_IF(mUseFbScaling, "Enable FrameBuffer Scaling");
+ property_get("debug.sf.enable_advanced_sf_phase_offset", value, "0");
+ mUseAdvanceSfOffset = atoi(value);
+ ALOGI_IF(mUseAdvanceSfOffset, "Enable Advance SF Phase Offset");
+
const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS;
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
@@ -430,6 +559,21 @@
property_get("debug.sf.disable_client_composition_cache", value, "0");
mDisableClientCompositionCache = atoi(value);
+ char property[PROPERTY_VALUE_MAX] = {0};
+ if((property_get("vendor.display.vsync_reliable_on_doze", property, "0") > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ mVsyncSourceReliableOnDoze = true;
+ }
+
+ // If mPluggableVsyncPrioritized is true then the order of priority of V-syncs is Pluggable
+ // followed by Primary and Secondary built-ins.
+ if((property_get("vendor.display.pluggable_vsync_prioritized", property, "0") > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ mPluggableVsyncPrioritized = true;
+ }
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -445,12 +589,82 @@
}
useFrameRateApi = use_frame_rate_api(true);
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ mDisplayConfigCallbackhandler = new DisplayConfigCallbackHandler(*this);
+ int ret = ::DisplayConfig::ClientInterface::Create("SurfaceFlinger"+std::to_string(0),
+ mDisplayConfigCallbackhandler,
+ &mDisplayConfigIntf);
+ if (ret || !mDisplayConfigIntf) {
+ ALOGE("DisplayConfig HIDL not present\n");
+ mDisplayConfigIntf = nullptr;
+ }
+ if (mDisplayConfigIntf) {
+#ifdef DISPLAY_CONFIG_API_LEVEL_1
+ std::string value = "";
+ std::string qsync_prop = "enable_qsync_idle";
+ ret = mDisplayConfigIntf->GetDebugProperty(qsync_prop, &value);
+ ALOGI("enable_qsync_idle, ret:%d value:%s", ret, value.c_str());
+ if (!ret && (value == "1")) {
+ mDisplayConfigIntf->ControlIdleStatusCallback(true);
+ }
+#endif
+ }
+#endif
mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false);
base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false");
+
+ mDolphinHandle = dlopen("libdolphin.so", RTLD_NOW);
+ if (!mDolphinHandle) {
+ ALOGW("Unable to open libdolphin.so: %s.", dlerror());
+ } else {
+ mDolphinInit = (bool (*) ())dlsym(mDolphinHandle, "dolphinInit");
+ mDolphinMonitor = (bool (*) (int, nsecs_t))dlsym(mDolphinHandle, "dolphinMonitor");
+ mDolphinScaling = (void (*)(int, int))dlsym(mDolphinHandle, "dolphinScaling");
+ mDolphinRefresh = (void (*) ())dlsym(mDolphinHandle, "dolphinRefresh");
+ mDolphinDequeueBuffer = (void (*)(const char *))dlsym(mDolphinHandle,
+ "dolphinDequeueBuffer");
+ mDolphinQueueBuffer = (void (*)(const char *))dlsym(mDolphinHandle,
+ "dolphinQueueBuffer");
+ bool allDolphinSymbolsFound = mDolphinInit && mDolphinMonitor &&
+ mDolphinScaling && mDolphinRefresh && mDolphinDequeueBuffer &&
+ mDolphinQueueBuffer;
+ if (allDolphinSymbolsFound && mDolphinInit()) {
+ mDolphinFuncsEnabled = true;
+ }
+ if (!mDolphinFuncsEnabled)
+ dlclose(mDolphinHandle);
+ }
+
+ mFrameExtnLibHandle = dlopen(EXTENSION_LIBRARY_NAME, RTLD_NOW);
+ if (!mFrameExtnLibHandle) {
+ ALOGE("Unable to open libframeextension.so: %s.", dlerror());
+ } else {
+ mCreateFrameExtnFunc =
+ (bool (*) (composer::FrameExtnIntf**))(dlsym(mFrameExtnLibHandle,
+ CREATE_FRAME_EXTN_INTERFACE));
+ mDestroyFrameExtnFunc =
+ (bool (*) (composer::FrameExtnIntf*))(dlsym(mFrameExtnLibHandle,
+ DESTROY_FRAME_EXTN_INTERFACE));
+ if (mCreateFrameExtnFunc && mDestroyFrameExtnFunc) {
+ mCreateFrameExtnFunc(&mFrameExtn);
+ if (!mFrameExtn) {
+ ALOGE("Frame Extension Object create failed.");
+ dlclose(mFrameExtnLibHandle);
+ }
+ } else {
+ ALOGE("Can't load libframeextension symbols: %s", dlerror());
+ dlclose(mFrameExtnLibHandle);
+ }
+ }
}
-SurfaceFlinger::~SurfaceFlinger() = default;
+SurfaceFlinger::~SurfaceFlinger() {
+ if (mDolphinFuncsEnabled)
+ dlclose(mDolphinHandle);
+ if (mFrameExtn)
+ dlclose(mFrameExtnLibHandle);
+}
void SurfaceFlinger::onFirstRef() {
mEventQueue->init(this);
@@ -630,7 +844,20 @@
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
enableRefreshRateOverlay(true);
}
+ if (mUseFbScaling) {
+ Mutex::Autolock _l(mStateLock);
+ ssize_t index = mCurrentState.displays.indexOfKey(getInternalDisplayTokenLocked());
+ if (index < 0) {
+ ALOGE("Invalid token %p", getInternalDisplayTokenLocked().get());
+ } else {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ setFrameBufferSizeForScaling(getDefaultDisplayDeviceLocked(), state);
+ }
+ }
+
}));
+
+ setupEarlyWakeUpFeature();
}
uint32_t SurfaceFlinger::getNewTexture() {
@@ -699,6 +926,15 @@
LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
"Internal display is disconnected.");
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ if (!mDisplayConfigIntf) {
+ ALOGE("DisplayConfig HIDL not present\n");
+ mDisplayConfigIntf = nullptr;
+ } else {
+ mDisplayConfigIntf->IsAsyncVDSCreationSupported(&mAsyncVdsCreationSupported);
+ ALOGI("IsAsyncVDSCreationSupported %d", mAsyncVdsCreationSupported);
+ }
+#endif
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
@@ -746,6 +982,56 @@
ALOGE("Run StartPropertySetThread failed!");
}
+ char smomoProp[PROPERTY_VALUE_MAX];
+ property_get("vendor.display.use_smooth_motion", smomoProp, "0");
+ if (atoi(smomoProp) && mSmoMo.init()) {
+ mSmoMo->SetChangeRefreshRateCallback(
+ [this](int32_t refreshRate) {
+ setRefreshRateTo(refreshRate);
+ });
+
+ std::vector<float> refreshRates;
+ auto iter = mRefreshRateConfigs->getAllRefreshRates().cbegin();
+ while (iter != mRefreshRateConfigs->getAllRefreshRates().cend()) {
+ if (iter->second->getFps() > 0) {
+ refreshRates.push_back(iter->second->getFps());
+ }
+ ++iter;
+ }
+ mSmoMo->SetDisplayRefreshRates(refreshRates);
+
+ ALOGI("SmoMo is enabled");
+ }
+
+ char layerExtProp[PROPERTY_VALUE_MAX];
+ property_get("vendor.display.use_layer_ext", layerExtProp, "0");
+ if (atoi(layerExtProp)) {
+ mUseLayerExt = true;
+ }
+ property_get("vendor.display.split_layer_ext", layerExtProp, "0");
+ if (atoi(layerExtProp)) {
+ mSplitLayerExt = true;
+ }
+ if ((mUseLayerExt || mSplitLayerExt) && mLayerExt.init()) {
+ ALOGI("Layer Extension is enabled");
+ }
+
+ mComposerExtnIntf = composer::ComposerExtnLib::GetInstance();
+ if (!mComposerExtnIntf) {
+ ALOGE("Unable to get composer extension");
+ } else {
+ int ret = mComposerExtnIntf->CreateFrameScheduler(&mFrameSchedulerExtnIntf);
+ if (ret) {
+ ALOGI("Unable to create frame scheduler extension");
+ }
+
+ ret = mComposerExtnIntf->CreateDisplayExtn(&mDisplayExtnIntf);
+ if (ret) {
+ ALOGI("Unable to create display extension");
+ }
+
+ createPhaseOffsetExtn();
+ }
ALOGV("Done initializing");
}
@@ -985,6 +1271,7 @@
void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
ATRACE_CALL();
auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId);
+ mVsyncPeriod = refreshRate.getVsyncPeriod();
ALOGV("setDesiredActiveConfig(%s)", refreshRate.getName().c_str());
std::lock_guard<std::mutex> lock(mActiveConfigLock);
@@ -1022,6 +1309,8 @@
if (mRefreshRateOverlay) {
mRefreshRateOverlay->changeRefreshRate(refreshRate);
}
+
+ setContentFps(static_cast<uint32_t>(refreshRate.getFps()));
}
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -1398,6 +1687,47 @@
.get();
}
+status_t SurfaceFlinger::setDisplayElapseTime(const sp<DisplayDevice>& display) const {
+ nsecs_t sfOffset = mPhaseConfiguration->getCurrentOffsets().late.sf;
+ if (!mUseAdvanceSfOffset && (sfOffset >= 0)) {
+ return OK;
+ }
+
+ if (mDisplaysList.size() != 1 || display->isVirtual()) {
+ // Revisit this for multi displays.
+ return OK;
+ }
+
+ uint64_t timeStamp = static_cast<uint64_t>(mVsyncTimeStamp + (sfOffset * -1));
+ return getHwComposer().setDisplayElapseTime(*display->getId(), timeStamp);
+}
+
+status_t SurfaceFlinger::isSupportedConfigSwitch(const sp<IBinder>& displayToken, int config) {
+ sp<DisplayDevice> display = nullptr;
+ {
+ Mutex::Autolock lock(mStateLock);
+ display = (getDisplayDeviceLocked(displayToken));
+ }
+
+ if (!display) {
+ ALOGE("Attempt to switch config %d for invalid display token %p", config,
+ displayToken.get());
+ return NAME_NOT_FOUND;
+ }
+#if (defined QTI_DISPLAY_CONFIG_ENABLED && defined VALIDATE_CONFIG_SWITCH)
+ const auto displayId = display->getId();
+ const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
+ bool supported = false;
+ mDisplayConfigIntf->IsSupportedConfigSwitch(*hwcDisplayId, config, &supported);
+ if (!supported) {
+ ALOGW("Switching to config:%d is not supported", config);
+ return INVALID_OPERATION;
+ }
+#endif
+
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::getDisplayedContentSample(const sp<IBinder>& displayToken,
uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) const {
@@ -1544,21 +1874,21 @@
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) {
- const auto& handle =
- vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
+ bool triggerRefresh = vsyncSource != eVsyncSourceSurfaceFlinger;
+ const auto& handle = triggerRefresh ? mAppConnectionHandle : mSfConnectionHandle;
- return mScheduler->createDisplayEventConnection(handle, configChanged);
+ return mScheduler->createDisplayEventConnection(handle, configChanged, triggerRefresh);
}
void SurfaceFlinger::signalTransaction() {
mScheduler->resetIdleTimer();
- mPowerAdvisor.notifyDisplayUpdateImminent();
+ notifyDisplayUpdateImminent();
mEventQueue->invalidate();
}
void SurfaceFlinger::signalLayerUpdate() {
mScheduler->resetIdleTimer();
- mPowerAdvisor.notifyDisplayUpdateImminent();
+ notifyDisplayUpdateImminent();
mEventQueue->invalidate();
}
@@ -1567,8 +1897,14 @@
mEventQueue->refresh();
}
-nsecs_t SurfaceFlinger::getVsyncPeriod() const {
- const auto displayId = getInternalDisplayIdLocked();
+nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
+ auto displayId = getInternalDisplayIdLocked();
+ if (mNextVsyncSource) {
+ displayId = mNextVsyncSource->getId();
+ } else if (mActiveVsyncSource) {
+ displayId = mActiveVsyncSource->getId();
+ }
+
if (!displayId || !getHwComposer().isConnected(*displayId)) {
return 0;
}
@@ -1591,11 +1927,6 @@
return;
}
- if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
- // For now, we don't do anything with external display vsyncs.
- return;
- }
-
bool periodFlushed = false;
mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed);
if (periodFlushed) {
@@ -1628,6 +1959,27 @@
}
setDesiredActiveConfig({refreshRate.getConfigId(), event});
+
+ uint32_t hwcDisplayId;
+ if (getHwcDisplayId(display, &hwcDisplayId)) {
+ setDisplayExtnActiveConfig(hwcDisplayId, refreshRate.getConfigId().value());
+ }
+}
+
+void SurfaceFlinger::setRefreshRateTo(int32_t refreshRate) {
+ auto& currentRefreshRate = mRefreshRateConfigs->getCurrentRefreshRate();
+
+ auto iter = mRefreshRateConfigs->getAllRefreshRates().cbegin();
+ while (iter != mRefreshRateConfigs->getAllRefreshRates().cend()) {
+ if (iter->second->inPolicy(refreshRate, refreshRate)) {
+ break;
+ }
+ ++iter;
+ }
+
+ if (currentRefreshRate != *iter->second) {
+ changeRefreshRate(*iter->second, Scheduler::ConfigEvent::Changed);
+ }
}
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
@@ -1648,6 +2000,15 @@
mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
+ if (connection != hal::Connection::CONNECTED) {
+ const std::optional<DisplayIdentificationInfo> info =
+ getHwComposer().onHotplug(hwcDisplayId, connection);
+ if (info) {
+ mDisplaysList.remove(getDisplayDeviceLocked(mPhysicalDisplayTokens[info->id]));
+ }
+ mNextVsyncSource = getVsyncSource();
+ }
+
if (std::this_thread::get_id() == mMainThreadId) {
// Process all pending hot plug events immediately if we are on the main thread.
processDisplayHotplugEventsLocked();
@@ -1677,26 +2038,49 @@
return;
}
repaintEverythingForHWC();
+
+ if (mDisplaysList.size() != 1) {
+ // Revisit this for multi displays.
+ return;
+ }
+
+ {
+ // Track Vsync Period before and after refresh.
+ std::lock_guard lock(mVsyncPeriodMutex);
+ mVsyncPeriods = {};
+ mVsyncPeriods.push_back(getVsyncPeriodFromHWC());
+ }
}
-void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
+void SurfaceFlinger::setVsyncEnabled(bool enabled) {
ATRACE_CALL();
// Enable / Disable HWVsync from the main thread to avoid race conditions with
// display power state.
- static_cast<void>(schedule([=]() MAIN_THREAD { setPrimaryVsyncEnabledInternal(enabled); }));
+ static_cast<void>(schedule([=]() MAIN_THREAD { setVsyncEnabledInternal(enabled); }));
}
-void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
+void SurfaceFlinger::setVsyncEnabledInternal(bool enabled) {
ATRACE_CALL();
+ Mutex::Autolock lockVsync(mVsyncLock);
mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;
- if (const auto displayId = getInternalDisplayIdLocked()) {
- sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
- if (display && display->isPoweredOn()) {
- getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
+ auto displayId = getInternalDisplayIdLocked();
+ if (mNextVsyncSource) {
+ // Disable current vsync source before enabling the next source
+ if (mActiveVsyncSource) {
+ displayId = mActiveVsyncSource->getId();
+ getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE);
}
+ displayId = mNextVsyncSource->getId();
+ } else if (mActiveVsyncSource) {
+ displayId = mActiveVsyncSource->getId();
+ }
+ getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
+ if (mNextVsyncSource) {
+ mActiveVsyncSource = mNextVsyncSource;
+ mNextVsyncSource = NULL;
}
}
@@ -1774,7 +2158,7 @@
setPowerModeInternal(display, currentDisplayPowerMode);
// Reset the timing values to account for the period of the swapped in HWC
- const nsecs_t vsyncPeriod = getVsyncPeriod();
+ const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
// The present fences returned from vr_hwc are not an accurate
@@ -1796,8 +2180,8 @@
// We are storing the last 2 present fences. If sf's phase offset is to be
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
- return mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
- : mPreviousPresentFences[1];
+ return mVSyncModulator->getOffsets().sf >= 0 ? mPreviousPresentFences[0]
+ : mPreviousPresentFences[1];
}
bool SurfaceFlinger::previousFramePending(int graceTimeMs) {
@@ -1829,7 +2213,36 @@
mScheduler->getDisplayStatInfo(&stats);
const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(now);
// Inflate the expected present time if we're targetting the next vsync.
- return mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod;
+ return mVSyncModulator->getOffsets().sf >= 0 ? presentTime : presentTime + stats.vsyncPeriod;
+}
+
+void SurfaceFlinger::updateFrameScheduler() NO_THREAD_SAFETY_ANALYSIS {
+ if (!mFrameSchedulerExtnIntf) {
+ return;
+ }
+
+ const sp<Fence>& fence = mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
+ : mPreviousPresentFences[1];
+
+ if (fence == Fence::NO_FENCE) {
+ return;
+ }
+ int fenceFd = fence->get();
+ nsecs_t timeStamp = 0;
+ int ret = mFrameSchedulerExtnIntf->UpdateFrameScheduling(fenceFd, &timeStamp);
+ if (ret <= 0) {
+ return;
+ }
+
+ const nsecs_t period = getVsyncPeriodFromHWC();
+ mScheduler->resyncToHardwareVsync(true, period, true /* force resync */);
+ if (timeStamp > 0) {
+ bool periodFlushed = false;
+ mScheduler->addResyncSample(timeStamp, period, &periodFlushed);
+ if (periodFlushed) {
+ mVSyncModulator->onRefreshRateChangeCompleted();
+ }
+ }
}
void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) {
@@ -1840,10 +2253,24 @@
break;
}
case MessageQueue::REFRESH: {
+ if (mFrameExtn) {
+ mRefreshTimeStamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ }
+ if (mDolphinFuncsEnabled) {
+ mDolphinRefresh();
+ }
onMessageRefresh();
+ if (mFrameExtn) {
+ mNumIdle = 0;
+ }
break;
}
}
+#ifdef PASS_COMPOSITOR_PID
+ if (mDisplayExtnIntf) {
+ mDisplayExtnIntf->SendCompositorPid();
+ }
+#endif
}
void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) {
@@ -1855,7 +2282,7 @@
// seeing this same value.
const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
mExpectedPresentTime = expectedVSyncTime;
-
+ updateFrameScheduler();
// When Backpressure propagation is enabled we want to give a small grace period
// for the present fence to fire instead of just giving up on this frame to handle cases
// where present fence is just about to get signaled.
@@ -1929,6 +2356,44 @@
}
}
+ if (mDolphinFuncsEnabled) {
+ int maxQueuedFrames = 0;
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ if (layer->hasReadyFrame()) {
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
+ if (layer->shouldPresentNow(expectedPresentTime)) {
+ int layerQueuedFrames = layer->getQueuedFrameCount();
+ const auto& drawingState{layer->getDrawingState()};
+ bool isLayerAvailable = layer->isOpaque(drawingState);
+ if (!isLayerAvailable) {
+ int32_t priority = layer->getPriority();
+ if (layer->isLayerFocusedBasedOnPriority(priority)) {
+ isLayerAvailable = true;
+ }
+ }
+ if (maxQueuedFrames < layerQueuedFrames &&
+ isLayerAvailable) {
+ maxQueuedFrames = layerQueuedFrames;
+ mNameLayerMax = layer->getName();
+ }
+ }
+ }
+ });
+ mMaxQueuedFrames = maxQueuedFrames;
+ DisplayStatInfo stats;
+ mScheduler->getDisplayStatInfo(&stats);
+ if(mDolphinMonitor(maxQueuedFrames, stats.vsyncPeriod)) {
+ signalLayerUpdate();
+ if (mFrameExtn) {
+ mNumIdle++;
+ }
+ return;
+ }
+ if (mFrameExtn) {
+ mNumIdle++;
+ }
+ }
+
// Our jank window is always at least 100ms since we missed a
// frame...
static constexpr nsecs_t kMinJankyDuration =
@@ -2014,6 +2479,11 @@
}
signalRefresh();
}
+ if (mFrameExtn && mDolphinFuncsEnabled) {
+ if (!refreshNeeded) {
+ mDolphinScaling(mNumIdle, mMaxQueuedFrames);
+ }
+ }
}
bool SurfaceFlinger::handleMessageTransaction() {
@@ -2090,8 +2560,17 @@
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
const auto presentTime = systemTime();
+ dumpDrawCycle(true);
+
+ {
+ Mutex::Autolock lock(mStateLock);
+ for (const auto& [_, display] : mDisplays) {
+ setDisplayElapseTime(display);
+ }
+ }
mCompositionEngine->present(refreshArgs);
+
mTimeStats->recordFrameDuration(mFrameStartTime, systemTime());
// Reset the frame start time now that we've recorded this frame.
mFrameStartTime = 0;
@@ -2122,7 +2601,8 @@
mTimeStats->incrementCompositionStrategyChanges();
}
- mVSyncModulator->onRefreshed(mHadClientComposition);
+ // TODO: b/160583065 Enable skip validation when SF caches all client composition layers
+ mVSyncModulator->onRefreshed(mHadClientComposition || mReusedClientComposition);
mLayersWithQueuedFrames.clear();
if (mVisibleRegionsDirty) {
@@ -2237,8 +2717,13 @@
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFences[1] = mPreviousPresentFences[0];
- mPreviousPresentFences[0] =
- display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
+
+ sp<DisplayDevice> vSyncSource = mNextVsyncSource;
+ if (mNextVsyncSource == NULL) {
+ vSyncSource = mActiveVsyncSource;
+ }
+ mPreviousPresentFences[0] = vSyncSource ?
+ getHwComposer().getPresentFence(*vSyncSource->getId()) : Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
getBE().mDisplayTimeline.push(presentFenceTime);
@@ -2272,6 +2757,8 @@
mScheduler->addPresentFence(presentFenceTime);
}
+ forceResyncModel();
+
const bool isDisplayConnected = display && getHwComposer().isConnected(*display->getId());
if (!hasSyncFramework) {
@@ -2295,6 +2782,8 @@
mAnimFrameTracker.advanceFrame();
}
+ dumpDrawCycle(false);
+
mTimeStats->incrementTotalFrames();
if (mHadClientComposition) {
mTimeStats->incrementClientCompositionFrames();
@@ -2361,6 +2850,43 @@
mRegionSamplingThread->notifyNewContent();
}
+ if (mSplitLayerExt && mLayerExt) {
+ std::vector<std::string> layerInfo;
+ mDrawingState.traverse([&](Layer* layer) {
+ if (layer->findOutputLayerForDisplay(display)) {
+ layerInfo.push_back(layer->getName());
+ }
+ });
+ mLayerExt->UpdateLayerState(layerInfo, mNumLayers);
+ }
+
+ if (mSmoMo) {
+ ATRACE_NAME("SmoMoUpdateState");
+ Mutex::Autolock lock(mStateLock);
+
+ uint32_t fps = 0;
+ std::vector<smomo::SmomoLayerStats> layers;
+
+ // Disable SmoMo by passing empty layer stack in multiple display case
+ if (mDisplays.size() == 1) {
+ mDrawingState.traverse([&](Layer* layer) {
+ if (layer->findOutputLayerForDisplay(display)) {
+ smomo::SmomoLayerStats layerStats;
+ layerStats.id = layer->getSequence();
+ layerStats.name = layer->getName();
+ layers.push_back(layerStats);
+ }
+ });
+
+ fps = mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+ }
+
+ mSmoMo->UpdateSmomoState(layers, fps);
+ int content_fps = mSmoMo->GetFrameRate();
+ setContentFps((content_fps > 0) ? content_fps : fps);
+ }
+
+
// Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the
// side-effect of getTotalSize(), so we check that again here
if (ATRACE_ENABLED()) {
@@ -2373,6 +2899,30 @@
return displayDevice.getViewport().toFloatRect();
}
+void SurfaceFlinger::forceResyncModel() NO_THREAD_SAFETY_ANALYSIS {
+ std::lock_guard lock(mVsyncPeriodMutex);
+ if (!mVsyncPeriods.size()) {
+ return;
+ }
+
+ const nsecs_t period = getVsyncPeriodFromHWC();
+ // Model resync should happen at every fps change.
+ // Upon increase/decrease in vsync period start resync immediately.
+ // Initial set of vsync wakeups happen at ref_time + N * period where N = 1, 2, 3 ..
+ // Since if doesnt make use of timestamp to compute period, resync can be triggered
+ // as soon as change is fps(period) is observed.
+ if (period > mVsyncPeriods.at(mVsyncPeriods.size() - 1)) {
+ ATRACE_CALL();
+ mScheduler->resyncToHardwareVsync(true, period, true /* force resync */);
+ mVsyncPeriods.push_back(period);
+ } else if (period < mVsyncPeriods.at(mVsyncPeriods.size() - 1)) {
+ // Vsync period changed. Trigger resync.
+ ATRACE_CALL();
+ mScheduler->resyncToHardwareVsync(true, period, true /* force resync */);
+ mVsyncPeriods = {};
+ }
+}
+
void SurfaceFlinger::computeLayerBounds() {
for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
const auto& displayDevice = pair.second;
@@ -2389,6 +2939,71 @@
}
}
+sp<DisplayDevice> SurfaceFlinger::getVsyncSource() {
+ // Return the vsync source from the active displays based on the order in which they are
+ // connected.
+ // Normally the order of priority is Primary (Built-in/Pluggable) followed by Secondary
+ // built-ins followed by Pluggable. But if mPluggableVsyncPrioritized is true then the
+ // order of priority is Pluggables followed by Primary and Secondary built-ins.
+
+ for (const auto& display : mDisplaysList) {
+ hal::PowerMode mode = display->getPowerMode();
+ if (display->isVirtual() || (mode == hal::PowerMode::OFF) ||
+ (mode == hal::PowerMode::DOZE_SUSPEND)) {
+ continue;
+ }
+
+ if (mVsyncSourceReliableOnDoze) {
+ if ((mode == hal::PowerMode::ON) ||
+ (mode == hal::PowerMode::DOZE)) {
+ return display;
+ }
+ } else if (mode == hal::PowerMode::ON) {
+ return display;
+ }
+ }
+
+ // In-case active displays are not present, source the vsync from
+ // the display which is in doze mode even if it is unreliable
+ // in the same order of display priority as above.
+ if (!mVsyncSourceReliableOnDoze) {
+ for (const auto& display : mDisplaysList) {
+ hal::PowerMode mode = display->getPowerMode();
+ if (display->isVirtual()) {
+ continue;
+ }
+
+ if (mode == hal::PowerMode::DOZE) {
+ return display;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void SurfaceFlinger::updateVsyncSource()
+ NO_THREAD_SAFETY_ANALYSIS {
+ Mutex::Autolock lock(mVsyncLock);
+ mNextVsyncSource = getVsyncSource();
+
+ if (mNextVsyncSource == NULL) {
+ // Switch off vsync for the last enabled source
+ mScheduler->disableHardwareVsync(true);
+ mScheduler->onScreenReleased(mAppConnectionHandle);
+ } else if (mNextVsyncSource && (mActiveVsyncSource == NULL)) {
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ bool isPrimary = mNextVsyncSource->isPrimary();
+ nsecs_t vsync = (isPrimary && (mVsyncPeriod > 0)) ? mVsyncPeriod : getVsyncPeriodFromHWC();
+ mScheduler->resyncToHardwareVsync(true, vsync);
+ } else if ((mNextVsyncSource != NULL) &&
+ (mActiveVsyncSource != NULL)) {
+ // Switch vsync to the new source
+ mScheduler->disableHardwareVsync(true);
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriodFromHWC());
+ }
+}
+
void SurfaceFlinger::postFrame() {
const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
if (display && getHwComposer().isConnected(*display->getId())) {
@@ -2438,6 +3053,8 @@
const DisplayId displayId = info->id;
const auto it = mPhysicalDisplayTokens.find(displayId);
+ bool isInternalDisplay = (getHwComposer().getDisplayConnectionType(displayId) ==
+ DisplayConnectionType::Internal);
if (event.connection == hal::Connection::CONNECTED) {
if (it == mPhysicalDisplayTokens.end()) {
@@ -2475,8 +3092,19 @@
mCurrentState.displays.removeItemsAt(index);
}
mPhysicalDisplayTokens.erase(it);
+ updateVsyncSource();
+ if (mInternalPresentationDisplays && isInternalDisplay) {
+ // Update mInternalPresentationDisplays flag
+ updateInternalDisplaysPresentationMode();
+ }
}
+ if (mEarlyWakeUpEnabled && isInternalDisplay) {
+ uint32_t hwcDisplayId = static_cast<uint32_t>(event.hwcDisplayId);
+ bool isConnected = (event.connection == hal::Connection::CONNECTED);
+ uint32_t activeConfigId = getHwComposer().getActiveConfigIndex(displayId);
+ updateDisplayExtension(hwcDisplayId, activeConfigId, isConnected);
+ }
processDisplayChangesLocked();
}
@@ -2578,6 +3206,7 @@
const DisplayDeviceState& state) {
int width = 0;
int height = 0;
+ bool canAllocateHwcForVDS = false;
ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
if (state.physical) {
const auto& activeConfig =
@@ -2594,6 +3223,20 @@
status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat);
+ if (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()) {
+ if (maxVirtualDisplaySize == 0 ||
+ ((uint64_t)width <= maxVirtualDisplaySize &&
+ (uint64_t)height <= maxVirtualDisplaySize)) {
+ uint64_t usage = 0;
+ // Replace with native_window_get_consumer_usage ?
+ status = state .surface->getConsumerUsage(&usage);
+ ALOGW_IF(status != NO_ERROR, "Unable to query usage (%d)", status);
+ if ((status == NO_ERROR) && canAllocateHwcDisplayIdForVDS(usage)) {
+ canAllocateHwcForVDS = true;
+ }
+ }
+ }
+
} else {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
@@ -2610,7 +3253,8 @@
builder.setIsSecure(state.isSecure);
builder.setLayerStackId(state.layerStack);
builder.setPowerAdvisor(&mPowerAdvisor);
- builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer());
+ builder.setUseHwcVirtualDisplays((mUseHwcVirtualDisplays && canAllocateHwcForVDS) ||
+ getHwComposer().isUsingVrComposer());
builder.setName(state.displayName);
const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
@@ -2624,8 +3268,9 @@
if (state.isVirtual()) {
sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, bqProducer,
- bqConsumer, state.displayName);
+ new VirtualDisplaySurface(getHwComposer(), displayId, state.surface,
+ bqProducer, bqConsumer, state.displayName,
+ state.isSecure);
displaySurface = vds;
producer = vds;
@@ -2645,9 +3290,44 @@
const auto display = setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
displaySurface, producer);
mDisplays.emplace(displayToken, display);
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
+ bool supported = false;
+ if (mDisplayConfigIntf) {
+ mDisplayConfigIntf->IsPowerModeOverrideSupported(*hwcDisplayId, &supported);
+ }
+ if (supported) {
+ sp<DisplayDevice> display = getDisplayDeviceLocked(displayToken);
+ display->setPowerModeOverrideConfig(true);
+ }
+#endif
if (!state.isVirtual()) {
+ sp<DisplayDevice> display = getDisplayDeviceLocked(displayToken);
+ if (mPluggableVsyncPrioritized && !isInternalDisplay(display)) {
+ // Insert the pluggable display just before the first built-in display
+ // so that the earlier pluggable display remains the V-sync source.
+ auto it = mDisplaysList.begin();
+ for (; it != mDisplaysList.end(); it++ ) {
+ if(isInternalDisplay(*it)) {
+ break;
+ }
+ }
+ mDisplaysList.insert(it, display);
+ } else {
+ mDisplaysList.push_back(display);
+ }
LOG_FATAL_IF(!displayId);
dispatchDisplayHotplugEvent(displayId->value, true);
+
+ if (!display->isPrimary() && isInternalDisplay(display)) {
+ const auto defaultDisplay = getDefaultDisplayDeviceLocked();
+ if (defaultDisplay && defaultDisplay->isPrimary()) {
+ if (state.layerStack != defaultDisplay->getLayerStack()) {
+ // Internal Physical Displays are in Presentation Mode
+ mInternalPresentationDisplays = true;
+ }
+ }
+ }
}
if (display->isPrimary()) {
@@ -2693,30 +3373,70 @@
}
if (const auto display = getDisplayDeviceLocked(displayToken)) {
+ bool displaySizeChanged = false;
if (currentState.layerStack != drawingState.layerStack) {
display->setLayerStack(currentState.layerStack);
}
if ((currentState.orientation != drawingState.orientation) ||
(currentState.viewport != drawingState.viewport) ||
(currentState.frame != drawingState.frame)) {
- display->setProjection(currentState.orientation, currentState.viewport,
+ if (mUseFbScaling && display->isPrimary()) {
+ const ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
+ DisplayDeviceState& tmpState = mCurrentState.displays.editValueAt(index);
+ tmpState.width = currentState.viewport.width();
+ tmpState.height = currentState.viewport.height();
+ tmpState.frame = currentState.viewport;
+ setFrameBufferSizeForScaling(display, currentState);
+ displaySizeChanged = true;
+ } else {
+ display->setProjection(currentState.orientation, currentState.viewport,
currentState.frame);
+ }
}
if (currentState.width != drawingState.width ||
currentState.height != drawingState.height) {
- display->setDisplaySize(currentState.width, currentState.height);
+ if (!displaySizeChanged) {
+ display->setDisplaySize(currentState.width, currentState.height);
- if (display->isPrimary()) {
- mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height);
- }
+ if (display->isPrimary()) {
+ mScheduler->onPrimaryDisplayAreaChanged(
+ currentState.width * currentState.height);
+ }
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->setViewport(display->getSize());
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->setViewport(display->getSize());
+ }
}
}
}
}
+void SurfaceFlinger::setFrameBufferSizeForScaling(sp<DisplayDevice> displayDevice,
+ const DisplayDeviceState& state) {
+ base::unique_fd fd;
+ auto display = displayDevice->getCompositionDisplay();
+ int newWidth = state.viewport.width();
+ int newHeight = state.viewport.height();
+ if (state.orientation == ui::ROTATION_90 || state.orientation == ui::ROTATION_270){
+ std::swap(newWidth, newHeight);
+ }
+ if (displayDevice->getWidth() == newWidth && displayDevice->getHeight() == newHeight) {
+ displayDevice->setProjection(state.orientation, state.viewport, state.viewport);
+ return;
+ }
+
+ if (mBootStage == BootStage::FINISHED) {
+ displayDevice->setDisplaySize(newWidth, newHeight);
+ displayDevice->setProjection(state.orientation, state.viewport, state.viewport);
+ display->getRenderSurface()->setViewportAndProjection();
+ display->getRenderSurface()->flipClientTarget(true);
+ // queue a scratch buffer to flip Client Target with updated size
+ display->getRenderSurface()->queueBuffer(std::move(fd));
+ display->getRenderSurface()->flipClientTarget(false);
+ // releases the FrameBuffer that was acquired as part of queueBuffer()
+ display->getRenderSurface()->onPresentDisplayCompleted();
+ }
+}
void SurfaceFlinger::processDisplayChangesLocked() {
// here we take advantage of Vector's copy-on-write semantics to
// improve performance by skipping the transaction entirely when
@@ -2975,7 +3695,7 @@
// start the EventThread
mScheduler =
- getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
+ getFactory().createScheduler([this](bool enabled) { setVsyncEnabled(enabled); },
*mRefreshRateConfigs, *this);
mAppConnectionHandle =
mScheduler->createConnection("app", mPhaseConfiguration->getCurrentOffsets().late.app,
@@ -3088,6 +3808,8 @@
bool visibleRegions = false;
bool frameQueued = false;
bool newDataLatched = false;
+ std::set<uint32_t> layerStackIds;
+ uint32_t layerStackId = 0;
const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
@@ -3105,6 +3827,8 @@
frameQueued = true;
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
+ layerStackId = layer->getLayerStack();
+ layerStackIds.insert(layerStackId);
} else {
ATRACE_NAME("!layer->shouldPresentNow()");
layer->useEmptyDamage();
@@ -3114,6 +3838,10 @@
}
});
+ if (wakeUpPresentationDisplays && !mLayersWithQueuedFrames.empty()) {
+ handlePresentationDisplaysEarlyWakeup(layerStackIds.size(), layerStackId);
+ }
+
// The client can continue submitting buffers for offscreen layers, but they will not
// be shown on screen. Therefore, we need to latch and release buffers of offscreen
// layers to ensure dequeueBuffer doesn't block indefinitely.
@@ -3185,6 +3913,12 @@
if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
ISurfaceComposer::MAX_LAYERS);
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ const auto& p = layer->getParent();
+ ALOGE("layer (%s) :: parent (%s).",
+ layer->getName().c_str(),
+ (p != nullptr) ? p->getName().c_str() : "no-parent");
+ });
return NO_MEMORY;
}
@@ -3339,6 +4073,10 @@
bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
+ if (mAsyncVdsCreationSupported) {
+ checkVirtualDisplayHint(displays);
+ }
+
Mutex::Autolock _l(mStateLock);
// If its TransactionQueue already has a pending TransactionState or if it is pending
@@ -3541,6 +4279,47 @@
}
}
+void SurfaceFlinger::checkVirtualDisplayHint(const Vector<DisplayState>& displays) {
+ for (const DisplayState& s : displays) {
+ const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
+ if (index < 0)
+ continue;
+
+ DisplayDeviceState& state = mCurrentState.displays.editValueAt(index);
+ const uint32_t what = s.what;
+ if (what & DisplayState::eSurfaceChanged) {
+ if (IInterface::asBinder(state.surface) != IInterface::asBinder(s.surface)) {
+ if (state.isVirtual() && s.surface != nullptr &&
+ (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer())) {
+ int width = 0;
+ int status = s.surface->query(NATIVE_WINDOW_WIDTH, &width);
+ ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
+ int height = 0;
+ status = s.surface->query(NATIVE_WINDOW_HEIGHT, &height);
+ ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
+ int format = 0;
+ status = s.surface->query(NATIVE_WINDOW_FORMAT, &format);
+ ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ if ((mDisplayConfigIntf) && (maxVirtualDisplaySize == 0 ||
+ ((uint64_t)width <= maxVirtualDisplaySize &&
+ (uint64_t)height <= maxVirtualDisplaySize))) {
+ uint64_t usage = 0;
+ // Replace with native_window_get_consumer_usage ?
+ status = s.surface->getConsumerUsage(&usage);
+ ALOGW_IF(status != NO_ERROR, "Unable to query usage (%d)", status);
+ if ((status == NO_ERROR) && canAllocateHwcDisplayIdForVDS(usage)) {
+ mDisplayConfigIntf->CreateVirtualDisplay(width, height, format);
+ return;
+ }
+ }
+#endif
+ }
+ }
+ }
+ }
+}
+
uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
if (index < 0) return 0;
@@ -3999,10 +4778,12 @@
// window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
// TODO b/64227542
+ metadata.setInt32(METADATA_WINDOW_TYPE_DONT_SCREENSHOT, 0);
if (metadata.has(METADATA_WINDOW_TYPE)) {
int32_t windowType = metadata.getInt32(METADATA_WINDOW_TYPE, 0);
if (windowType == 441731) {
metadata.setInt32(METADATA_WINDOW_TYPE, InputWindowInfo::TYPE_NAVIGATION_BAR_PANEL);
+ metadata.setInt32(METADATA_WINDOW_TYPE_DONT_SCREENSHOT, 1);
primaryDisplayOnly = true;
}
}
@@ -4216,8 +4997,7 @@
{});
setPowerModeInternal(display, hal::PowerMode::ON);
-
- const nsecs_t vsyncPeriod = getVsyncPeriod();
+ const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
// Use phase of 0 since phase is not known.
@@ -4247,21 +5027,35 @@
return;
}
+ mActiveVsyncSource = getVsyncSource();
+
display->setPowerMode(mode);
+ // Dummy display created by LibSurfaceFlinger unit test
+ // for setPowerModeInternal test cases.
+ bool isDummyDisplay = (std::find(mDisplaysList.begin(),
+ mDisplaysList.end(), display) == mDisplaysList.end());
+
if (mInterceptor->isEnabled()) {
mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
}
-
+ const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
if (currentMode == hal::PowerMode::OFF) {
if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
}
getHwComposer().setPowerMode(*displayId, mode);
- if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
- getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
- mScheduler->onScreenAcquired(mAppConnectionHandle);
- mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ bool internalDisplay = isInternalDisplay(display);
+ if (isDummyDisplay) {
+ if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
+ getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
+ }
+ } else if ((mPluggableVsyncPrioritized && !internalDisplay) ||
+ (displayId == getInternalDisplayIdLocked()) ||
+ internalDisplay) {
+ updateVsyncSource();
}
mVisibleRegionsDirty = true;
@@ -4269,32 +5063,43 @@
repaintEverything();
} else if (mode == hal::PowerMode::OFF) {
// Turn off the display
- if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) {
- ALOGW("Couldn't set SCHED_OTHER on display off: %s\n", strerror(errno));
- }
- if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
- mScheduler->disableHardwareVsync(true);
- mScheduler->onScreenReleased(mAppConnectionHandle);
- }
+ if (isDummyDisplay) {
+ if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) {
+ ALOGW("Couldn't set SCHED_OTHER on display off: %s\n", strerror(errno));
+ }
+ if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
+ mScheduler->disableHardwareVsync(true);
+ mScheduler->onScreenReleased(mAppConnectionHandle);
+ }
- // Make sure HWVsync is disabled before turning off the display
- getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE);
-
+ // Make sure HWVsync is disabled before turning off the display
+ getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE);
+ } else {
+ updateVsyncSource();
+ }
getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(*displayId, mode);
- if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
- mScheduler->onScreenAcquired(mAppConnectionHandle);
- mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ if (isDummyDisplay) {
+ if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
+ }
+ } else {
+ updateVsyncSource();
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
- if (display->isPrimary()) {
- mScheduler->disableHardwareVsync(true);
- mScheduler->onScreenReleased(mAppConnectionHandle);
+ if (isDummyDisplay) {
+ if (display->isPrimary()) {
+ mScheduler->disableHardwareVsync(true);
+ mScheduler->onScreenReleased(mAppConnectionHandle);
+ }
+ } else {
+ updateVsyncSource();
}
getHwComposer().setPowerMode(*displayId, mode);
} else {
@@ -4302,16 +5107,30 @@
getHwComposer().setPowerMode(*displayId, mode);
}
+ const sp<DisplayDevice> vsyncSource = getVsyncSource();
+ struct sched_param param = {0};
+ if (vsyncSource != NULL) {
+ param.sched_priority = 1;
+ if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
+ ALOGW("Couldn't set SCHED_FIFO on display on");
+ }
+ } else {
+ if (sched_setscheduler(0, SCHED_OTHER, ¶m) != 0) {
+ ALOGW("Couldn't set SCHED_OTHER on display off");
+ }
+ }
+
if (display->isPrimary()) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
}
+ setEarlyWakeUpConfig(display, mode);
ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
}
-void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
+void SurfaceFlinger::setPowerModeOnMainThread(const sp<IBinder>& displayToken, int mode) {
schedule([=]() MAIN_THREAD {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
@@ -4325,7 +5144,82 @@
}).wait();
}
+void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
+ sp<DisplayDevice> display = nullptr;
+ {
+ Mutex::Autolock lock(mStateLock);
+ display = (getDisplayDeviceLocked(displayToken));
+ }
+ if (!display) {
+ ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
+ displayToken.get());
+ return;
+ } else if (display->isVirtual()) {
+ ALOGW("Attempt to set power mode %d for virtual display", mode);
+ return;
+ }
+
+#ifdef QTI_DISPLAY_CONFIG_ENABLED
+ const auto displayId = display->getId();
+ const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
+ const hal::PowerMode currentDisplayPowerMode = display->getPowerMode();
+ const hal::PowerMode newDisplayPowerMode = static_cast<hal::PowerMode>(mode);
+ // Fallback to default power state behavior as HWC does not support power mode override.
+ if (!display->getPowerModeOverrideConfig() ||
+ !((currentDisplayPowerMode == hal::PowerMode::OFF &&
+ newDisplayPowerMode == hal::PowerMode::ON) ||
+ (currentDisplayPowerMode == hal::PowerMode::ON &&
+ newDisplayPowerMode == hal::PowerMode::OFF))) {
+ setPowerModeOnMainThread(displayToken, mode);
+ return;
+ }
+
+ ::DisplayConfig::PowerMode hwcMode = ::DisplayConfig::PowerMode::kOff;
+ switch (mode) {
+ case HWC_POWER_MODE_DOZE: hwcMode = ::DisplayConfig::PowerMode::kDoze; break;
+ case HWC_POWER_MODE_NORMAL: hwcMode = ::DisplayConfig::PowerMode::kOn; break;
+ case HWC_POWER_MODE_DOZE_SUSPEND: hwcMode = ::DisplayConfig::PowerMode::kDozeSuspend; break;
+ default: hwcMode = ::DisplayConfig::PowerMode::kOff; break;
+ }
+
+ bool step_up = false;
+ if (currentDisplayPowerMode == hal::PowerMode::OFF) {
+ if (newDisplayPowerMode == hal::PowerMode::DOZE ||
+ newDisplayPowerMode == hal::PowerMode::ON) {
+ step_up = true;
+ }
+ } else if (currentDisplayPowerMode == hal::PowerMode::DOZE_SUSPEND) {
+ if (newDisplayPowerMode == hal::PowerMode::DOZE ||
+ newDisplayPowerMode == hal::PowerMode::ON) {
+ step_up = true;
+ }
+ } else if (currentDisplayPowerMode == hal::PowerMode::DOZE) {
+ if (newDisplayPowerMode == hal::PowerMode::ON) {
+ step_up = true;
+ }
+ }
+ // Change hardware state first while stepping up.
+ if (step_up) {
+ mDisplayConfigIntf->SetPowerMode(*hwcDisplayId, hwcMode);
+ }
+ // Change SF state now.
+ setPowerModeOnMainThread(displayToken, mode);
+ // Change hardware state now while stepping down.
+
+ if (!step_up) {
+ mDisplayConfigIntf->SetPowerMode(*hwcDisplayId, hwcMode);
+ }
+#else
+ setPowerModeOnMainThread(displayToken, mode);
+#endif
+}
+
status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) {
+ size_t numArgs = args.size();
+ if (numArgs && ((args[0] == String16("--file")) ||
+ (args[0] == String16("--allocated_buffers")))) {
+ return doDumpContinuous(fd, args);
+ }
std::string result;
IPCThreadState* ipc = IPCThreadState::self();
@@ -4366,7 +5260,13 @@
(it->second)(args, asProto, result);
dumpLayers = false;
} else if (!asProto) {
- dumpAllLocked(args, result);
+ // selection of mini dumpsys (Format: adb shell dumpsys SurfaceFlinger --mini)
+ if (numArgs && ((args[0] == String16("--mini")))) {
+ dumpMini(result);
+ dumpLayers = false;
+ } else {
+ dumpAllLocked(args, result);
+ }
}
}
@@ -4387,6 +5287,129 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::doDumpContinuous(int fd, const DumpArgs& args) {
+ // Format: adb shell dumpsys SurfaceFlinger --file --no-limit
+ size_t numArgs = args.size();
+ status_t err = NO_ERROR;
+
+ if (args[0] == String16("--allocated_buffers")) {
+ std::string dumpsys;
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ alloc.dump(dumpsys);
+ write(fd, dumpsys.c_str(), dumpsys.size());
+ return NO_ERROR;
+ }
+
+ Mutex::Autolock _l(mFileDump.lock);
+ // Same command is used to start and end dump.
+ mFileDump.running = !mFileDump.running;
+ // selection of full dumpsys or not (defualt, dumpsys will be minimum required)
+ // Format: adb shell dumpsys SurfaceFlinger --file --no-limit --full-dump
+ if (numArgs >= 3 && (args[2] == String16("--full-dump"))) {
+ mFileDump.fullDump = true;
+ }
+ if (mFileDump.running) {
+ std::ofstream ofs;
+ ofs.open(mFileDump.name, std::ofstream::out | std::ofstream::trunc);
+ if (!ofs) {
+ mFileDump.running = false;
+ err = UNKNOWN_ERROR;
+ } else {
+ ofs.close();
+ mFileDump.position = 0;
+ if (numArgs >= 2 && (args[1] == String16("--no-limit"))) {
+ mFileDump.noLimit = true;
+ } else {
+ mFileDump.noLimit = false;
+ }
+ }
+ }
+
+ std::string result;
+ result += mFileDump.running ? "Start" : "End";
+ result += mFileDump.noLimit ? " unlimited" : " fixed limit";
+ result += " dumpsys to file : ";
+ result += mFileDump.name;
+ result += "\n";
+ write(fd, result.c_str(), result.size());
+
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::dumpDrawCycle(bool prePrepare) {
+ Mutex::Autolock _l(mFileDump.lock);
+
+ // User might stop dump collection in middle of prepare & commit.
+ // Collect dumpsys again after commit and replace.
+ if (!mFileDump.running && !mFileDump.replaceAfterCommit) {
+ return;
+ }
+ Vector<String16> args;
+ std::string dumpsys;
+ {
+ Mutex::Autolock lock(mStateLock);
+ if (mFileDump.fullDump) {
+ dumpAllLocked(args, dumpsys);
+ } else {
+ dumpMini(dumpsys);
+ }
+ }
+
+ if (mFileDump.fullDump) {
+ const LayersProto layersProto = dumpDrawingStateProto(SurfaceTracing::TRACE_ALL);
+ const auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ dumpsys.append(LayerProtoParser::layerTreeToString(layerTree));
+ dumpsys.append("\n");
+ dumpsys.append("Offscreen Layers:\n");
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing,
+ [&](Layer* layer) {
+ layer->dumpCallingUidPid(dumpsys);
+ });
+ }
+ }
+
+ char timeStamp[32];
+ char dataSize[32];
+ char hms[32];
+ long millis;
+ struct timeval tv;
+ struct tm *ptm;
+ gettimeofday(&tv, NULL);
+ ptm = localtime(&tv.tv_sec);
+ strftime (hms, sizeof (hms), "%H:%M:%S", ptm);
+ millis = tv.tv_usec / 1000;
+ snprintf(timeStamp, sizeof(timeStamp), "Timestamp: %s.%03ld", hms, millis);
+ snprintf(dataSize, sizeof(dataSize), "Size: %8zu", dumpsys.size());
+ std::fstream fs;
+ fs.open(mFileDump.name, std::ios::app);
+ if (!fs) {
+ ALOGE("Failed to open %s file for dumpsys", mFileDump.name);
+ return;
+ }
+ // Format:
+ // | start code | after commit? | time stamp | dump size | dump data |
+ fs.seekp(mFileDump.position, std::ios::beg);
+ fs << "#@#@-- DUMPSYS START --@#@#" << std::endl;
+ fs << "PostCommit: " << ( prePrepare ? "false" : "true" ) << std::endl;
+ fs << timeStamp << std::endl;
+ fs << dataSize << std::endl;
+ fs << dumpsys << std::endl;
+
+ if (prePrepare) {
+ mFileDump.replaceAfterCommit = true;
+ } else {
+ mFileDump.replaceAfterCommit = false;
+ // Reposition only after commit.
+ // Keep file size to appx 20 MB limit by default, wrap around if exceeds.
+ mFileDump.position = fs.tellp();
+ if (!mFileDump.noLimit && (mFileDump.position > (20 * 1024 * 1024))) {
+ mFileDump.position = 0;
+ }
+ }
+ fs.close();
+}
+
status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
if (asProto && mTracing.isEnabled()) {
mTracing.writeToFileAsync();
@@ -4401,7 +5424,7 @@
}
void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
- StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriod());
+ StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriodFromHWC());
if (args.size() > 1) {
const auto name = String8(args[1]);
@@ -4466,7 +5489,7 @@
mPhaseConfiguration->dump(result);
StringAppendF(&result,
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
- dispSyncPresentTimeOffset, getVsyncPeriod());
+ dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
StringAppendF(&result,
@@ -4696,6 +5719,42 @@
}).get());
}
+void SurfaceFlinger::dumpMini(std::string& result) const {
+ /*
+ * * Dump Display state
+ * */
+ StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size());
+ for (const auto& [token, display] : mDisplays) {
+ display->dump(result);
+ }
+ result.append("\n");
+
+ /*
+ * HWC layer minidump
+ */
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ if (!displayId) {
+ continue;
+ }
+
+ StringAppendF(&result, "Display %s HWC layers:\n", to_string(*displayId).c_str());
+ Layer::miniDumpHeader(result);
+ const DisplayDevice& displayDevice = *display;
+ mCurrentState.traverseInZOrder(
+ [&](Layer* layer) { layer->miniDump(result, displayDevice); });
+ result.append("\n");
+ }
+
+ /*
+ * Dump HWComposer state
+ */
+ result.append("h/w composer state:\n");
+ bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
+ StringAppendF(&result, " h/w composer %s\n", hwcDisabled ? "disabled" : "enabled");
+ getHwComposer().dump(result);
+}
+
void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
@@ -5010,9 +6069,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1036 are currently used for backdoors. The code
+ // Numbers from 1000 to 1036 and 20000 to 20002 are currently used for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1036) {
+ if ((code >= 1000 && code <= 1036) || (code >= 20000 && code <= 20002)) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5331,8 +6390,12 @@
case 1035: {
n = data.readInt32();
mDebugDisplayConfigSetByBackdoor = false;
- if (n >= 0) {
+ const auto numConfigs = mRefreshRateConfigs->getAllRefreshRates().size();
+ if ((n >= 0) && (n < numConfigs)) {
const auto displayToken = getInternalDisplayToken();
+ if(isSupportedConfigSwitch(displayToken, n) != NO_ERROR) {
+ return BAD_VALUE;
+ }
status_t result = setActiveConfig(displayToken, n);
if (result != NO_ERROR) {
return result;
@@ -5353,6 +6416,163 @@
}
return NO_ERROR;
}
+ case 20000: {
+ uint64_t disp = 0;
+ int32_t mode = HWC_POWER_MODE_NORMAL;
+ int32_t tile_h_loc = -1;
+ int32_t tile_v_loc = -1;
+ uint32_t num_h_tiles = 1;
+ uint32_t num_v_tiles = 1;
+ if (data.readUint64(&disp) != NO_ERROR) {
+ err = BAD_TYPE;
+ ALOGE("Invalid 64-bit unsigned-int display id parameter.");
+ break;
+ }
+ if (data.readInt32(&mode) != NO_ERROR) {
+ err = BAD_TYPE;
+ ALOGE("Invalid 32-bit signed-int power mode parameter.");
+ break;
+ }
+ if (data.readInt32(&tile_h_loc) != NO_ERROR) {
+ tile_h_loc = -1;
+ }
+ if (data.readInt32(&tile_v_loc) != NO_ERROR) {
+ tile_v_loc = 0;
+ }
+ if (tile_h_loc < 0) {
+ ALOGI("Debug: Set display = %llu, power mode = %d", (unsigned long long)disp,
+ mode);
+ setPowerMode(getPhysicalDisplayToken(disp), mode);
+ } else {
+#if defined(QTI_DISPLAY_CONFIG_ENABLED) && defined(DISPLAY_CONFIG_TILE_DISPLAY_APIS_1_0)
+ ::DisplayConfig::PowerMode hwcMode = ::DisplayConfig::PowerMode::kOff;
+ switch (mode) {
+ case HWC_POWER_MODE_DOZE:
+ hwcMode = ::DisplayConfig::PowerMode::kDoze;
+ break;
+ case HWC_POWER_MODE_NORMAL:
+ hwcMode = ::DisplayConfig::PowerMode::kOn;
+ break;
+ case HWC_POWER_MODE_DOZE_SUSPEND:
+ hwcMode = ::DisplayConfig::PowerMode::kDozeSuspend;
+ break;
+ default:
+ break;
+ }
+ // A regular display has one h tile and one v tile.
+ mDisplayConfigIntf->GetDisplayTileCount(disp, &num_h_tiles, &num_v_tiles);
+ if (((num_h_tiles * num_v_tiles) < 2) || tile_h_loc >= num_h_tiles
+ || tile_v_loc >= num_v_tiles) {
+ ALOGE("Debug: Display %llu has only %u h tiles and %u v tiles. Not a true "
+ "tile display or invalid tile h or v locations given.",
+ (unsigned long long)disp, num_h_tiles, num_v_tiles);
+ } else {
+ err = mDisplayConfigIntf->SetPowerModeTiled(disp, hwcMode, tile_h_loc,
+ tile_v_loc);
+ if (NO_ERROR != err) {
+ ALOGE("Debug: DisplayConfig::SetPowerModeTiled() returned error %d",
+ err);
+ break;
+ }
+ }
+#endif
+ ALOGI("Debug: Set display = %llu, power mode = %d at tile h loc = %d, tile v "
+ "loc = %d (Has %u h tiles and %u v tiles)", (unsigned long long)disp,
+ mode, tile_h_loc, tile_v_loc, num_h_tiles, num_v_tiles);
+ }
+ return NO_ERROR;
+ }
+ case 20001: {
+ uint64_t disp = 0;
+ int32_t level = 0;
+ int32_t tile_h_loc = -1;
+ int32_t tile_v_loc = -1;
+ uint32_t num_h_tiles = 1;
+ uint32_t num_v_tiles = 1;
+ if (data.readUint64(&disp) != NO_ERROR) {
+ err = BAD_TYPE;
+ ALOGE("Invalid 64-bit unsigned-int display id parameter.");
+ break;
+ }
+ if (data.readInt32(&level) != NO_ERROR) {
+ err = BAD_TYPE;
+ ALOGE("Invalid 32-bit signed-int brightess parameter.");
+ break;
+ }
+ float levelf = static_cast<float>(level)/255.0f;
+ if (data.readInt32(&tile_h_loc) != NO_ERROR) {
+ tile_h_loc = -1;
+ }
+ if (data.readInt32(&tile_v_loc) != NO_ERROR) {
+ tile_v_loc = 0;
+ }
+ if (tile_h_loc < 0) {
+ ALOGI("Debug: Set display = %llu, brightness level = %d/255 (%0.2ff)",
+ (unsigned long long)disp, level, levelf);
+ setDisplayBrightness(getPhysicalDisplayToken(disp), levelf);
+ } else {
+#if defined(QTI_DISPLAY_CONFIG_ENABLED) && defined(DISPLAY_CONFIG_TILE_DISPLAY_APIS_1_0)
+ // A regular display has one h tile and one v tile.
+ mDisplayConfigIntf->GetDisplayTileCount(disp, &num_h_tiles, &num_v_tiles);
+ if (((num_h_tiles * num_v_tiles) < 2) || tile_h_loc >= num_h_tiles
+ || tile_v_loc >= num_v_tiles) {
+ ALOGE("Debug: Display %llu has only %u h tiles and %u v tiles. Not a true "
+ "tile display or invalid tile h or v locations given.",
+ (unsigned long long)disp, num_h_tiles, num_v_tiles);
+ } else {
+ err = mDisplayConfigIntf->SetPanelBrightnessTiled(disp, level, tile_h_loc,
+ tile_v_loc);
+ if (NO_ERROR != err) {
+ ALOGE("Debug: DisplayConfig::SetPanelBrightnessTiled() returned error "
+ "%d", err);
+ break;
+ }
+ }
+#endif
+ ALOGI("Debug: Set display = %llu, brightness level = %d/255 (%0.2ff) at tile h "
+ "loc = %d, tile v loc = %d (Has %u h tiles and %u v tiles)",
+ (unsigned long long)disp, level, levelf, tile_h_loc, tile_v_loc,
+ num_h_tiles, num_v_tiles);
+ }
+ return NO_ERROR;
+ }
+ case 20002: {
+ uint64_t disp = 0;
+ int32_t pref = 0;
+ if (data.readUint64(&disp) != NO_ERROR) {
+ err = BAD_TYPE;
+ ALOGE("Invalid 64-bit unsigned-int display id parameter.");
+ break;
+ }
+ if (data.readInt32(&pref) != NO_ERROR) {
+ err = BAD_TYPE;
+ ALOGE("Invalid 32-bit signed-int wider-mode preference parameter.");
+ break;
+ }
+ ALOGI("Debug: Set display = %llu, wider-mode preference = %d",
+ (unsigned long long)disp, pref);
+#if defined(QTI_DISPLAY_CONFIG_ENABLED) && defined(DISPLAY_CONFIG_TILE_DISPLAY_APIS_1_0)
+ ::DisplayConfig::WiderModePref wider_mode_pref =
+ ::DisplayConfig::WiderModePref::kNoPreference;
+ switch (pref) {
+ case 1:
+ wider_mode_pref = ::DisplayConfig::WiderModePref::kWiderAsyncMode;
+ break;
+ case 2:
+ wider_mode_pref = ::DisplayConfig::WiderModePref::kWiderSyncMode;
+ break;
+ default:
+ // Use default DisplayConfig::WiderModePref::kNoPreference.
+ break;
+ }
+ err = mDisplayConfigIntf->SetWiderModePreference(disp, wider_mode_pref);
+ if (NO_ERROR != err) {
+ ALOGE("Debug: DisplayConfig::SetWiderModePreference() returned error %d", err);
+ break;
+ }
+#endif
+ return NO_ERROR;
+ }
}
}
return err;
@@ -5365,7 +6585,7 @@
void SurfaceFlinger::repaintEverythingForHWC() {
mRepaintEverything = true;
- mPowerAdvisor.notifyDisplayUpdateImminent();
+ notifyAllDisplaysUpdateImminent();
mEventQueue->invalidate();
}
@@ -5860,6 +7080,9 @@
std::vector<Layer*> renderedLayers;
Region clearRegion = Region::INVALID_REGION;
traverseLayers([&](Layer* layer) {
+ if (layer->isSecureDisplay()) {
+ return;
+ }
const bool supportProtectedContent = false;
Region clip(renderArea.getBounds());
compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
@@ -5998,6 +7221,8 @@
LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy");
if (!display->isPrimary()) {
+ return NO_ERROR;
+
// TODO(b/144711714): For non-primary displays we should be able to set an active config
// as well. For now, just call directly to setActiveConfigWithConstraints but ideally
// it should go thru setDesiredActiveConfig, similar to primary display.
@@ -6025,6 +7250,14 @@
->getVsyncPeriod();
mScheduler->onNonPrimaryDisplayConfigChanged(mAppConnectionHandle, display->getId()->value,
policy->defaultConfig, vsyncPeriod);
+
+ if (isInternalDisplay(display)) {
+ uint32_t hwcDisplayId;
+ if (getHwcDisplayId(display, &hwcDisplayId)) {
+ setDisplayExtnActiveConfig(hwcDisplayId, policy->defaultConfig.value());
+ }
+ }
+
return NO_ERROR;
}
@@ -6072,6 +7305,10 @@
preferredRefreshRate.getConfigId().value());
setDesiredActiveConfig(
{preferredRefreshRate.getConfigId(), Scheduler::ConfigEvent::Changed});
+ uint32_t hwcDisplayId;
+ if (getHwcDisplayId(display, &hwcDisplayId)) {
+ setDisplayExtnActiveConfig(hwcDisplayId, preferredRefreshRate.getConfigId().value());
+ }
} else {
LOG_ALWAYS_FATAL("Desired config not allowed: %d",
preferredRefreshRate.getConfigId().value());
@@ -6080,6 +7317,27 @@
return NO_ERROR;
}
+bool SurfaceFlinger::canAllocateHwcDisplayIdForVDS(uint64_t usage) {
+ uint64_t flag_mask_pvt_wfd = ~0;
+ uint64_t flag_mask_hw_video = ~0;
+ char value[PROPERTY_VALUE_MAX] = {};
+ property_get("vendor.display.vds_allow_hwc", value, "0");
+ int allowHwcForVDS = atoi(value);
+ // Reserve hardware acceleration for WFD use-case
+ // GRALLOC_USAGE_PRIVATE_WFD + GRALLOC_USAGE_HW_VIDEO_ENCODER = WFD using HW composer.
+ flag_mask_pvt_wfd = GRALLOC_USAGE_PRIVATE_WFD;
+ flag_mask_hw_video = GRALLOC_USAGE_HW_VIDEO_ENCODER;
+ // GRALLOC_USAGE_PRIVATE_WFD + GRALLOC_USAGE_SW_READ_OFTEN
+ // WFD using GLES (directstreaming).
+ sDirectStreaming = ((usage & GRALLOC_USAGE_PRIVATE_WFD) &&
+ (usage & GRALLOC_USAGE_SW_READ_OFTEN));
+ return (allowHwcForVDS || ((usage & flag_mask_pvt_wfd) &&
+ (usage & flag_mask_hw_video)));
+}
+
+bool SurfaceFlinger::skipColorLayer(const char* layerType) {
+ return (sDirectStreaming && !strncmp(layerType, "ColorLayer", strlen("ColorLayer")));
+}
status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t defaultConfig,
float primaryRefreshRateMin,
@@ -6252,6 +7510,11 @@
Mutex::Autolock lock(mStateLock);
if (authenticateSurfaceTextureLocked(surface)) {
sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
+ if (layer == nullptr) {
+ ALOGE("Attempt to set frame rate on a layer that no longer exists");
+ return BAD_VALUE;
+ }
+
if (layer->setFrameRate(
Layer::FrameRate(frameRate,
Layer::FrameRate::convertCompatibility(compatibility)))) {
@@ -6358,6 +7621,210 @@
}));
}
+void SurfaceFlinger::setContentFps(uint32_t contentFps) {
+ if (mBootFinished && !mSetActiveConfigPending) {
+ if (mDisplayExtnIntf) {
+ mDisplayExtnIntf->SetContentFps(contentFps);
+ }
+ }
+}
+
+bool SurfaceFlinger::isInternalDisplay(const sp<DisplayDevice>& display) {
+ if (display) {
+ const auto connectionType = display->getConnectionType();
+ return (connectionType && (*connectionType == DisplayConnectionType::Internal));
+ }
+ return false;
+}
+
+bool SurfaceFlinger::getHwcDisplayId(const sp<DisplayDevice>& display, uint32_t *hwcDisplayId) {
+ if (display) {
+ const auto displayId = display->getId();
+ if (displayId) {
+ const auto halDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
+ if (halDisplayId) {
+ *hwcDisplayId = static_cast<uint32_t>(*halDisplayId);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void SurfaceFlinger::updateDisplayExtension(uint32_t displayId, uint32_t configId, bool connected) {
+ ALOGV("updateDisplayExtn: Display:%d, Config:%d, Connected:%d", displayId, configId, connected);
+
+#ifdef EARLY_WAKEUP_FEATURE
+ if (connected) {
+ mDisplayExtnIntf->RegisterDisplay(displayId);
+ mDisplayExtnIntf->SetActiveConfig(displayId, configId);
+ } else {
+ mDisplayExtnIntf->UnregisterDisplay(displayId);
+ }
+#endif
+}
+
+void SurfaceFlinger::setDisplayExtnActiveConfig(uint32_t displayId, uint32_t activeConfigId) {
+ if (!mEarlyWakeUpEnabled) {
+ return;
+ }
+
+ ALOGV("setDisplayExtnActiveConfig: Display:%d, ActiveConfig:%d", displayId, activeConfigId);
+#ifdef EARLY_WAKEUP_FEATURE
+ mDisplayExtnIntf->SetActiveConfig(displayId, activeConfigId);
+#endif
+}
+
+void SurfaceFlinger::notifyAllDisplaysUpdateImminent() {
+ if (!mEarlyWakeUpEnabled) {
+ mPowerAdvisor.notifyDisplayUpdateImminent();
+ return;
+ }
+
+#ifdef EARLY_WAKEUP_FEATURE
+ if (mPowerAdvisor.canNotifyDisplayUpdateImminent()) {
+ ATRACE_CALL();
+ // Notify Display Extn for GPU and Display Early Wakeup
+ mDisplayExtnIntf->NotifyEarlyWakeUp(true, true);
+ }
+#endif
+}
+
+void SurfaceFlinger::notifyDisplayUpdateImminent() {
+ if (!mEarlyWakeUpEnabled) {
+ mPowerAdvisor.notifyDisplayUpdateImminent();
+ return;
+ }
+
+#ifdef EARLY_WAKEUP_FEATURE
+ if (mPowerAdvisor.canNotifyDisplayUpdateImminent()) {
+ ATRACE_CALL();
+
+ if (mInternalPresentationDisplays) {
+ // Notify Display Extn for GPU Early Wakeup only
+ mDisplayExtnIntf->NotifyEarlyWakeUp(true, false);
+ wakeUpPresentationDisplays = true;
+ } else {
+ // Notify Display Extn for GPU and Display Early Wakeup
+ mDisplayExtnIntf->NotifyEarlyWakeUp(true, true);
+ }
+ }
+#endif
+}
+
+void SurfaceFlinger::handlePresentationDisplaysEarlyWakeup(size_t updatingDisplays,
+ uint32_t layerStackId) {
+ // Filter-out the updating display(s) for early wake-up in Presentation mode.
+ if (mEarlyWakeUpEnabled && mInternalPresentationDisplays) {
+ ATRACE_CALL();
+ uint32_t hwcDisplayId;
+ bool internalDisplay = false;
+ bool singleUpdatingDisplay = (updatingDisplays == 1);
+
+ if (singleUpdatingDisplay) {
+ Mutex::Autolock lock(mStateLock);
+ const sp<DisplayDevice> display = getDisplayByLayerStack(layerStackId);
+ internalDisplay = isInternalDisplay(display) && getHwcDisplayId(display, &hwcDisplayId);
+ }
+
+#ifdef EARLY_WAKEUP_FEATURE
+ if (!singleUpdatingDisplay) {
+ // Notify Display Extn for Early Wakeup of displays
+ mDisplayExtnIntf->NotifyEarlyWakeUp(false, true);
+ } else if (internalDisplay) {
+ // Notify Display Extn for Early Wakeup of given display
+ mDisplayExtnIntf->NotifyDisplayEarlyWakeUp(hwcDisplayId);
+ }
+#endif
+
+ }
+ wakeUpPresentationDisplays = false;
+}
+
+void SurfaceFlinger::updateInternalDisplaysPresentationMode() {
+ mInternalPresentationDisplays = false;
+ if (mDisplaysList.size() <= 1) {
+ return;
+ }
+
+ bool compareStack = false;
+ ui::LayerStack previousStackId;
+ for (const auto& display : mDisplaysList) {
+ if (isInternalDisplay(display)) {
+ auto currentStackId = display->getLayerStack();
+ // Compare Layer Stack IDs of Internal Displays
+ if (compareStack && (previousStackId != currentStackId)) {
+ mInternalPresentationDisplays = true;
+ return;
+ }
+ previousStackId = currentStackId;
+ compareStack = true;
+ }
+ }
+}
+
+void SurfaceFlinger::NotifyIdleStatus() {
+ mScheduler->setIdleState();
+}
+
+void SurfaceFlinger::setupEarlyWakeUpFeature() {
+#ifdef EARLY_WAKEUP_FEATURE
+ mEarlyWakeUpEnabled = false;
+ char propValue[PROPERTY_VALUE_MAX];
+ property_get("vendor.display.enable_early_wakeup", propValue, "0");
+ if (mDisplayExtnIntf && (atoi(propValue) == 1)) {
+ for (const auto& display : mDisplaysList) {
+ // Register Internal Physical Displays
+ if (isInternalDisplay(display)) {
+ uint32_t hwcDisplayId;
+ if (getHwcDisplayId(display, &hwcDisplayId)) {
+ const auto displayId = display->getId();
+ uint32_t configId = getHwComposer().getActiveConfigIndex(*displayId);
+ updateDisplayExtension(hwcDisplayId, configId, true);
+ }
+ }
+ }
+ mEarlyWakeUpEnabled = true;
+ }
+ ALOGI("Early Wakeup Feature enabled: %d", mEarlyWakeUpEnabled);
+#endif
+}
+
+void SurfaceFlinger::createPhaseOffsetExtn() {
+#ifdef PHASE_OFFSET_EXTN
+ if (mUseAdvanceSfOffset) {
+ int ret = mComposerExtnIntf->CreatePhaseOffsetExtn(&g_comp_ext_intf_.phaseOffsetExtnIntf);
+ if (ret) {
+ ALOGI("Unable to create PhaseOffset extension");
+ return;
+ }
+
+ // Get the Advanced SF Offsets from Phase Offset Extn
+ std::unordered_map<float, int64_t> advancedSfOffsets;
+ g_comp_ext_intf_.phaseOffsetExtnIntf->GetAdvancedSfOffsets(&advancedSfOffsets);
+
+ // Update the Advanced SF Offsets
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mPhaseConfiguration->UpdateSfOffsets(advancedSfOffsets);
+ mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
+ }
+#endif
+}
+
+void SurfaceFlinger::setEarlyWakeUpConfig(const sp<DisplayDevice>& display, hal::PowerMode mode) {
+ if (mEarlyWakeUpEnabled && isInternalDisplay(display)) {
+ uint32_t hwcDisplayId;
+ if (getHwcDisplayId(display, &hwcDisplayId)) {
+ // Enable/disable Early Wake-up feature on a display based on its Power mode.
+ bool enable = (mode == hal::PowerMode::ON) || (mode == hal::PowerMode::DOZE);
+ ALOGV("setEarlyWakeUpConfig: Display: %d, Enable: %d", hwcDisplayId, enable);
+#ifdef DYNAMIC_EARLY_WAKEUP_CONFIG
+ mDisplayExtnIntf->SetEarlyWakeUpConfig(hwcDisplayId, enable);
+#endif
+ }
+ }
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 913158f..54cdefd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -81,9 +81,34 @@
#include <unordered_map>
#include <unordered_set>
#include <utility>
+#include <list>
using namespace android::surfaceflinger;
+namespace smomo {
+class SmomoIntf;
+} // namespace smomo
+
+namespace composer {
+class ComposerExtnIntf;
+class ComposerExtnLib;
+class FrameSchedulerIntf;
+class DisplayExtnIntf;
+} // namespace composer
+
+using smomo::SmomoIntf;
+
+namespace composer {
+class LayerExtnIntf;
+}
+
+using composer::LayerExtnIntf;
+
+namespace composer {
+class FrameExtnIntf;
+}
+using composer::FrameExtnIntf;
+
namespace android {
class Client;
@@ -172,6 +197,52 @@
int32_t mComposerSequenceId = 0;
};
+class SmomoWrapper {
+public:
+ SmomoWrapper() {}
+ ~SmomoWrapper();
+
+ bool init();
+
+ SmomoIntf* operator->() { return mInst; }
+ operator bool() { return mInst != nullptr; }
+
+ SmomoWrapper(const SmomoWrapper&) = delete;
+ SmomoWrapper& operator=(const SmomoWrapper&) = delete;
+
+private:
+ SmomoIntf *mInst = nullptr;
+ void *mSmoMoLibHandle = nullptr;
+
+ using CreateSmoMoFuncPtr = std::add_pointer<bool(uint16_t, SmomoIntf**)>::type;
+ using DestroySmoMoFuncPtr = std::add_pointer<void(SmomoIntf*)>::type;
+ CreateSmoMoFuncPtr mSmoMoCreateFunc;
+ DestroySmoMoFuncPtr mSmoMoDestroyFunc;
+};
+
+class LayerExtWrapper {
+public:
+ LayerExtWrapper() {}
+ ~LayerExtWrapper();
+
+ bool init();
+
+ LayerExtnIntf* operator->() { return mInst; }
+ operator bool() { return mInst != nullptr; }
+
+ LayerExtWrapper(const LayerExtWrapper&) = delete;
+ LayerExtWrapper& operator=(const LayerExtWrapper&) = delete;
+
+private:
+ LayerExtnIntf *mInst = nullptr;
+ void *mLayerExtLibHandle = nullptr;
+
+ using CreateLayerExtnFuncPtr = std::add_pointer<bool(uint16_t, LayerExtnIntf**)>::type;
+ using DestroyLayerExtnFuncPtr = std::add_pointer<void(LayerExtnIntf*)>::type;
+ CreateLayerExtnFuncPtr mLayerExtCreateFunc;
+ DestroyLayerExtnFuncPtr mLayerExtDestroyFunc;
+};
+
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
public ClientCache::ErasedRecipient,
@@ -242,6 +313,8 @@
static bool useContextPriority;
+ static bool sDirectStreaming;
+
// The data space and pixel format that SurfaceFlinger expects hardware composer
// to composite efficiently. Meaning under most scenarios, hardware composer
// will accept layers with the data space and pixel format.
@@ -298,10 +371,10 @@
// enable/disable h/w composer event
// TODO: this should be made accessible only to EventThread
- void setPrimaryVsyncEnabled(bool enabled);
+ void setVsyncEnabled(bool enabled);
// main thread function to enable/disable h/w composer event
- void setPrimaryVsyncEnabledInternal(bool enabled) REQUIRES(mStateLock);
+ void setVsyncEnabledInternal(bool enabled) REQUIRES(mStateLock);
// called on the main thread by MessageQueue when an internal message
// is received
@@ -336,6 +409,10 @@
// debug.sf.disable_client_composition_cache
bool mDisableClientCompositionCache = false;
+ nsecs_t mVsyncTimeStamp = -1;
+
+ void NotifyIdleStatus();
+
private:
friend class BufferLayer;
friend class BufferQueueLayer;
@@ -504,6 +581,9 @@
status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
int8_t compatibility) override;
status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override;
+ status_t setDisplayElapseTime(const sp<DisplayDevice>& display) const;
+ status_t isSupportedConfigSwitch(const sp<IBinder>& displayToken, int config);
+
/* ------------------------------------------------------------------------
* DeathRecipient interface
*/
@@ -526,6 +606,7 @@
int32_t sequenceId, hal::HWDisplayId display,
const hal::VsyncPeriodChangeTimeline& updatedTimeline) override;
void onSeamlessPossible(int32_t sequenceId, hal::HWDisplayId display) override;
+ void setPowerModeOnMainThread(const sp<IBinder>& displayToken, int mode);
/* ------------------------------------------------------------------------
* ISchedulerCallback
@@ -607,6 +688,7 @@
void commitInputWindowCommands() REQUIRES(mStateLock);
void setInputWindowsFinished();
void updateCursorAsync();
+ void updateFrameScheduler();
void initScheduler(DisplayId primaryDisplayId);
/* handlePageFlip - latch a new buffer if available and compute the dirty
@@ -645,6 +727,7 @@
bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
const Vector<ComposerState>& states);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
+ void checkVirtualDisplayHint(const Vector<DisplayState>& displays);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
REQUIRES(mStateLock);
@@ -737,6 +820,9 @@
void traverseLayersInDisplay(const sp<const DisplayDevice>& display,
const LayerVector::Visitor& visitor);
+
+ bool canAllocateHwcDisplayIdForVDS(uint64_t usage);
+ bool skipColorLayer(const char* layerType);
sp<StartPropertySetThread> mStartPropertySetThread;
/* ------------------------------------------------------------------------
@@ -819,6 +905,9 @@
*/
void invalidateHwcGeometry();
+ sp<DisplayDevice> getVsyncSource();
+ void updateVsyncSource();
+ void forceResyncModel();
void postComposition();
void getCompositorTiming(CompositorTiming* compositorTiming);
void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
@@ -845,19 +934,23 @@
const DisplayDeviceState& currentState,
const DisplayDeviceState& drawingState) REQUIRES(mStateLock);
void processDisplayHotplugEventsLocked() REQUIRES(mStateLock);
+ void setFrameBufferSizeForScaling(sp<DisplayDevice> displayDevice,
+ const DisplayDeviceState& state);
void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
/* ------------------------------------------------------------------------
* VSync
*/
- nsecs_t getVsyncPeriod() const REQUIRES(mStateLock);
+ nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
// Sets the refresh rate by switching active configs, if they are available for
// the desired refresh rate.
void changeRefreshRateLocked(const RefreshRate&, Scheduler::ConfigEvent event)
REQUIRES(mStateLock);
+ void setRefreshRateTo(int32_t refreshRate);
+
bool isDisplayConfigAllowed(HwcConfigIndexType configId) const REQUIRES(mStateLock);
// Gets the fence for the previous frame.
@@ -940,7 +1033,7 @@
}
void dumpAllLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
-
+ void dumpMini(std::string& result) const REQUIRES(mStateLock);
void appendSfConfigString(std::string& result) const;
void listLayersLocked(std::string& result) const;
void dumpStatsLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
@@ -974,6 +1067,19 @@
status_t doDump(int fd, const DumpArgs& args, bool asProto);
+ status_t doDumpContinuous(int fd, const DumpArgs& args);
+ void dumpDrawCycle(bool prePrepare);
+
+ struct {
+ Mutex lock;
+ const char *name = "/data/misc/wmtrace/dumpsys.txt";
+ bool running = false;
+ bool noLimit = false;
+ bool fullDump = false;
+ bool replaceAfterCommit = false;
+ long int position = 0;
+ } mFileDump;
+
status_t dumpCritical(int fd, const DumpArgs&, bool asProto);
status_t dumpAll(int fd, const DumpArgs& args, bool asProto) override {
@@ -982,6 +1088,30 @@
void onFrameRateFlexibilityTokenReleased();
+ void setContentFps(uint32_t contentFps);
+
+ bool isInternalDisplay(const sp<DisplayDevice>& display);
+
+ bool getHwcDisplayId(const sp<DisplayDevice>& display, uint32_t *hwcDisplayId);
+
+ void updateDisplayExtension(uint32_t displayId, uint32_t configId, bool connected);
+
+ void setDisplayExtnActiveConfig(uint32_t displayId, uint32_t activeConfigId);
+
+ void notifyAllDisplaysUpdateImminent();
+
+ void notifyDisplayUpdateImminent();
+
+ void handlePresentationDisplaysEarlyWakeup(size_t updatingDisplays, uint32_t layerStackId);
+
+ void updateInternalDisplaysPresentationMode();
+
+ void setupEarlyWakeUpFeature();
+
+ void createPhaseOffsetExtn();
+
+ void setEarlyWakeUpConfig(const sp<DisplayDevice>& display, hal::PowerMode mode);
+
/* ------------------------------------------------------------------------
* VrFlinger
*/
@@ -1000,6 +1130,8 @@
// access must be protected by mStateLock
mutable Mutex mStateLock;
+ mutable Mutex mVsyncLock;
+ mutable Mutex mDolphinStateLock;
State mCurrentState{LayerVector::StateSet::Current};
std::atomic<int32_t> mTransactionFlags = 0;
Condition mTransactionCV;
@@ -1075,6 +1207,8 @@
// don't use a lock for these, we don't care
int mDebugRegion = 0;
+ bool mVsyncSourceReliableOnDoze = false;
+ bool mPluggableVsyncPrioritized = false;
bool mDebugDisableHWC = false;
bool mDebugDisableTransformHint = false;
volatile nsecs_t mDebugInTransaction = 0;
@@ -1098,10 +1232,16 @@
std::atomic<bool> mDisableBlurs = false;
// If blurs are considered expensive and should require high GPU frequency.
bool mBlursAreExpensive = false;
+ bool mUseAdvanceSfOffset = false;
+ bool mUseFbScaling = false;
+ bool mAsyncVdsCreationSupported = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
std::atomic<uint32_t> mHwcFrameMissedCount = 0;
std::atomic<uint32_t> mGpuFrameMissedCount = 0;
+ std::mutex mVsyncPeriodMutex;
+ std::vector<nsecs_t> mVsyncPeriods;
+
TransactionCompletedThread mTransactionCompletedThread;
// Restrict layers to use two buffers in their bufferqueues.
@@ -1162,6 +1302,10 @@
bool mHasPoweredOff = false;
std::atomic<size_t> mNumLayers = 0;
+ // Vsync Source
+ sp<DisplayDevice> mActiveVsyncSource = NULL;
+ sp<DisplayDevice> mNextVsyncSource = NULL;
+ std::list<sp<DisplayDevice>> mDisplaysList;
// Verify that transaction is being called by an approved process:
// either AID_GRAPHICS or AID_SYSTEM.
@@ -1295,6 +1439,39 @@
int mFrameRateFlexibilityTokenCount = 0;
sp<IBinder> mDebugFrameRateFlexibilityToken;
+
+ SmomoWrapper mSmoMo;
+ LayerExtWrapper mLayerExt;
+
+public:
+ nsecs_t mRefreshTimeStamp = -1;
+ nsecs_t mVsyncPeriod = -1;
+ std::string mNameLayerMax;
+ int mMaxQueuedFrames = -1;
+ int mNumIdle = -1;
+
+private:
+ bool mEarlyWakeUpEnabled = false;
+ bool wakeUpPresentationDisplays = false;
+ bool mInternalPresentationDisplays = false;
+ bool mDolphinFuncsEnabled = false;
+ void *mDolphinHandle = nullptr;
+ bool (*mDolphinInit)() = nullptr;
+ bool (*mDolphinMonitor)(int number, nsecs_t vsyncPeriod) = nullptr;
+ void (*mDolphinScaling)(int numIdle, int maxQueuedFrames) = nullptr;
+ void (*mDolphinRefresh)() = nullptr;
+ void (*mDolphinDequeueBuffer)(const char *name) = nullptr;
+ void (*mDolphinQueueBuffer)(const char *name) = nullptr;
+
+ FrameExtnIntf* mFrameExtn = nullptr;
+ void *mFrameExtnLibHandle = nullptr;
+ bool (*mCreateFrameExtnFunc)(FrameExtnIntf **interface) = nullptr;
+ bool (*mDestroyFrameExtnFunc)(FrameExtnIntf *interface) = nullptr;
+ composer::ComposerExtnIntf *mComposerExtnIntf = nullptr;
+ composer::FrameSchedulerIntf *mFrameSchedulerExtnIntf = nullptr;
+ composer::DisplayExtnIntf *mDisplayExtnIntf = nullptr;
+ bool mUseLayerExt = false;
+ bool mSplitLayerExt = false;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index ce5f35c..06bdcdc 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -85,7 +85,7 @@
using HotplugEvent = TestableSurfaceFlinger::HotplugEvent;
using HWC2Display = TestableSurfaceFlinger::HWC2Display;
-constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
+constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'667;
constexpr int32_t DEFAULT_DPI = 320;
constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index b50ddf5..2a59a28 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -35,6 +35,7 @@
void setRefreshRateFps(float) override {}
void dump(std::string&) const override {}
+ void UpdateSfOffsets(std::unordered_map<float, int64_t>) override {}
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 1aa7320..72c4395 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -115,7 +115,8 @@
ASSERT_NO_FATAL_FAILURE(
connection = mScheduler->createDisplayEventConnection(handle,
ISurfaceComposer::
- eConfigChangedSuppress));
+ eConfigChangedSuppress,
+ false /* No Refresh */));
EXPECT_FALSE(connection);
EXPECT_FALSE(mScheduler->getEventConnection(handle));
@@ -143,7 +144,9 @@
ASSERT_NO_FATAL_FAILURE(
connection = mScheduler->createDisplayEventConnection(mConnectionHandle,
ISurfaceComposer::
- eConfigChangedSuppress));
+ eConfigChangedSuppress,
+ false /* No Refresh */));
+
ASSERT_EQ(mEventThreadConnection, connection);
EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle));
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index d5ecae8..7b1c8f7 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -51,7 +51,7 @@
// Used to inject mock event thread.
ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
- return Scheduler::createConnection(std::move(eventThread));
+ return Scheduler::createConnection(std::move(eventThread), false /* No Refresh */);
}
size_t layerHistorySize() const NO_THREAD_SAFETY_ANALYSIS {
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index be49ef3..c2a7752 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -51,6 +51,7 @@
void setPeriod(nsecs_t) final {}
void resetModel() final {}
+ bool needsMoreSamples() const final { return false; }
void dump(std::string&) const final {}
private:
@@ -86,6 +87,7 @@
void setPeriod(nsecs_t) final {}
void resetModel() final {}
+ bool needsMoreSamples() const final { return false; }
void dump(std::string&) const final {}
private:
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index d940dc5..373f6a5 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -47,6 +47,7 @@
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
MOCK_METHOD0(resetModel, void());
+ MOCK_CONST_METHOD0(needsMoreSamples, bool());
MOCK_CONST_METHOD1(dump, void(std::string&));
nsecs_t nextVSyncTime(nsecs_t timePoint) const {
@@ -115,11 +116,15 @@
operator VSyncDispatch::CallbackToken() const { return mToken; }
- void counter(nsecs_t time, nsecs_t) { mCalls.push_back(time); }
+ void counter(nsecs_t time, nsecs_t wakeup_time) {
+ mCalls.push_back(time);
+ mWakeupTime.push_back(wakeup_time);
+ }
VSyncDispatch& mDispatch;
VSyncDispatch::CallbackToken mToken;
std::vector<nsecs_t> mCalls;
+ std::vector<nsecs_t> mWakeupTime;
};
class PausingCallback {
@@ -747,6 +752,31 @@
EXPECT_THAT(cb2.mCalls.size(), Eq(1));
}
+TEST_F(VSyncDispatchTimerQueueTest, laggedTimerGroupsCallbacksWithinLag) {
+ CountingCallback cb1(mDispatch);
+ CountingCallback cb2(mDispatch);
+
+ Sequence seq;
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+ .InSequence(seq)
+ .WillOnce(Return(1000));
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+ .InSequence(seq)
+ .WillOnce(Return(1000));
+
+ EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2, 390, 1000), ScheduleResult::Scheduled);
+
+ mMockClock.setLag(100);
+ mMockClock.advanceBy(700);
+
+ ASSERT_THAT(cb1.mWakeupTime.size(), Eq(1));
+ EXPECT_THAT(cb1.mWakeupTime[0], Eq(600));
+ ASSERT_THAT(cb2.mWakeupTime.size(), Eq(1));
+ EXPECT_THAT(cb2.mWakeupTime[0], Eq(610));
+}
+
class VSyncDispatchTimerQueueEntryTest : public testing::Test {
protected:
nsecs_t const mPeriod = 1000;
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index fc39235..d4cd11d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -73,27 +73,27 @@
TEST_F(VSyncPredictorTest, reportsSamplesNeededWhenHasNoDataPoints) {
for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
- EXPECT_TRUE(tracker.needsMoreSamples(mNow += mPeriod));
- tracker.addVsyncTimestamp(mNow);
+ EXPECT_TRUE(tracker.needsMoreSamples());
+ tracker.addVsyncTimestamp(mNow += mPeriod);
}
- EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+ EXPECT_FALSE(tracker.needsMoreSamples());
}
TEST_F(VSyncPredictorTest, reportsSamplesNeededAfterExplicitRateChange) {
for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
tracker.addVsyncTimestamp(mNow += mPeriod);
}
- EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+ EXPECT_FALSE(tracker.needsMoreSamples());
auto const changedPeriod = mPeriod * 2;
tracker.setPeriod(changedPeriod);
- EXPECT_TRUE(tracker.needsMoreSamples(mNow));
+ EXPECT_TRUE(tracker.needsMoreSamples());
for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
- EXPECT_TRUE(tracker.needsMoreSamples(mNow += changedPeriod));
- tracker.addVsyncTimestamp(mNow);
+ EXPECT_TRUE(tracker.needsMoreSamples());
+ tracker.addVsyncTimestamp(mNow += changedPeriod);
}
- EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+ EXPECT_FALSE(tracker.needsMoreSamples());
}
TEST_F(VSyncPredictorTest, transitionsToModelledPointsAfterSynthetic) {
@@ -320,20 +320,6 @@
EXPECT_THAT(intercept, Eq(0));
}
-TEST_F(VSyncPredictorTest, willBecomeInaccurateAfterA_longTimeWithNoSamples) {
- auto const simulatedVsyncs = generateVsyncTimestamps(kMinimumSamplesForPrediction, mPeriod, 0);
-
- for (auto const& timestamp : simulatedVsyncs) {
- tracker.addVsyncTimestamp(timestamp);
- }
- auto const mNow = *simulatedVsyncs.rbegin();
- EXPECT_FALSE(tracker.needsMoreSamples(mNow));
-
- // TODO: would be better to decay this as a result of the variance of the samples
- static auto constexpr aLongTimeOut = 1000000000;
- EXPECT_TRUE(tracker.needsMoreSamples(mNow + aLongTimeOut));
-}
-
TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) {
auto const simulatedVsyncs =
generateVsyncTimestamps(kMinimumSamplesForPrediction + 1, mPeriod, 0);
@@ -443,7 +429,7 @@
// When VsyncPredictor returns the period it means that it doesn't know how to predict and
// it needs to get more samples
if (slope == mPeriod && intercept == 0) {
- EXPECT_TRUE(tracker.needsMoreSamples(now));
+ EXPECT_TRUE(tracker.needsMoreSamples());
}
}
}
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index a972562..6856612 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -41,6 +41,7 @@
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
MOCK_METHOD0(resetModel, void());
+ MOCK_CONST_METHOD0(needsMoreSamples, bool());
MOCK_CONST_METHOD1(dump, void(std::string&));
};
@@ -57,6 +58,7 @@
nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
void resetModel() final { mTracker->resetModel(); }
+ bool needsMoreSamples() const final { return mTracker->needsMoreSamples(); }
void dump(std::string& result) const final { mTracker->dump(result); }
private:
@@ -455,6 +457,83 @@
EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
}
+TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTracker) {
+ auto time = 0;
+ bool periodFlushed = false;
+ nsecs_t const newPeriod = 4000;
+ mReactor.setPeriod(newPeriod);
+
+ static auto constexpr numSamplesWithNewPeriod = 4;
+ Sequence seq;
+ EXPECT_CALL(*mMockTracker, needsMoreSamples())
+ .Times(numSamplesWithNewPeriod - 2)
+ .InSequence(seq)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*mMockTracker, needsMoreSamples())
+ .Times(1)
+ .InSequence(seq)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(numSamplesWithNewPeriod);
+
+ EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+
+ EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+ // confirmed period, but predictor wants numRequest samples. This one and prior are valid.
+ EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed));
+}
+
+TEST_F(VSyncReactorTest, hwVsyncturnsOffOnConfirmationWhenTrackerDoesntRequest) {
+ auto time = 0;
+ bool periodFlushed = false;
+ nsecs_t const newPeriod = 4000;
+ mReactor.setPeriod(newPeriod);
+
+ Sequence seq;
+ EXPECT_CALL(*mMockTracker, needsMoreSamples())
+ .Times(1)
+ .InSequence(seq)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2);
+
+ EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed));
+}
+
+TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTrackerMultiplePeriodChanges) {
+ auto time = 0;
+ bool periodFlushed = false;
+ nsecs_t const newPeriod1 = 4000;
+ nsecs_t const newPeriod2 = 7000;
+
+ mReactor.setPeriod(newPeriod1);
+
+ Sequence seq;
+ EXPECT_CALL(*mMockTracker, needsMoreSamples())
+ .Times(4)
+ .InSequence(seq)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*mMockTracker, needsMoreSamples())
+ .Times(1)
+ .InSequence(seq)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(7);
+
+ EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+ // confirmed period, but predictor wants numRequest samples. This one and prior are valid.
+ EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed));
+
+ mReactor.setPeriod(newPeriod2);
+ EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed));
+}
+
static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) {
return period - phase;
}
@@ -648,7 +727,7 @@
TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) {
bool periodFlushed = true;
- EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(3);
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2);
mReactor.setIgnorePresentFences(true);
nsecs_t const newPeriod = 5000;
@@ -672,7 +751,7 @@
kPendingLimit, true /* supportKernelIdleTimer */);
bool periodFlushed = true;
- EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(5);
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(4);
idleReactor.setIgnorePresentFences(true);
// First, set the same period, which should only be confirmed when we receive two
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index c2c5072..7df3239 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -111,6 +111,7 @@
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
MOCK_METHOD3(setLayerZOrder, Error(Display, Layer, uint32_t));
MOCK_METHOD4(setLayerInfo, Error(Display, Layer, uint32_t, uint32_t));
+ MOCK_METHOD3(setLayerType, Error(Display, Layer, uint32_t));
MOCK_METHOD3(getRenderIntents, Error(Display, ColorMode, std::vector<RenderIntent>*));
MOCK_METHOD3(setLayerColorTransform, Error(Display, Layer, const float*));
MOCK_METHOD4(getDisplayedContentSamplingAttributes,
@@ -141,6 +142,7 @@
MOCK_METHOD1(getLayerGenericMetadataKeys,
V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
MOCK_METHOD2(getClientTargetProperty, Error(Display, IComposerClient::ClientTargetProperty*));
+ MOCK_METHOD2(setDisplayElapseTime, Error(Display, uint64_t));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
index fe99e77..f01997b 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
@@ -96,6 +96,7 @@
MOCK_METHOD1(getClientTargetProperty, hal::Error(hal::ClientTargetProperty*));
MOCK_CONST_METHOD1(getConnectionType, hal::Error(android::DisplayConnectionType*));
MOCK_CONST_METHOD0(isVsyncPeriodSwitchSupported, bool());
+ MOCK_METHOD1(setDisplayElapseTime, hal::Error(uint64_t));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index e22d0cf..d19b943 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -32,6 +32,7 @@
MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
MOCK_METHOD0(notifyDisplayUpdateImminent, void());
+ MOCK_METHOD0(canNotifyDisplayUpdateImminent, bool());
};
} // namespace mock
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index f69de1f..aa8040b 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -89,7 +89,6 @@
"libhardware",
"libsync",
"libbase",
- "libdl_android",
"libhidlbase",
"liblog",
"libui",
@@ -100,6 +99,7 @@
"libnativebridge_lazy",
"libnativeloader_lazy",
"libnativewindow",
+ "libvndksupport",
"android.hardware.graphics.common@1.0",
"libSurfaceFlingerProp",
],
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7bcb2c1..f840561 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,20 +28,17 @@
#include <android/dlext.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
-#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
#include <sys/prctl.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <vndksupport/linker.h>
#include <algorithm>
#include <array>
#include <climits>
#include <new>
-#include <string_view>
-#include <sstream>
#include <vector>
#include "stubhal.h"
@@ -151,19 +148,11 @@
Hal Hal::hal_;
-void* LoadLibrary(const android_dlextinfo& dlextinfo,
- const std::string_view subname) {
- ATRACE_CALL();
-
- std::stringstream ss;
- ss << "vulkan." << subname << ".so";
- return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
-}
-
const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
"ro.hardware." HWVULKAN_HARDWARE_MODULE_ID,
- "ro.board.platform",
+ "ro.board.platform"
}};
+constexpr int LIB_DL_FLAGS = RTLD_LOCAL | RTLD_NOW;
// LoadDriver returns:
// * 0 when succeed, or
@@ -174,23 +163,30 @@
const hwvulkan_module_t** module) {
ATRACE_CALL();
- const android_dlextinfo dlextinfo = {
- .flags = ANDROID_DLEXT_USE_NAMESPACE,
- .library_namespace = library_namespace,
- };
void* so = nullptr;
- char prop[PROPERTY_VALUE_MAX];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- int prop_len = property_get(key, prop, nullptr);
- if (prop_len > 0 && prop_len <= UINT_MAX) {
- std::string_view lib_name(prop, static_cast<unsigned int>(prop_len));
- so = LoadLibrary(dlextinfo, lib_name);
- if (so)
- break;
+ std::string lib_name = android::base::GetProperty(key, "");
+ if (lib_name.empty())
+ continue;
+
+ lib_name = "vulkan." + lib_name + ".so";
+ if (library_namespace) {
+ // load updated driver
+ const android_dlextinfo dlextinfo = {
+ .flags = ANDROID_DLEXT_USE_NAMESPACE,
+ .library_namespace = library_namespace,
+ };
+ so = android_dlopen_ext(lib_name.c_str(), LIB_DL_FLAGS, &dlextinfo);
+ } else {
+ // load built-in driver
+ so = android_load_sphal_library(lib_name.c_str(), LIB_DL_FLAGS);
}
+ if (so)
+ break;
}
- if (!so)
+ if (!so) {
return -ENOENT;
+ }
auto hmi = static_cast<hw_module_t*>(dlsym(so, HAL_MODULE_INFO_SYM_AS_STR));
if (!hmi) {
@@ -211,12 +207,9 @@
int LoadBuiltinDriver(const hwvulkan_module_t** module) {
ATRACE_CALL();
- auto ns = android_get_exported_namespace("sphal");
- if (!ns)
- return -ENOENT;
android::GraphicsEnv::getInstance().setDriverToLoad(
android::GpuStatsInfo::Driver::VULKAN);
- return LoadDriver(ns, module);
+ return LoadDriver(nullptr, module);
}
int LoadUpdatedDriver(const hwvulkan_module_t** module) {
@@ -238,7 +231,6 @@
bool Hal::Open() {
ATRACE_CALL();
-
const nsecs_t openTime = systemTime();
ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");
@@ -256,16 +248,16 @@
if (result != 0) {
android::GraphicsEnv::getInstance().setDriverLoaded(
android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime);
- ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result);
return true;
}
-
hwvulkan_device_t* device;
ATRACE_BEGIN("hwvulkan module open");
result =
module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
reinterpret_cast<hw_device_t**>(&device));
+
+
ATRACE_END();
if (result != 0) {
android::GraphicsEnv::getInstance().setDriverLoaded(