Merge "SurfaceFlinger: add more cleanup to unittests"
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index f9c8c8a..bdbc0d3 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -31,6 +31,7 @@
using ::android::sp;
using ::android::status_t;
using ::android::String16;
+using ::android::String8;
using ::android::wp;
namespace ABBinderTag {
@@ -67,8 +68,6 @@
AIBinder::~AIBinder() {}
bool AIBinder::associateClass(const AIBinder_Class* clazz) {
- using ::android::String8;
-
if (clazz == nullptr) return false;
if (mClazz == clazz) return true;
@@ -119,6 +118,33 @@
return getClass()->getInterfaceDescriptor();
}
+status_t ABBinder::dump(int fd, const ::android::Vector<String16>& args) {
+ AIBinder_onDump onDump = getClass()->onDump;
+
+ if (onDump == nullptr) {
+ return STATUS_OK;
+ }
+
+ // technically UINT32_MAX would be okay here, but INT32_MAX is expected since this may be
+ // null in Java
+ if (args.size() > INT32_MAX) {
+ LOG(ERROR) << "ABBinder::dump received too many arguments: " << args.size();
+ return STATUS_BAD_VALUE;
+ }
+
+ std::vector<String8> utf8Args; // owns memory of utf8s
+ utf8Args.reserve(args.size());
+ std::vector<const char*> utf8Pointers; // what can be passed over NDK API
+ utf8Pointers.reserve(args.size());
+
+ for (size_t i = 0; i < args.size(); i++) {
+ utf8Args.push_back(String8(args[i]));
+ utf8Pointers.push_back(utf8Args[i].c_str());
+ }
+
+ return onDump(this, fd, utf8Pointers.data(), utf8Pointers.size());
+}
+
status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
binder_flags_t flags) {
if (isUserCommand(code)) {
@@ -232,6 +258,13 @@
return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact);
}
+void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) {
+ CHECK(clazz != nullptr) << "setOnDump requires non-null clazz";
+
+ // this is required to be called before instances are instantiated
+ clazz->onDump = onDump;
+}
+
void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
CHECK(who == mWho);
@@ -325,6 +358,30 @@
return PruneStatusT(binder->getBinder()->pingBinder());
}
+binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint32_t numArgs) {
+ if (binder == nullptr) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+
+ ABBinder* bBinder = binder->asABBinder();
+ if (bBinder != nullptr) {
+ AIBinder_onDump onDump = binder->getClass()->onDump;
+ if (onDump == nullptr) {
+ return STATUS_OK;
+ }
+ return PruneStatusT(onDump(bBinder, fd, args, numArgs));
+ }
+
+ ::android::Vector<String16> utf16Args;
+ utf16Args.setCapacity(numArgs);
+ for (uint32_t i = 0; i < numArgs; i++) {
+ utf16Args.push(String16(String8(args[i])));
+ }
+
+ status_t status = binder->getBinder()->dump(fd, utf16Args);
+ return PruneStatusT(status);
+}
+
binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) {
if (binder == nullptr || recipient == nullptr) {
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 7852298..0dd795a 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -25,6 +25,7 @@
#include <binder/Binder.h>
#include <binder/IBinder.h>
+#include <utils/Vector.h>
inline bool isUserCommand(transaction_code_t code) {
return code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION;
@@ -66,6 +67,7 @@
ABBinder* asABBinder() override { return this; }
const ::android::String16& getInterfaceDescriptor() const override;
+ ::android::status_t dump(int fd, const ::android::Vector<::android::String16>& args) override;
::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
::android::Parcel* reply, binder_flags_t flags) override;
@@ -106,10 +108,14 @@
const ::android::String16& getInterfaceDescriptor() const { return mInterfaceDescriptor; }
+ // required to be non-null, implemented for every class
const AIBinder_Class_onCreate onCreate;
const AIBinder_Class_onDestroy onDestroy;
const AIBinder_Class_onTransact onTransact;
+ // optional methods for a class
+ AIBinder_onDump onDump;
+
private:
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
// one.
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 9c6c55e..bddc10d 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -179,6 +179,31 @@
__INTRODUCED_IN(29);
/**
+ * Dump information about an AIBinder (usually for debugging).
+ *
+ * When no arguments are provided, a brief overview of the interview should be given.
+ *
+ * \param binder interface being dumped
+ * \param fd file descriptor to be dumped to, should be flushed, ownership is not passed.
+ * \param args array of null-terminated strings for dump (may be null if numArgs is 0)
+ * \param numArgs number of args to be sent
+ *
+ * \return binder_status_t result of transaction (if remote, for instance)
+ */
+typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char** args,
+ uint32_t numArgs);
+
+/**
+ * This sets the implementation of the dump method for a class.
+ *
+ * If this isn't set, nothing will be dumped when dump is called (for instance with
+ * android.os.Binder#dump). Must be called before any instance of the class is created.
+ *
+ * \param dump function to call when an instance of this binder class is being dumped.
+ */
+void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
+
+/**
* Creates a new binder object of the appropriate class.
*
* Ownership of args is passed to this object. The lifecycle is implemented with AIBinder_incStrong
@@ -237,6 +262,21 @@
binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29);
/**
+ * Built-in transaction for all binder objects. This dumps information about a given binder.
+ *
+ * See also AIBinder_Class_setOnDump, AIBinder_onDump
+ *
+ * \param binder the binder to dump information about
+ * \param fd where information should be dumped to
+ * \param args null-terminated arguments to pass (may be null if numArgs is 0)
+ * \param numArgs number of args to send
+ *
+ * \return STATUS_OK if dump succeeds (or if there is nothing to dump)
+ */
+binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint32_t numArgs)
+ __INTRODUCED_IN(29);
+
+/**
* Registers for notifications that the associated binder is dead. The same death recipient may be
* associated with multiple different binders. If the binder is local, then no death recipient will
* be given (since if the local process dies, then no recipient will exist to recieve a
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index a42c60b..b82141c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -104,6 +104,30 @@
* this will be checked using AIBinder_isRemote.
*/
virtual bool isRemote() = 0;
+
+ /**
+ * Dumps information about the interface.
+ */
+ virtual binder_status_t dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/) {
+ return STATUS_OK;
+ }
+
+ /**
+ * Helper method to create a class
+ */
+ static AIBinder_Class* defineClass(const char* interfaceDescriptor,
+ AIBinder_Class_onCreate onCreate,
+ AIBinder_Class_onDestroy onDestroy,
+ AIBinder_Class_onTransact onTransact,
+ AIBinder_onDump onDump = nullptr) {
+ AIBinder_Class* clazz =
+ AIBinder_Class_define(interfaceDescriptor, onCreate, onDestroy, onTransact);
+ if (clazz == nullptr) {
+ return nullptr;
+ }
+ AIBinder_Class_setOnDump(clazz, onDump);
+ return clazz;
+ }
};
/**
@@ -144,6 +168,10 @@
bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override {
+ return AIBinder_dump(asBinder().get(), fd, args, numArgs);
+ }
+
private:
SpAIBinder mBinder;
};
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 655f4d5..7e65817 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -2,10 +2,12 @@
global:
AIBinder_associateClass;
AIBinder_Class_define;
+ AIBinder_Class_setOnDump;
AIBinder_DeathRecipient_delete;
AIBinder_DeathRecipient_new;
AIBinder_debugGetRefCount;
AIBinder_decStrong;
+ AIBinder_dump;
AIBinder_fromJavaBinder;
AIBinder_getCallingPid;
AIBinder_getCallingUid;
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 4cddf94..5fd4a95 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -45,14 +45,14 @@
namespace android {
namespace bpf {
-typedef struct {
+struct time_key_t {
uint32_t uid;
uint32_t freq;
-} time_key_t;
+};
-typedef struct {
+struct val_t {
uint64_t ar[100];
-} val_t;
+};
static std::mutex gInitializedMutex;
static bool gInitialized = false;
@@ -65,19 +65,13 @@
static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
std::string data;
- if (!android::base::ReadFileToString(path, &data)) {
- ALOGD("Failed to read file %s", path.c_str());
- return false;
- }
+ if (!android::base::ReadFileToString(path, &data)) return false;
auto strings = android::base::Split(data, " \n");
for (const auto &s : strings) {
if (s.empty()) continue;
uint32_t n;
- if (!android::base::ParseUint(s, &n)) {
- ALOGD("Failed to parse file %s", path.c_str());
- return false;
- }
+ if (!android::base::ParseUint(s, &n)) return false;
out->emplace_back(n);
}
return true;
@@ -141,16 +135,8 @@
std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
eventType.c_str(), eventName.c_str());
int prog_fd = bpf_obj_get(path.c_str());
- if (prog_fd < 0) {
- ALOGD("bpf_obj_get() failed for program %s", path.c_str());
- return false;
- }
- if (bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) < 0) {
- ALOGD("Failed to attach bpf program to tracepoint %s/%s", eventType.c_str(),
- eventName.c_str());
- return false;
- }
- return true;
+ if (prog_fd < 0) return false;
+ return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
}
// Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
@@ -224,20 +210,16 @@
auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
const BpfMap<time_key_t, val_t> &) {
if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
- std::vector<std::vector<uint64_t>> v;
+ (*freqTimeMap)[key.uid].resize(gNPolicies);
for (uint32_t i = 0; i < gNPolicies; ++i) {
- std::vector<uint64_t> v2(gPolicyFreqs[i].size(), 0);
- v.emplace_back(v2);
+ (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
}
- (*freqTimeMap)[key.uid] = v;
}
for (size_t policy = 0; policy < gNPolicies; ++policy) {
for (const auto &cpu : gPolicyCpus[policy]) {
- uint32_t cpuTime = val.ar[cpu];
- if (cpuTime == 0) continue;
auto freqIdx = policyFreqIdxs[policy][key.freq];
- (*freqTimeMap)[key.uid][policy][freqIdx] += cpuTime;
+ (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu];
}
}
return android::netdutils::status::ok;
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 0205452..9f6103e 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#pragma once
+
#include <unordered_map>
#include <vector>
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 3c67542..515209e 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -90,6 +90,7 @@
MotionEvent* event = new MotionEvent();
PointerCoords coords;
+ coords.clear();
constexpr size_t pointerCount = 1;
PointerProperties properties[pointerCount];
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 3ac1c58..2899bcf 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -75,7 +75,7 @@
* scRGB:
*
* The red, green, and blue components are stored in extended sRGB space,
- * but are linear, not gamma-encoded.
+ * and gamma-encoded using the SRGB transfer function.
* The RGB primaries and the white point are the same as BT.709.
*
* The values are floating point.
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index 20699c9..1651057 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -29,20 +29,20 @@
static NotifyMotionArgs generateBasicMotionArgs() {
// Create a basic motion event for testing
- constexpr size_t pointerCount = 1;
- PointerProperties properties[pointerCount];
- properties[0].id = 0;
- properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ PointerProperties properties;
+ properties.id = 0;
+ properties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
- PointerCoords coords[pointerCount];
- coords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 1);
- coords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
+ PointerCoords coords;
+ coords.clear();
+ coords.setAxisValue(AMOTION_EVENT_AXIS_X, 1);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
static constexpr nsecs_t downTime = 2;
NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/,
AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN,
0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/,
- 0/*pointerCount*/, properties, coords, 0/*xPrecision*/, 0/*yPrecision*/,
+ 1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/,
downTime, {}/*videoFrames*/);
return motionArgs;
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 7cd9e49..da34083 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -392,7 +392,7 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
- if (mFlinger->mUse90Hz && mFlinger->mUseSmart90ForVideo) {
+ if (mFlinger->mUseSmart90ForVideo) {
// Report the requested present time to the Scheduler, if the feature is turned on.
mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp,
item.mIsAutoTimestamp, mName.c_str());
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 665179e..1eccf9a 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -43,6 +43,7 @@
namespace android {
DispSync::~DispSync() = default;
+DispSync::Callback::~Callback() = default;
namespace impl {
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 4a90f10..f629697 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DISPSYNC_H
-#define ANDROID_DISPSYNC_H
+#pragma once
#include <stddef.h>
@@ -35,10 +34,16 @@
public:
class Callback {
public:
- virtual ~Callback() = default;
+ Callback() = default;
+ virtual ~Callback();
virtual void onDispSyncEvent(nsecs_t when) = 0;
+
+ protected:
+ Callback(Callback const&) = delete;
+ Callback& operator=(Callback const&) = delete;
};
+ DispSync() = default;
virtual ~DispSync();
virtual void reset() = 0;
@@ -57,6 +62,10 @@
virtual nsecs_t expectedPresentTime() = 0;
virtual void dump(std::string& result) const = 0;
+
+protected:
+ DispSync(DispSync const&) = delete;
+ DispSync& operator=(DispSync const&) = delete;
};
namespace impl {
@@ -239,5 +248,3 @@
} // namespace impl
} // namespace android
-
-#endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5b4af4a..f3a7f87 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -67,9 +67,14 @@
mPrimaryDispSync = std::move(primaryDispSync);
mEventControlThread = std::make_unique<impl::EventControlThread>(function);
+ mSetIdleTimerMs = set_idle_timer_ms(0);
+
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.set_idle_timer_ms", value, "0");
- mSetIdleTimerMs = atoi(value);
+ int int_value = atoi(value);
+ if (int_value) {
+ mSetIdleTimerMs = atoi(value);
+ }
if (mSetIdleTimerMs > 0) {
mIdleTimer =
@@ -308,14 +313,10 @@
mLayerHistory.incrementCounter();
}
-void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) {
+void Scheduler::setChangeRefreshRateCallback(
+ const ChangeRefreshRateCallback& changeRefreshRateCallback) {
std::lock_guard<std::mutex> lock(mCallbackLock);
- mExpiredTimerCallback = expiredTimerCallback;
-}
-
-void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mResetTimerCallback = resetTimerCallback;
+ mChangeRefreshRateCallback = changeRefreshRateCallback;
}
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
@@ -414,16 +415,18 @@
void Scheduler::resetTimerCallback() {
std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mResetTimerCallback) {
- mResetTimerCallback();
+ if (mChangeRefreshRateCallback) {
+ // We do not notify the applications about config changes when idle timer is reset.
+ mChangeRefreshRateCallback(RefreshRateType::PERFORMANCE, ConfigEvent::None);
ATRACE_INT("ExpiredIdleTimer", 0);
}
}
void Scheduler::expiredTimerCallback() {
std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mExpiredTimerCallback) {
- mExpiredTimerCallback();
+ if (mChangeRefreshRateCallback) {
+ // We do not notify the applications about config changes when idle timer expires.
+ mChangeRefreshRateCallback(RefreshRateType::DEFAULT, ConfigEvent::None);
ATRACE_INT("ExpiredIdleTimer", 1);
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 7f113e7..5b9759b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -28,6 +28,7 @@
#include "IdleTimer.h"
#include "InjectVSyncSource.h"
#include "LayerHistory.h"
+#include "RefreshRateConfigs.h"
#include "SchedulerUtils.h"
namespace android {
@@ -36,9 +37,19 @@
class Scheduler {
public:
- using ExpiredIdleTimerCallback = std::function<void()>;
+ // Enum to keep track of whether we trigger event to notify choreographer of config changes.
+ enum class ConfigEvent { None, Changed };
+
+ // logical or operator with the semantics of at least one of the events is Changed
+ friend ConfigEvent operator|(const ConfigEvent& first, const ConfigEvent& second) {
+ if (first == ConfigEvent::Changed) return ConfigEvent::Changed;
+ if (second == ConfigEvent::Changed) return ConfigEvent::Changed;
+ return ConfigEvent::None;
+ }
+
+ using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+ using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>;
using GetVsyncPeriod = std::function<nsecs_t()>;
- using ResetIdleTimerCallback = std::function<void()>;
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -135,10 +146,11 @@
const std::string layerName);
// Increments counter in the layer history to indicate that SF has started a new frame.
void incrementFrameCounter();
- // Callback that gets invoked once the idle timer expires.
- void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
- // Callback that gets invoked once the idle timer is reset.
- void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
+ // Callback that gets invoked when Scheduler wants to change the refresh rate.
+ void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);
+
+ // Returns whether idle timer is enabled or not
+ bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
// Returns relevant information about Scheduler for dumpsys purposes.
std::string doDump();
@@ -216,8 +228,7 @@
std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
std::mutex mCallbackLock;
- ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
- ExpiredIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
+ ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b90bd53..9b0e8c1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -370,9 +370,6 @@
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
- property_get("debug.sf.use_90Hz", value, "0");
- mUse90Hz = atoi(value);
-
property_get("debug.sf.use_smart_90_for_video", value, "0");
mUseSmart90ForVideo = atoi(value);
@@ -563,19 +560,21 @@
readPersistentProperties();
mBootStage = BootStage::FINISHED;
- // TODO(b/122905403): Once the display policy is completely integrated, this flag should go
- // away and it should be controlled by flipping the switch in setting. The switch in
- // settings should only be available to P19 devices, if they are opted into 90Hz fishfood.
- // The boot must be complete before we can set the active config.
+ // set the refresh rate according to the policy
+ const auto displayId = getInternalDisplayIdLocked();
+ LOG_ALWAYS_FATAL_IF(!displayId);
- if (mUse90Hz) {
+ const auto performanceRefreshRate =
+ mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
+
+ if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
mPhaseOffsets->setRefreshRateType(
scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
- setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
} else {
mPhaseOffsets->setRefreshRateType(
scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
- setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
+ setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
}
}));
}
@@ -699,15 +698,12 @@
ALOGE("Run StartPropertySetThread failed!");
}
- if (mUse90Hz) {
- mScheduler->setExpiredIdleTimerCallback([this] {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
- });
- mScheduler->setResetIdleTimerCallback([this] {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
- });
+ if (mScheduler->isIdleTimerEnabled()) {
+ mScheduler->setChangeRefreshRateCallback(
+ [this](RefreshRateType type, Scheduler::ConfigEvent event) {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(type, event);
+ });
}
mRefreshRateConfigs[*display->getId()] = std::make_shared<scheduler::RefreshRateConfigs>(
getHwComposer().getConfigs(*display->getId()));
@@ -917,7 +913,7 @@
}
void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
- ConfigEvent event) {
+ Scheduler::ConfigEvent event) {
ATRACE_CALL();
// Lock is acquired by setRefreshRateTo.
@@ -941,7 +937,7 @@
// config twice. However event generation config might have changed so we need to update it
// accordingly
std::lock_guard<std::mutex> lock(mActiveConfigLock);
- const ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
+ const Scheduler::ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, desiredConfig};
if (!mDesiredActiveConfigChanged) {
@@ -975,7 +971,7 @@
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
- if (mUpcomingActiveConfig.event != ConfigEvent::None) {
+ if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
mUpcomingActiveConfig.configId);
}
@@ -1416,9 +1412,8 @@
return mAllowedConfigs[displayId]->isConfigAllowed(config);
}
-void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, ConfigEvent event) {
+void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) {
ATRACE_CALL();
-
mPhaseOffsets->setRefreshRateType(refreshRate);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
@@ -1592,7 +1587,7 @@
break;
}
- if (mUse90Hz && mUseSmart90ForVideo) {
+ if (mUseSmart90ForVideo) {
// This call is made each time SF wakes up and creates a new frame. It is part
// of video detection feature.
mScheduler->incrementFrameCounter();
@@ -4395,7 +4390,7 @@
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriod());
- StringAppendF(&result, "Scheduler enabled. 90Hz feature: %s\n", mUse90Hz ? "on" : "off");
+ StringAppendF(&result, "Scheduler enabled.");
StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n",
mUseSmart90ForVideo ? "on" : "off");
mScheduler->dump(mAppConnectionHandle, result);
@@ -5656,11 +5651,24 @@
// we may want to enhance this logic to pick a similar config
// to the current one
ALOGV("Old config is not allowed - switching to config %d", config.configId);
- setDesiredActiveConfig(displayToken, config.configId, ConfigEvent::Changed);
+ setDesiredActiveConfig(displayToken, config.configId,
+ Scheduler::ConfigEvent::Changed);
break;
}
}
}
+
+ // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT,
+ // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed.
+ if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) {
+ const auto performanceRefreshRate =
+ mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
+ if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
+ }
+ }
}
status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 75947ef..8de1e97 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -522,20 +522,11 @@
void signalLayerUpdate();
void signalRefresh();
- enum class ConfigEvent { None, Changed };
-
- // logical or operator with the semantics of at least one of the events is Changed
- friend ConfigEvent operator|(const ConfigEvent& first, const ConfigEvent& second) {
- if (first == ConfigEvent::Changed) return ConfigEvent::Changed;
- if (second == ConfigEvent::Changed) return ConfigEvent::Changed;
- return ConfigEvent::None;
- }
-
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
- void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode, ConfigEvent event)
- REQUIRES(mStateLock);
+ void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
+ Scheduler::ConfigEvent event) REQUIRES(mStateLock);
// Once HWC has returned the present fence, this sets the active config and a new refresh
// rate in SF. It also triggers HWC vsync.
void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -816,8 +807,8 @@
// Sets the refresh rate by switching active configs, if they are available for
// the desired refresh rate.
- void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType, ConfigEvent event)
- REQUIRES(mStateLock);
+ void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType,
+ Scheduler::ConfigEvent event) REQUIRES(mStateLock);
bool isConfigAllowed(const DisplayId& displayId, int32_t config);
@@ -1109,7 +1100,6 @@
/* ------------------------------------------------------------------------
* Scheduler
*/
- bool mUse90Hz = false;
bool mUseSmart90ForVideo = false;
std::unique_ptr<Scheduler> mScheduler;
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
@@ -1126,7 +1116,7 @@
struct ActiveConfigInfo {
int configId;
sp<IBinder> displayToken;
- ConfigEvent event;
+ Scheduler::ConfigEvent event;
bool operator!=(const ActiveConfigInfo& other) const {
if (configId != other.configId) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index cb9a6c0..875fca8 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -209,6 +209,14 @@
return static_cast<int32_t>(defaultValue);
}
+int32_t set_idle_timer_ms(int32_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::set_idle_timer_ms();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
#define DISPLAY_PRIMARY_SIZE 3
constexpr float kSrgbRedX = 0.4123f;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 9917683..0199d79 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -55,6 +55,8 @@
int32_t wcg_composition_pixel_format(
android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
+int32_t set_idle_timer_ms(int32_t defaultValue);
+
android::ui::DisplayPrimaries getDisplayNativePrimaries();
} // namespace sysprop
} // namespace android
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 429636b..949c23c 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -286,3 +286,14 @@
access: Readonly
prop_name: "ro.surface_flinger.display_primary_white"
}
+
+# setIdleTimerMs indicates what is considered a timeout in milliseconds for Scheduler. This value is
+# used by the Scheduler to trigger inactivity callbacks that will switch the display to a lower
+# refresh rate. Setting this property to 0 means there is no timer.
+prop {
+ api_name: "set_idle_timer_ms"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.set_idle_timer_ms"
+}
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 91999ae..be862c9 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*"
+ "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*"
}
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 34cdff7..319e01c 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -198,12 +198,15 @@
class ScreenCapture : public RefBase {
public:
static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
+ captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
+ }
+
+ static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
const auto sf = ComposerService::getComposerService();
- const auto token = sf->getInternalDisplayToken();
SurfaceComposerClient::Transaction().apply(true);
sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(token, &outBuffer, Rect(), 0, 0, false));
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
*sc = std::make_unique<ScreenCapture>(outBuffer);
}
@@ -482,6 +485,12 @@
return screenshot;
}
+ void asTransaction(const std::function<void(Transaction&)>& exec) {
+ Transaction t;
+ exec(t);
+ t.apply(true);
+ }
+
static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
static BufferGenerator bufferGenerator;
return bufferGenerator.get(outBuffer, outFence);
@@ -4086,11 +4095,6 @@
fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
}
- void asTransaction(const std::function<void(Transaction&)>& exec) {
- Transaction t;
- exec(t);
- t.apply(true);
- }
sp<SurfaceControl> mBGSurfaceControl;
sp<SurfaceControl> mFGSurfaceControl;
@@ -5421,4 +5425,102 @@
}
}
+class MultiDisplayLayerBoundsTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ SurfaceComposerClient::getDisplayInfo(mMainDisplay, &mMainDisplayInfo);
+
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&mProducer, &consumer);
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(mMainDisplayInfo.w, mMainDisplayInfo.h);
+ }
+
+ virtual void TearDown() {
+ SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+ LayerTransactionTest::TearDown();
+ mColorLayer = 0;
+ }
+
+ void createDisplay(const Rect& layerStackRect, uint32_t layerStack) {
+ mVirtualDisplay =
+ SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
+ asTransaction([&](Transaction& t) {
+ t.setDisplaySurface(mVirtualDisplay, mProducer);
+ t.setDisplayLayerStack(mVirtualDisplay, layerStack);
+ t.setDisplayProjection(mVirtualDisplay, mMainDisplayInfo.orientation, layerStackRect,
+ Rect(mMainDisplayInfo.w, mMainDisplayInfo.h));
+ });
+ }
+
+ void createColorLayer(uint32_t layerStack) {
+ mColorLayer =
+ createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ ASSERT_TRUE(mColorLayer != nullptr);
+ ASSERT_TRUE(mColorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setLayerStack(mColorLayer, layerStack);
+ t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
+ t.setLayer(mColorLayer, INT32_MAX - 2);
+ t.setColor(mColorLayer,
+ half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
+ mExpectedColor.b / 255.0f});
+ t.show(mColorLayer);
+ });
+ }
+
+ DisplayInfo mMainDisplayInfo;
+ sp<IBinder> mMainDisplay;
+ sp<IBinder> mVirtualDisplay;
+ sp<IGraphicBufferProducer> mProducer;
+ sp<SurfaceControl> mColorLayer;
+ Color mExpectedColor = {63, 63, 195, 255};
+};
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
+ createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 1 /* layerStack */);
+ createColorLayer(1 /* layerStack */);
+
+ asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+ // Verify color layer does not render on main display.
+ std::unique_ptr<ScreenCapture> sc;
+ ScreenCapture::captureScreen(&sc, mMainDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), {0, 0, 0, 255});
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+ // Verify color layer renders correctly on virtual display.
+ ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 0});
+}
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) {
+ // Create a display and set its layer stack to the main display's layer stack so
+ // the contents of the main display are mirrored on to the virtual display.
+
+ // Assumption here is that the new mirrored display has the same viewport as the
+ // primary display that it is mirroring.
+ createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 0 /* layerStack */);
+ createColorLayer(0 /* layerStack */);
+
+ asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+ // Verify color layer renders correctly on main display and it is mirrored on the
+ // virtual display.
+ std::unique_ptr<ScreenCapture> sc;
+ ScreenCapture::captureScreen(&sc, mMainDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+ ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+}
+
} // namespace android