Merge "Compile BufferHubServer_test for 64-bit on a 64-bit platform"
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 6cbe4ae..5c1cab6 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -40,7 +40,6 @@
<feature name="android.software.voice_recognizers" notLowRam="true" />
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
- <feature name="android.software.input_methods" />
<feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index d75de1e..44883cc 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -26,6 +26,7 @@
#ifndef ANDROID_CHOREOGRAPHER_H
#define ANDROID_CHOREOGRAPHER_H
+#include <stdint.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
@@ -43,6 +44,16 @@
*/
typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data);
+/**
+ * Prototype of the function that is called when a new frame is being rendered.
+ * It's passed the time that the frame is being rendered as nanoseconds in the
+ * CLOCK_MONOTONIC time base, as well as the data pointer provided by the
+ * application that registered a callback. All callbacks that run as part of
+ * rendering a frame will observe the same frame time, so it should be used
+ * whenever events need to be synchronized (e.g. animations).
+ */
+typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data);
+
#if __ANDROID_API__ >= 24
/**
@@ -52,23 +63,39 @@
AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24);
/**
- * Post a callback to be run on the next frame. The data pointer provided will
- * be passed to the callback function when it's called.
+ * Deprecated: Use AChoreographer_postFrameCallback64 instead.
*/
void AChoreographer_postFrameCallback(AChoreographer* choreographer,
- AChoreographer_frameCallback callback, void* data) __INTRODUCED_IN(24);
+ AChoreographer_frameCallback callback, void* data) __INTRODUCED_IN(24) __DEPRECATED_IN(29);
/**
- * Post a callback to be run on the frame following the specified delay. The
- * data pointer provided will be passed to the callback function when it's
- * called.
+ * Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead.
*/
void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
AChoreographer_frameCallback callback, void* data,
- long delayMillis) __INTRODUCED_IN(24);
+ long delayMillis) __INTRODUCED_IN(24) __DEPRECATED_IN(29);
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Power a callback to be run on the next frame. The data pointer provided will
+ * be passed to the callback function when it's called.
+ */
+void AChoreographer_postFrameCallback64(AChoreographer* chroreographer,
+ AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
+
+/**
+ * Post a callback to be run on the frame following the specified delay. The
+ * data pointer provided will be passed to the callback function when it's
+ * called.
+ */
+void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
+ AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif // ANDROID_CHOREOGRAPHER_H
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 0e79239..ef2ad99 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -40,9 +40,9 @@
struct ASurfaceControl;
/**
- * The SurfaceControl API can be used to provide a heirarchy of surfaces for
+ * The SurfaceControl API can be used to provide a hierarchy of surfaces for
* composition to the system compositor. ASurfaceControl represents a content node in
- * this heirarchy.
+ * this hierarchy.
*/
typedef struct ASurfaceControl ASurfaceControl;
@@ -112,7 +112,7 @@
* the callback.
*
* |stats| is an opaque handle that can be passed to ASurfaceTransactionStats functions to query
- * information about the transaction. The handle is only valid during the the callback.
+ * information about the transaction. The handle is only valid during the callback.
*
* THREADING
* The transaction completed callback can be invoked on any thread.
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/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 962d263..84ba644 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -100,6 +100,7 @@
output.writeFloat(bgColorAlpha);
output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
+ output.writeBool(colorSpaceAgnostic);
return NO_ERROR;
}
@@ -177,6 +178,7 @@
bgColorAlpha = input.readFloat();
bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
+ colorSpaceAgnostic = input.readBool();
return NO_ERROR;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 3affa23..af6373d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -20,6 +20,11 @@
#include <gui/Surface.h>
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <thread>
+
#include <inttypes.h>
#include <android/native_window.h>
@@ -450,6 +455,74 @@
return NO_ERROR;
}
+class FenceMonitor {
+public:
+ explicit FenceMonitor(const char* name) : mName(name), mFencesQueued(0), mFencesSignaled(0) {
+ std::thread thread(&FenceMonitor::loop, this);
+ pthread_setname_np(thread.native_handle(), mName);
+ thread.detach();
+ }
+
+ void queueFence(const sp<Fence>& fence) {
+ char message[64];
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ snprintf(message, sizeof(message), "Trace fence %u", mFencesQueued);
+ ATRACE_NAME(message);
+
+ mQueue.push_back(fence);
+ mCondition.notify_one();
+ mFencesQueued++;
+ ATRACE_INT(mName, int32_t(mQueue.size()));
+ }
+
+private:
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+ void loop() {
+ while (true) {
+ threadLoop();
+ }
+ }
+#pragma clang diagnostic pop
+
+ void threadLoop() {
+ sp<Fence> fence;
+ uint32_t fenceNum;
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mQueue.empty()) {
+ mCondition.wait(lock);
+ }
+ fence = mQueue[0];
+ fenceNum = mFencesSignaled;
+ }
+ {
+ char message[64];
+ snprintf(message, sizeof(message), "waiting for %s %u", mName, fenceNum);
+ ATRACE_NAME(message);
+
+ status_t result = fence->waitForever(message);
+ if (result != OK) {
+ ALOGE("Error waiting for fence: %d", result);
+ }
+ }
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mQueue.pop_front();
+ mFencesSignaled++;
+ ATRACE_INT(mName, int32_t(mQueue.size()));
+ }
+ }
+
+ const char* mName;
+ uint32_t mFencesQueued;
+ uint32_t mFencesSignaled;
+ std::deque<sp<Fence>> mQueue;
+ std::condition_variable mCondition;
+ std::mutex mMutex;
+};
+
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
ATRACE_CALL();
ALOGV("Surface::dequeueBuffer");
@@ -519,6 +592,11 @@
// this should never happen
ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
+ if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
+ static FenceMonitor hwcReleaseThread("HWC release");
+ hwcReleaseThread.queueFence(fence);
+ }
+
if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
freeAllBuffers();
}
@@ -761,6 +839,11 @@
mQueueBufferCondition.broadcast();
+ if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
+ static FenceMonitor gpuCompletionThread("GPU completion");
+ gpuCompletionThread.queueFence(fence);
+ }
+
return err;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 050ba87..d6708ab 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -989,6 +989,20 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorSpaceAgnostic(
+ const sp<SurfaceControl>& sc, const bool agnostic) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eColorSpaceAgnosticChanged;
+ s->colorSpaceAgnostic = agnostic;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
@@ -1476,6 +1490,19 @@
outIsWideColorDisplay);
}
+status_t SurfaceComposerClient::addRegionSamplingListener(
+ const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) {
+ return ComposerService::getComposerService()->addRegionSamplingListener(samplingArea,
+ stopLayerHandle,
+ listener);
+}
+
+status_t SurfaceComposerClient::removeRegionSamplingListener(
+ const sp<IRegionSamplingListener>& listener) {
+ return ComposerService::getComposerService()->removeRegionSamplingListener(listener);
+}
+
// ----------------------------------------------------------------------------
status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 32d7391..35e795c 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -88,6 +88,7 @@
eCachedBufferChanged = 0x2'00000000,
eBackgroundColorChanged = 0x4'00000000,
eMetadataChanged = 0x8'00000000,
+ eColorSpaceAgnosticChanged = 0x10'00000000,
};
layer_state_t()
@@ -115,7 +116,8 @@
api(-1),
colorTransform(mat4()),
bgColorAlpha(0),
- bgColorDataspace(ui::Dataspace::UNKNOWN) {
+ bgColorDataspace(ui::Dataspace::UNKNOWN),
+ colorSpaceAgnostic(false) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -192,6 +194,10 @@
// the background color layer
float bgColorAlpha;
ui::Dataspace bgColorDataspace;
+
+ // A color space agnostic layer means the color of this layer can be
+ // interpreted in any color space.
+ bool colorSpaceAgnostic;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e062339..48c978f 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -50,6 +50,7 @@
class HdrCapabilities;
class ISurfaceComposerClient;
class IGraphicBufferProducer;
+class IRegionSamplingListener;
class Region;
// ---------------------------------------------------------------------------
@@ -360,6 +361,7 @@
Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
const sp<NativeHandle>& sidebandStream);
Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
+ Transaction& setColorSpaceAgnostic(const sp<SurfaceControl>& sc, const bool agnostic);
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
@@ -448,6 +450,10 @@
static status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
uint64_t timestamp, DisplayedFrameStats* outStats);
+ static status_t addRegionSamplingListener(const Rect& samplingArea,
+ const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener);
+ static status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener);
private:
virtual void onFirstRef();
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index 5652c0c..d33ecfb 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -240,7 +240,7 @@
float const luma_gray = 0.50;
};
-TEST_F(RegionSamplingTest, CollectsLuma) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
fill_render(rgba_green);
sp<ISurfaceComposer> composer = ComposerService::getComposerService();
@@ -254,7 +254,7 @@
composer->removeRegionSamplingListener(listener);
}
-TEST_F(RegionSamplingTest, CollectsChangingLuma) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) {
fill_render(rgba_green);
sp<ISurfaceComposer> composer = ComposerService::getComposerService();
@@ -275,7 +275,7 @@
composer->removeRegionSamplingListener(listener);
}
-TEST_F(RegionSamplingTest, CollectsLumaFromTwoRegions) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) {
fill_render(rgba_green);
sp<ISurfaceComposer> composer = ComposerService::getComposerService();
sp<Listener> greenListener = new Listener();
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 3c67542..a106451 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -66,60 +66,60 @@
EXPECT_NEAR_BY_FRACTION(actual, target, COEFFICIENT_TOLERANCE);
}
-void failWithMessage(std::string message) {
+static void failWithMessage(std::string message) {
FAIL() << message; // cannot do this directly from a non-void function
}
struct Position {
- nsecs_t time;
- float x;
- float y;
+ nsecs_t time;
+ float x;
+ float y;
};
-
-MotionEvent* createSimpleMotionEvent(const Position* positions, size_t numSamples) {
+static std::unique_ptr<MotionEvent> createSimpleMotionEvent(
+ const std::vector<Position>& positions) {
/**
* Only populate the basic fields of a MotionEvent, such as time and a single axis
* Designed for use with manually-defined tests.
- * Create a new MotionEvent on the heap, caller responsible for destroying the object.
*/
- if (numSamples < 1) {
- failWithMessage(StringPrintf("Need at least 1 sample to create a MotionEvent."
- " Received numSamples=%zu", numSamples));
+ if (positions.empty()) {
+ failWithMessage("Need at least 1 sample to create a MotionEvent. Received empty vector.");
}
- MotionEvent* event = new MotionEvent();
- PointerCoords coords;
- constexpr size_t pointerCount = 1;
- PointerProperties properties[pointerCount];
+ std::unique_ptr<MotionEvent> event = std::make_unique<MotionEvent>();
+ constexpr size_t pointerCount = 1;
+ PointerCoords coords[pointerCount];
+ coords[0].clear();
+
+ PointerProperties properties[pointerCount];
properties[0].id = DEFAULT_POINTER_ID;
properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
// First sample added separately with initialize
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
+ coords[0].setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
+ coords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
event->initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
- 0 /*downTime*/, positions[0].time, pointerCount, properties, &coords);
+ 0 /*downTime*/, positions[0].time, pointerCount, properties, coords);
- for (size_t i = 1; i < numSamples; i++) {
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[i].y);
- event->addSample(positions[i].time, &coords);
+ for (size_t i = 1; i < positions.size(); i++) {
+ coords[0].setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
+ coords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, positions[i].y);
+ event->addSample(positions[i].time, coords);
}
return event;
}
-static void computeAndCheckVelocity(const Position* positions, size_t numSamples,
+static void computeAndCheckVelocity(const std::vector<Position>& positions,
int32_t axis, float targetVelocity) {
VelocityTracker vt(nullptr);
float Vx, Vy;
- MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
- vt.addMovement(event);
+ std::unique_ptr<MotionEvent> event = createSimpleMotionEvent(positions);
+ vt.addMovement(event.get());
vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy);
@@ -133,14 +133,13 @@
default:
FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
}
- delete event;
}
-static void computeAndCheckQuadraticEstimate(const Position* positions, size_t numSamples,
+static void computeAndCheckQuadraticEstimate(const std::vector<Position>& positions,
const std::array<float, 3>& coefficients) {
VelocityTracker vt("lsq2");
- MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
- vt.addMovement(event);
+ std::unique_ptr<MotionEvent> event = createSimpleMotionEvent(positions);
+ vt.addMovement(event.get());
VelocityTracker::Estimator estimator;
EXPECT_TRUE(vt.getEstimator(0, &estimator));
for (size_t i = 0; i< coefficients.size(); i++) {
@@ -157,35 +156,32 @@
// Same coordinate is reported 2 times in a row
// It is difficult to determine the correct answer here, but at least the direction
// of the reported velocity should be positive.
- Position values[] = {
+ std::vector<Position> values = {
{ 0, 273, NAN },
{ 12585000, 293, NAN },
{ 14730000, 293, NAN },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1600);
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 1600);
}
TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) {
// Same coordinate is reported 3 times in a row
- Position values[] = {
+ std::vector<Position> values = {
{ 0, 293, NAN },
{ 6132000, 293, NAN },
{ 11283000, 293, NAN },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 0);
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 0);
}
TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) {
// Fixed velocity at 5 points per 10 milliseconds
- Position values[] = {
+ std::vector<Position> values = {
{ 0, 0, NAN },
{ 10000000, 5, NAN },
{ 20000000, 10, NAN },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 500);
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 500);
}
@@ -203,7 +199,7 @@
// @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
TEST_F(VelocityTrackerTest, DISABLED_SwordfishFlingDown) {
// Recording of a fling on Swordfish that could cause a fling in the wrong direction
- Position values[] = {
+ std::vector<Position> values = {
{ 0, 271, 96 },
{ 16071042, 269.786346, 106.922775 },
{ 35648403, 267.983063, 156.660034 },
@@ -212,9 +208,8 @@
{ 85639375, 274.79245, 428.113159 },
{ 96948871, 274.79245, 428.113159 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 623.577637);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 8523.348633);
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 623.577637);
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 8523.348633);
}
// --------------- Recorded by hand on sailfish, generated by a script -----------------------------
@@ -236,7 +231,7 @@
TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) {
// Sailfish - fling up - slow - 1
- Position values[] = {
+ std::vector<Position> values = {
{ 235089067457000, 528.00, 983.00 },
{ 235089084684000, 527.00, 981.00 },
{ 235089093349000, 527.00, 977.00 },
@@ -254,17 +249,16 @@
{ 235089160784000, 559.00, 851.00 },
{ 235089162955851, 560.66, 843.82 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 872.794617); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 951.698181); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3604.819336); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3044.966064); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 872.794617); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 951.698181); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -3604.819336); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -3044.966064); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) {
// Sailfish - fling up - slow - 2
- Position values[] = {
+ std::vector<Position> values = {
{ 235110560704000, 522.00, 1107.00 },
{ 235110575764000, 522.00, 1107.00 },
{ 235110584385000, 522.00, 1107.00 },
@@ -283,15 +277,14 @@
{ 235110655089581, 525.54, 1000.19 },
{ 235110660368000, 530.00, 980.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4096.583008); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3455.094238); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -4096.583008); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -3455.094238); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) {
// Sailfish - fling up - slow - 3
- Position values[] = {
+ std::vector<Position> values = {
{ 792536237000, 580.00, 1317.00 },
{ 792541538987, 580.63, 1311.94 },
{ 792544613000, 581.00, 1309.00 },
@@ -311,17 +304,16 @@
{ 792625653873, 617.32, 1121.73 },
{ 792629200000, 619.00, 1115.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 574.33429); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 617.40564); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2361.982666); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2500.055664); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 574.33429); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 617.40564); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -2361.982666); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -2500.055664); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) {
// Sailfish - fling up - faster - 1
- Position values[] = {
+ std::vector<Position> values = {
{ 235160420675000, 610.00, 1042.00 },
{ 235160428220000, 609.00, 1026.00 },
{ 235160436544000, 609.00, 1024.00 },
@@ -341,17 +333,16 @@
{ 235160512603000, 670.00, 837.00 },
{ 235160520366000, 679.00, 814.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1274.141724); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1438.53186); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3877.35498); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3695.859619); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 1274.141724); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 1438.53186); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -3877.35498); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -3695.859619); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) {
// Sailfish - fling up - faster - 2
- Position values[] = {
+ std::vector<Position> values = {
{ 847153808000, 576.00, 1264.00 },
{ 847171174000, 576.00, 1262.00 },
{ 847179640000, 576.00, 1257.00 },
@@ -367,15 +358,14 @@
{ 847235701400, 607.56, 1103.83 },
{ 847237986000, 610.00, 1095.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4280.07959); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4241.004395); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -4280.07959); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -4241.004395); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) {
// Sailfish - fling up - faster - 3
- Position values[] = {
+ std::vector<Position> values = {
{ 235200532789000, 507.00, 1084.00 },
{ 235200549221000, 507.00, 1083.00 },
{ 235200557841000, 507.00, 1081.00 },
@@ -391,15 +381,14 @@
{ 235200608527086, 563.02, 910.94 },
{ 235200616933000, 590.00, 844.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -8715.686523); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -7639.026367); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -8715.686523); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -7639.026367); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) {
// Sailfish - fling up - fast - 1
- Position values[] = {
+ std::vector<Position> values = {
{ 920922149000, 561.00, 1412.00 },
{ 920930185000, 559.00, 1377.00 },
{ 920930262463, 558.98, 1376.66 },
@@ -414,17 +403,16 @@
{ 920980906000, 672.00, 993.00 },
{ 920989261000, 715.00, 903.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5670.329102); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5991.866699); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -13021.101562); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -15093.995117); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 5670.329102); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, 5991.866699); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -13021.101562); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -15093.995117); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) {
// Sailfish - fling up - fast - 2
- Position values[] = {
+ std::vector<Position> values = {
{ 235247153233000, 518.00, 1168.00 },
{ 235247170452000, 517.00, 1167.00 },
{ 235247178908000, 515.00, 1159.00 },
@@ -437,15 +425,14 @@
{ 235247213222491, 574.72, 778.45 },
{ 235247220736000, 620.00, 641.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20286.958984); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20494.587891); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -20286.958984); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -20494.587891); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) {
// Sailfish - fling up - fast - 3
- Position values[] = {
+ std::vector<Position> values = {
{ 235302568736000, 529.00, 1167.00 },
{ 235302576644000, 523.00, 1140.00 },
{ 235302579395063, 520.91, 1130.61 },
@@ -456,15 +443,14 @@
{ 235302610545000, 652.00, 605.00 },
{ 235302613019881, 679.26, 526.73 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -39295.941406); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -36461.421875); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -39295.941406); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, -36461.421875); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) {
// Sailfish - fling down - slow - 1
- Position values[] = {
+ std::vector<Position> values = {
{ 235655749552755, 582.00, 432.49 },
{ 235655750638000, 582.00, 433.00 },
{ 235655758865000, 582.00, 440.00 },
@@ -484,17 +470,16 @@
{ 235655834541000, 566.00, 623.00 },
{ 235655842893000, 563.00, 649.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -419.749695); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -398.303894); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3309.016357); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3969.099854); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -419.749695); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -398.303894); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 3309.016357); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 3969.099854); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) {
// Sailfish - fling down - slow - 2
- Position values[] = {
+ std::vector<Position> values = {
{ 235671152083370, 485.24, 558.28 },
{ 235671154126000, 485.00, 559.00 },
{ 235671162497000, 484.00, 566.00 },
@@ -514,17 +499,16 @@
{ 235671238098000, 472.00, 765.00 },
{ 235671246532000, 470.00, 799.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -262.80426); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -243.665344); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4215.682129); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4587.986816); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -262.80426); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -243.665344); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 4215.682129); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 4587.986816); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) {
// Sailfish - fling down - slow - 3
- Position values[] = {
+ std::vector<Position> values = {
{ 170983201000, 557.00, 533.00 },
{ 171000668000, 556.00, 534.00 },
{ 171007359750, 554.73, 535.27 },
@@ -537,17 +521,16 @@
{ 171043147000, 541.00, 571.00 },
{ 171051052000, 536.00, 586.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -723.413513); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -651.038452); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 2091.502441); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 1934.517456); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -723.413513); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -651.038452); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 2091.502441); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 1934.517456); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) {
// Sailfish - fling down - faster - 1
- Position values[] = {
+ std::vector<Position> values = {
{ 235695280333000, 558.00, 451.00 },
{ 235695283971237, 558.43, 454.45 },
{ 235695289038000, 559.00, 462.00 },
@@ -567,15 +550,14 @@
{ 235695368118682, 562.24, 722.52 },
{ 235695373403000, 564.00, 744.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4254.639648); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4698.415039); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 4254.639648); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 4698.415039); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) {
// Sailfish - fling down - faster - 2
- Position values[] = {
+ std::vector<Position> values = {
{ 235709624766000, 535.00, 579.00 },
{ 235709642256000, 534.00, 580.00 },
{ 235709643350278, 533.94, 580.06 },
@@ -592,17 +574,16 @@
{ 235709709830000, 512.00, 739.00 },
{ 235709710626776, 511.72, 741.85 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -430.440247); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -447.600311); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3953.859375); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4316.155273); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -430.440247); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -447.600311); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 3953.859375); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 4316.155273); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) {
// Sailfish - fling down - faster - 3
- Position values[] = {
+ std::vector<Position> values = {
{ 235727628927000, 540.00, 440.00 },
{ 235727636810000, 537.00, 454.00 },
{ 235727646176000, 536.00, 454.00 },
@@ -621,15 +602,14 @@
{ 235727720880776, 516.33, 655.36 },
{ 235727721580000, 516.00, 658.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4484.617676); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4927.92627); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 4484.617676); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 4927.92627); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) {
// Sailfish - fling down - fast - 1
- Position values[] = {
+ std::vector<Position> values = {
{ 235762352849000, 467.00, 286.00 },
{ 235762360250000, 443.00, 344.00 },
{ 235762362787412, 434.77, 363.89 },
@@ -640,15 +620,14 @@
{ 235762394133000, 406.00, 648.00 },
{ 235762396429369, 404.37, 680.67 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 19084.931641); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16064.685547); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 19084.931641); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 16064.685547); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) {
// Sailfish - fling down - fast - 2
- Position values[] = {
+ std::vector<Position> values = {
{ 235772487188000, 576.00, 204.00 },
{ 235772495159000, 553.00, 236.00 },
{ 235772503568000, 551.00, 240.00 },
@@ -659,15 +638,14 @@
{ 235772529174000, 498.00, 451.00 },
{ 235772537635000, 484.00, 589.00 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 18660.048828); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16918.439453); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 18660.048828); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 16918.439453); // lsq2
}
TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) {
// Sailfish - fling down - fast - 3
- Position values[] = {
+ std::vector<Position> values = {
{ 507650295000, 628.00, 233.00 },
{ 507658234000, 605.00, 269.00 },
{ 507666784000, 601.00, 274.00 },
@@ -679,11 +657,10 @@
{ 507700707000, 454.00, 792.00 },
{ 507703352649, 443.71, 857.77 },
};
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6772.508301); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6388.48877); // lsq2
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 29765.908203); // impulse
- computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -6772.508301); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_X, -6388.48877); // lsq2
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 29765.908203); // impulse
+ computeAndCheckVelocity(values, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
}
/*
@@ -710,7 +687,7 @@
* In the test, we would convert these coefficients to (0*(1E3)^0, 0*(1E3)^1, 1*(1E3)^2).
*/
TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constant) {
- Position values[] = {
+ std::vector<Position> values = {
{ 0000000, 1, 1 }, // 0 s
{ 1000000, 1, 1 }, // 0.001 s
{ 2000000, 1, 1 }, // 0.002 s
@@ -720,15 +697,14 @@
// -0.002, 1
// -0.001, 1
// -0.000, 1
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({1, 0, 0}));
+ computeAndCheckQuadraticEstimate(values, std::array<float, 3>({1, 0, 0}));
}
/*
* Straight line y = x :: the constant and quadratic coefficients are zero.
*/
TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) {
- Position values[] = {
+ std::vector<Position> values = {
{ 0000000, -2, -2 },
{ 1000000, -1, -1 },
{ 2000000, -0, -0 },
@@ -738,15 +714,14 @@
// -0.002, -2
// -0.001, -1
// -0.000, 0
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 1E3, 0}));
+ computeAndCheckQuadraticEstimate(values, std::array<float, 3>({0, 1E3, 0}));
}
/*
* Parabola
*/
TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic) {
- Position values[] = {
+ std::vector<Position> values = {
{ 0000000, 1, 1 },
{ 1000000, 4, 4 },
{ 2000000, 8, 8 },
@@ -756,15 +731,14 @@
// -0.002, 1
// -0.001, 4
// -0.000, 8
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({8, 4.5E3, 0.5E6}));
+ computeAndCheckQuadraticEstimate(values, std::array<float, 3>({8, 4.5E3, 0.5E6}));
}
/*
* Parabola
*/
TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic2) {
- Position values[] = {
+ std::vector<Position> values = {
{ 0000000, 1, 1 },
{ 1000000, 4, 4 },
{ 2000000, 9, 9 },
@@ -774,15 +748,14 @@
// -0.002, 1
// -0.001, 4
// -0.000, 9
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({9, 6E3, 1E6}));
+ computeAndCheckQuadraticEstimate(values, std::array<float, 3>({9, 6E3, 1E6}));
}
/*
* Parabola :: y = x^2 :: the constant and linear coefficients are zero.
*/
TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic3) {
- Position values[] = {
+ std::vector<Position> values = {
{ 0000000, 4, 4 },
{ 1000000, 1, 1 },
{ 2000000, 0, 0 },
@@ -792,8 +765,7 @@
// -0.002, 4
// -0.001, 1
// -0.000, 0
- size_t count = sizeof(values) / sizeof(Position);
- computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 0E3, 1E6}));
+ computeAndCheckQuadraticEstimate(values, std::array<float, 3>({0, 0E3, 1E6}));
}
} // namespace android
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/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index 4b16027..db9f26e 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -43,7 +43,7 @@
* Blocks execution while queue is empty.
*/
T pop() {
- std::unique_lock<std::mutex> lock(mLock);
+ std::unique_lock lock(mLock);
android::base::ScopedLockAssertion assumeLock(mLock);
mHasElements.wait(lock, [this]{
android::base::ScopedLockAssertion assumeLock(mLock);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index d288736..bcb1ec5 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -46,6 +46,7 @@
#include "InputDispatcher.h"
#include <errno.h>
+#include <inttypes.h>
#include <limits.h>
#include <sstream>
#include <stddef.h>
@@ -262,7 +263,7 @@
InputDispatcher::~InputDispatcher() {
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
resetKeyRepeatLocked();
releasePendingEventLocked();
@@ -277,8 +278,8 @@
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
- AutoMutex _l(mLock);
- mDispatcherIsAliveCondition.broadcast();
+ std::scoped_lock _l(mLock);
+ mDispatcherIsAlive.notify_all();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
@@ -697,7 +698,7 @@
#if DEBUG_DISPATCH_CYCLE
ALOGD("Injected inbound event was dropped.");
#endif
- setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
+ setInjectionResult(entry, INPUT_EVENT_INJECTION_FAILED);
}
if (entry == mNextUnblockedEvent) {
mNextUnblockedEvent = nullptr;
@@ -851,7 +852,7 @@
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
- setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
+ setInjectionResult(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
mReporter->reportDroppedKey(entry->sequenceNum);
return true;
@@ -865,7 +866,7 @@
return false;
}
- setInjectionResultLocked(entry, injectionResult);
+ setInjectionResult(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}
@@ -901,7 +902,7 @@
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
- setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
+ setInjectionResult(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
@@ -926,7 +927,7 @@
return false;
}
- setInjectionResultLocked(entry, injectionResult);
+ setInjectionResult(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
CancelationOptions::Mode mode(isPointerEvent ?
@@ -1972,17 +1973,17 @@
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ enqueueDispatchEntry(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ enqueueDispatchEntry(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ enqueueDispatchEntry(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ enqueueDispatchEntry(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ enqueueDispatchEntry(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ enqueueDispatchEntry(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
@@ -1991,7 +1992,7 @@
}
}
-void InputDispatcher::enqueueDispatchEntryLocked(
+void InputDispatcher::enqueueDispatchEntry(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
int32_t inputTargetFlags = inputTarget->flags;
@@ -2226,9 +2227,9 @@
#endif
// Clear the dispatch queues.
- drainDispatchQueueLocked(&connection->outboundQueue);
+ drainDispatchQueue(&connection->outboundQueue);
traceOutboundQueueLength(connection);
- drainDispatchQueueLocked(&connection->waitQueue);
+ drainDispatchQueue(&connection->waitQueue);
traceWaitQueueLength(connection);
// The connection appears to be unrecoverably broken.
@@ -2243,16 +2244,16 @@
}
}
-void InputDispatcher::drainDispatchQueueLocked(Queue<DispatchEntry>* queue) {
+void InputDispatcher::drainDispatchQueue(Queue<DispatchEntry>* queue) {
while (!queue->isEmpty()) {
DispatchEntry* dispatchEntry = queue->dequeueAtHead();
- releaseDispatchEntryLocked(dispatchEntry);
+ releaseDispatchEntry(dispatchEntry);
}
}
-void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) {
+void InputDispatcher::releaseDispatchEntry(DispatchEntry* dispatchEntry) {
if (dispatchEntry->hasForegroundTarget()) {
- decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
+ decrementPendingForegroundDispatches(dispatchEntry->eventEntry);
}
delete dispatchEntry;
}
@@ -2261,7 +2262,7 @@
InputDispatcher* d = static_cast<InputDispatcher*>(data);
{ // acquire lock
- AutoMutex _l(d->mLock);
+ std::scoped_lock _l(d->mLock);
ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
if (connectionIndex < 0) {
@@ -2399,7 +2400,7 @@
target.inputChannel = connection->inputChannel;
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
+ enqueueDispatchEntry(connection, cancelationEventEntry, // increments ref
&target, InputTarget::FLAG_DISPATCH_AS_IS);
cancelationEventEntry->release();
@@ -2509,7 +2510,7 @@
bool needWake;
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
ConfigurationChangedEntry* newEntry =
new ConfigurationChangedEntry(args->sequenceNum, args->eventTime);
@@ -2537,7 +2538,7 @@
newKeyCode = AKEYCODE_HOME;
}
if (newKeyCode != AKEYCODE_UNKNOWN) {
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
struct KeyReplacement replacement = {keyCode, deviceId};
mReplacedKeys.add(replacement, newKeyCode);
keyCode = newKeyCode;
@@ -2547,7 +2548,7 @@
// In order to maintain a consistent stream of up and down events, check to see if the key
// going up is one we've replaced in a down event and haven't yet replaced in an up event,
// even if the modifier was released between the down and the up events.
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
struct KeyReplacement replacement = {keyCode, deviceId};
ssize_t index = mReplacedKeys.indexOfKey(replacement);
if (index >= 0) {
@@ -2742,7 +2743,7 @@
bool needWake;
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
DeviceResetEntry* newEntry =
new DeviceResetEntry(args->sequenceNum, args->eventTime, args->deviceId);
@@ -2896,7 +2897,7 @@
int32_t injectionResult;
{ // acquire lock
- AutoMutex _l(mLock);
+ std::unique_lock _l(mLock);
if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
@@ -2917,7 +2918,7 @@
break;
}
- mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout);
+ mInjectionResultAvailable.wait_for(_l, std::chrono::nanoseconds(remainingTimeout));
}
if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED
@@ -2937,7 +2938,7 @@
break;
}
- mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout);
+ mInjectionSyncFinished.wait_for(_l, std::chrono::nanoseconds(remainingTimeout));
}
}
}
@@ -2959,7 +2960,7 @@
|| mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
}
-void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) {
+void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionResult) {
InjectionState* injectionState = entry->injectionState;
if (injectionState) {
#if DEBUG_INJECTION
@@ -2988,7 +2989,7 @@
}
injectionState->injectionResult = injectionResult;
- mInjectionResultAvailableCondition.broadcast();
+ mInjectionResultAvailable.notify_all();
}
}
@@ -2999,13 +3000,13 @@
}
}
-void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) {
+void InputDispatcher::decrementPendingForegroundDispatches(EventEntry* entry) {
InjectionState* injectionState = entry->injectionState;
if (injectionState) {
injectionState->pendingForegroundDispatches -= 1;
if (injectionState->pendingForegroundDispatches == 0) {
- mInjectionSyncFinishedCondition.broadcast();
+ mInjectionSyncFinished.notify_all();
}
}
}
@@ -3077,7 +3078,7 @@
ALOGD("setInputWindows displayId=%" PRId32, displayId);
#endif
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
// Copy old handles for release if they are no longer present.
const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
@@ -3234,7 +3235,7 @@
ALOGD("setFocusedApplication displayId=%" PRId32, displayId);
#endif
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
sp<InputApplicationHandle> oldFocusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
@@ -3276,7 +3277,7 @@
ALOGD("setFocusedDisplay displayId=%" PRId32, displayId);
#endif
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
if (mFocusedDisplayId != displayId) {
sp<InputWindowHandle> oldFocusedWindowHandle =
@@ -3328,7 +3329,7 @@
bool changed;
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) {
if (mDispatchFrozen && !frozen) {
@@ -3363,7 +3364,7 @@
#endif
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
if (mInputFilterEnabled == enabled) {
return;
@@ -3386,7 +3387,7 @@
}
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromToken);
sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toToken);
@@ -3730,7 +3731,7 @@
#endif
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
// If InputWindowHandle is null and displayId is not ADISPLAY_ID_NONE,
// treat inputChannel as monitor channel for displayId.
@@ -3772,7 +3773,7 @@
#endif
{ // acquire lock
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/);
if (status) {
@@ -4033,7 +4034,7 @@
connection->outboundQueue.enqueueAtHead(dispatchEntry);
traceOutboundQueueLength(connection);
} else {
- releaseDispatchEntryLocked(dispatchEntry);
+ releaseDispatchEntry(dispatchEntry);
}
}
@@ -4271,7 +4272,7 @@
}
void InputDispatcher::dump(std::string& dump) {
- AutoMutex _l(mLock);
+ std::scoped_lock _l(mLock);
dump += "Input Dispatcher State:\n";
dumpDispatchStateLocked(dump);
@@ -4284,10 +4285,9 @@
void InputDispatcher::monitor() {
// Acquire and release the lock to ensure that the dispatcher has not deadlocked.
- mLock.lock();
+ std::unique_lock _l(mLock);
mLooper->wake();
- mDispatcherIsAliveCondition.wait(mLock);
- mLock.unlock();
+ mDispatcherIsAlive.wait(_l);
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 9d8919b..24ae32f 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -17,6 +17,7 @@
#ifndef _UI_INPUT_DISPATCHER_H
#define _UI_INPUT_DISPATCHER_H
+#include <condition_variable>
#include <input/Input.h>
#include <input/InputApplication.h>
#include <input/InputTransport.h>
@@ -884,9 +885,9 @@
sp<InputDispatcherPolicyInterface> mPolicy;
InputDispatcherConfiguration mConfig;
- Mutex mLock;
+ std::mutex mLock;
- Condition mDispatcherIsAliveCondition;
+ std::condition_variable mDispatcherIsAlive;
sp<Looper> mLooper;
@@ -944,13 +945,13 @@
GUARDED_BY(mLock);
// Event injection and synchronization.
- Condition mInjectionResultAvailableCondition;
+ std::condition_variable mInjectionResultAvailable;
bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
- void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
+ void setInjectionResult(EventEntry* entry, int32_t injectionResult);
- Condition mInjectionSyncFinishedCondition;
+ std::condition_variable mInjectionSyncFinished;
void incrementPendingForegroundDispatches(EventEntry* entry);
- void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
+ void decrementPendingForegroundDispatches(EventEntry* entry);
// Key repeat tracking.
struct KeyRepeatState {
@@ -1136,7 +1137,7 @@
EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
- void enqueueDispatchEntryLocked(const sp<Connection>& connection,
+ void enqueueDispatchEntry(const sp<Connection>& connection,
EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
REQUIRES(mLock);
@@ -1144,8 +1145,8 @@
uint32_t seq, bool handled) REQUIRES(mLock);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool notify) REQUIRES(mLock);
- void drainDispatchQueueLocked(Queue<DispatchEntry>* queue);
- void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry);
+ void drainDispatchQueue(Queue<DispatchEntry>* queue);
+ void releaseDispatchEntry(DispatchEntry* dispatchEntry);
static int handleReceiveCallback(int fd, int events, void* data);
void synthesizeCancelationEventsForAllConnectionsLocked(
@@ -1197,7 +1198,7 @@
bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) REQUIRES(mLock);
bool afterMotionEventLockedInterruptible(const sp<Connection>& connection,
- DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled);
+ DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) REQUIRES(mLock);
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
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/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 756ca42..7884362 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -239,7 +239,8 @@
void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata) {
+ int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) {
RETURN_IF_NO_HWC_LAYER(displayDevice);
// Apply this display's projection's viewport to the visible region
@@ -291,10 +292,10 @@
setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
}
- ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
- error = hwcLayer->setDataspace(mCurrentDataSpace);
+ ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+ error = hwcLayer->setDataspace(dataspace);
if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
to_string(error).c_str(), static_cast<int32_t>(error));
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index e9dbdea..8149cba 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -81,7 +81,8 @@
bool isHdrY410() const override;
void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+ const Rect& viewport, int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) override;
bool onPreComposition(nsecs_t refreshStartTime) override;
bool onPostComposition(const std::optional<DisplayId>& displayId,
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 7d2dcba..cc78ece 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -496,7 +496,7 @@
BufferLayerConsumer::Image::~Image() {
if (mGraphicBuffer != nullptr) {
- ALOGE("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
+ ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId());
}
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 7cd9e49..e4179ee 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -392,10 +392,9 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
- if (mFlinger->mUse90Hz && 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());
+ if (mFlinger->mUseSmart90ForVideo) {
+ // Report mApi ID for each layer.
+ mFlinger->mScheduler->addNativeWindowApi(item.mApi);
}
Mutex::Autolock lock(mQueueItemLock);
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 2aeece7..a2692bc 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -81,7 +81,8 @@
void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
const ui::Transform& transform, const Rect& viewport,
- int32_t /* supportedPerFrameMetadata */) {
+ int32_t /* supportedPerFrameMetadata */,
+ const ui::Dataspace targetDataspace) {
RETURN_IF_NO_HWC_LAYER(display);
Region visible = transform.transform(visibleRegion.intersect(viewport));
@@ -101,9 +102,10 @@
setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
- error = hwcLayer->setDataspace(mCurrentDataSpace);
+ const ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+ error = hwcLayer->setDataspace(dataspace);
if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
to_string(error).c_str(), static_cast<int32_t>(error));
}
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 9786419..9a72b40 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -36,7 +36,8 @@
bool setColor(const half3& color) override;
void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+ const Rect& viewport, int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) override;
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 738f4b6..7927fa9 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -40,6 +40,6 @@
}
void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
- const Rect&, int32_t) {}
+ const Rect&, int32_t, const ui::Dataspace) {}
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index c7cfdcd..7222a3e 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -34,7 +34,8 @@
bool canReceiveInput() const override;
void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+ const Rect& viewport, int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) override;
bool isCreatedFromMainThread() const override { return true; }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5ab4523..5c3fb05 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -103,6 +103,7 @@
mCurrentState.cornerRadius = 0.0f;
mCurrentState.api = -1;
mCurrentState.hasColorTransform = false;
+ mCurrentState.colorSpaceAgnostic = false;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -1355,6 +1356,17 @@
return true;
}
+bool Layer::setColorSpaceAgnostic(const bool agnostic) {
+ if (mCurrentState.colorSpaceAgnostic == agnostic) {
+ return false;
+ }
+ mCurrentState.sequence++;
+ mCurrentState.colorSpaceAgnostic = agnostic;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
uint32_t Layer::getLayerStack() const {
auto p = mDrawingParent.promote();
if (p == nullptr) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 143ac94..1afb917 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -210,6 +210,7 @@
// The deque of callback handles for this frame. The back of the deque contains the most
// recent callback handle.
std::deque<sp<CallbackHandle>> callbackHandles;
+ bool colorSpaceAgnostic;
};
explicit Layer(const LayerCreationArgs& args);
@@ -297,6 +298,7 @@
virtual bool setColorTransform(const mat4& matrix);
virtual mat4 getColorTransform() const;
virtual bool hasColorTransform() const;
+ virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
// Used only to set BufferStateLayer state
virtual bool setTransform(uint32_t /*transform*/) { return false; };
@@ -315,6 +317,7 @@
return false;
};
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
+ virtual bool setColorSpaceAgnostic(const bool agnostic);
ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
@@ -450,7 +453,8 @@
bool getForceClientComposition(const sp<DisplayDevice>& display);
virtual void setPerFrameData(const sp<const DisplayDevice>& display,
const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata) = 0;
+ int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) = 0;
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 2d6d33c..04e8796 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -92,12 +92,10 @@
void LayerProtoHelper::writeToProto(const ui::Transform& transform,
TransformProto* transformProto) {
- const uint32_t type = transform.getType();
+ const uint32_t type = transform.getType() | (transform.getOrientation() << 8);
transformProto->set_type(type);
- if (type &
- (ui::Transform::SCALE | ui::Transform::ROTATE | ui::Transform::TRANSLATE |
- ui::Transform::UNKNOWN)) {
+ if (type & (ui::Transform::SCALE | ui::Transform::UNKNOWN)) {
transformProto->set_dsdx(transform[0][0]);
transformProto->set_dtdx(transform[0][1]);
transformProto->set_dsdy(transform[1][0]);
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index bd8548c..4f0b3bb 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -21,27 +21,168 @@
#include "RegionSamplingThread.h"
+#include <cutils/properties.h>
#include <gui/IRegionSamplingListener.h>
#include <utils/Trace.h>
+#include <string>
#include "DisplayDevice.h"
#include "Layer.h"
#include "SurfaceFlinger.h"
namespace android {
+using namespace std::chrono_literals;
template <typename T>
struct SpHash {
size_t operator()(const sp<T>& p) const { return std::hash<T*>()(p.get()); }
};
-RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) : mFlinger(flinger) {
- std::lock_guard threadLock(mThreadMutex);
- mThread = std::thread([this]() { threadMain(); });
- pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
+constexpr auto lumaSamplingStepTag = "LumaSamplingStep";
+enum class samplingStep {
+ noWorkNeeded,
+ idleTimerWaiting,
+ waitForZeroPhase,
+ waitForSamplePhase,
+ sample
+};
+
+constexpr auto defaultRegionSamplingOffset = -3ms;
+constexpr auto defaultRegionSamplingPeriod = 100ms;
+constexpr auto defaultRegionSamplingTimerTimeout = 100ms;
+// TODO: (b/127403193) duration to string conversion could probably be constexpr
+template <typename Rep, typename Per>
+inline std::string toNsString(std::chrono::duration<Rep, Per> t) {
+ return std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(t).count());
}
+RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() {
+ char value[PROPERTY_VALUE_MAX] = {};
+
+ property_get("debug.sf.region_sampling_offset_ns", value,
+ toNsString(defaultRegionSamplingOffset).c_str());
+ int const samplingOffsetNsRaw = atoi(value);
+
+ property_get("debug.sf.region_sampling_period_ns", value,
+ toNsString(defaultRegionSamplingPeriod).c_str());
+ int const samplingPeriodNsRaw = atoi(value);
+
+ property_get("debug.sf.region_sampling_timer_timeout_ns", value,
+ toNsString(defaultRegionSamplingTimerTimeout).c_str());
+ int const samplingTimerTimeoutNsRaw = atoi(value);
+
+ if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) {
+ ALOGW("User-specified sampling tuning options nonsensical. Using defaults");
+ mSamplingOffset = defaultRegionSamplingOffset;
+ mSamplingPeriod = defaultRegionSamplingPeriod;
+ mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout;
+ } else {
+ mSamplingOffset = std::chrono::nanoseconds(samplingOffsetNsRaw);
+ mSamplingPeriod = std::chrono::nanoseconds(samplingPeriodNsRaw);
+ mSamplingTimerTimeout = std::chrono::nanoseconds(samplingTimerTimeoutNsRaw);
+ }
+}
+
+struct SamplingOffsetCallback : DispSync::Callback {
+ SamplingOffsetCallback(RegionSamplingThread& samplingThread, Scheduler& scheduler,
+ std::chrono::nanoseconds targetSamplingOffset)
+ : mRegionSamplingThread(samplingThread),
+ mScheduler(scheduler),
+ mTargetSamplingOffset(targetSamplingOffset) {}
+
+ ~SamplingOffsetCallback() { stopVsyncListener(); }
+
+ SamplingOffsetCallback(const SamplingOffsetCallback&) = delete;
+ SamplingOffsetCallback& operator=(const SamplingOffsetCallback&) = delete;
+
+ void startVsyncListener() {
+ std::lock_guard lock(mMutex);
+ if (mVsyncListening) return;
+
+ mPhaseIntervalSetting = Phase::ZERO;
+ mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
+ sync.addEventListener("SamplingThreadDispSyncListener", 0, this);
+ });
+ mVsyncListening = true;
+ }
+
+ void stopVsyncListener() {
+ std::lock_guard lock(mMutex);
+ stopVsyncListenerLocked();
+ }
+
+private:
+ void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ {
+ if (!mVsyncListening) return;
+
+ mScheduler.withPrimaryDispSync(
+ [this](android::DispSync& sync) { sync.removeEventListener(this); });
+ mVsyncListening = false;
+ }
+
+ void onDispSyncEvent(nsecs_t /* when */) final {
+ std::unique_lock<decltype(mMutex)> lock(mMutex);
+
+ if (mPhaseIntervalSetting == Phase::ZERO) {
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase));
+ mPhaseIntervalSetting = Phase::SAMPLING;
+ mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
+ sync.changePhaseOffset(this, mTargetSamplingOffset.count());
+ });
+ return;
+ }
+
+ if (mPhaseIntervalSetting == Phase::SAMPLING) {
+ mPhaseIntervalSetting = Phase::ZERO;
+ mScheduler.withPrimaryDispSync(
+ [this](android::DispSync& sync) { sync.changePhaseOffset(this, 0); });
+ stopVsyncListenerLocked();
+ lock.unlock();
+ mRegionSamplingThread.notifySamplingOffset();
+ return;
+ }
+ }
+
+ RegionSamplingThread& mRegionSamplingThread;
+ Scheduler& mScheduler;
+ const std::chrono::nanoseconds mTargetSamplingOffset;
+ mutable std::mutex mMutex;
+ enum class Phase {
+ ZERO,
+ SAMPLING
+ } mPhaseIntervalSetting /*GUARDED_BY(mMutex) macro doesnt work with unique_lock?*/
+ = Phase::ZERO;
+ bool mVsyncListening /*GUARDED_BY(mMutex)*/ = false;
+};
+
+RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler,
+ const TimingTunables& tunables)
+ : mFlinger(flinger),
+ mScheduler(scheduler),
+ mTunables(tunables),
+ mIdleTimer(std::chrono::duration_cast<std::chrono::milliseconds>(
+ mTunables.mSamplingTimerTimeout),
+ [] {}, [this] { checkForStaleLuma(); }),
+ mPhaseCallback(std::make_unique<SamplingOffsetCallback>(*this, mScheduler,
+ tunables.mSamplingOffset)),
+ lastSampleTime(0ns) {
+ {
+ std::lock_guard threadLock(mThreadMutex);
+ mThread = std::thread([this]() { threadMain(); });
+ pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
+ }
+ mIdleTimer.start();
+}
+
+RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler)
+ : RegionSamplingThread(flinger, scheduler,
+ TimingTunables{defaultRegionSamplingOffset,
+ defaultRegionSamplingPeriod,
+ defaultRegionSamplingTimerTimeout}) {}
+
RegionSamplingThread::~RegionSamplingThread() {
+ mIdleTimer.stop();
+
{
std::lock_guard lock(mMutex);
mRunning = false;
@@ -71,8 +212,41 @@
mDescriptors.erase(wp<IBinder>(IInterface::asBinder(listener)));
}
-void RegionSamplingThread::sampleNow() {
+void RegionSamplingThread::checkForStaleLuma() {
std::lock_guard lock(mMutex);
+
+ if (mDiscardedFrames) {
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForZeroPhase));
+ mDiscardedFrames = false;
+ mPhaseCallback->startVsyncListener();
+ }
+}
+
+void RegionSamplingThread::notifyNewContent() {
+ doSample();
+}
+
+void RegionSamplingThread::notifySamplingOffset() {
+ doSample();
+}
+
+void RegionSamplingThread::doSample() {
+ std::lock_guard lock(mMutex);
+ auto now = std::chrono::nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+ if (lastSampleTime + mTunables.mSamplingPeriod > now) {
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::idleTimerWaiting));
+ mDiscardedFrames = true;
+ return;
+ }
+
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::sample));
+
+ mDiscardedFrames = false;
+ lastSampleTime = now;
+
+ mIdleTimer.reset();
+ mPhaseCallback->stopVsyncListener();
+
mSampleRequested = true;
mCondition.notify_one();
}
@@ -238,6 +412,7 @@
for (size_t d = 0; d < activeDescriptors.size(); ++d) {
activeDescriptors[d].listener->onSampleCollected(lumas[d]);
}
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded));
}
void RegionSamplingThread::threadMain() {
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index ab06513..d4e57bf 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -16,6 +16,7 @@
#pragma once
+#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>
@@ -25,17 +26,42 @@
#include <binder/IBinder.h>
#include <ui/Rect.h>
#include <utils/StrongPointer.h>
+#include "Scheduler/IdleTimer.h"
namespace android {
class GraphicBuffer;
class IRegionSamplingListener;
class Layer;
+class Scheduler;
class SurfaceFlinger;
+struct SamplingOffsetCallback;
class RegionSamplingThread : public IBinder::DeathRecipient {
public:
- explicit RegionSamplingThread(SurfaceFlinger& flinger);
+ struct TimingTunables {
+ // debug.sf.sampling_offset_ns
+ // When asynchronously collecting sample, the offset, from zero phase in the vsync timeline
+ // at which the sampling should start.
+ std::chrono::nanoseconds mSamplingOffset;
+ // debug.sf.sampling_period_ns
+ // This is the maximum amount of time the luma recieving client
+ // should have to wait for a new luma value after a frame is updated. The inverse of this is
+ // roughly the sampling rate. Sampling system rounds up sub-vsync sampling period to vsync
+ // period.
+ std::chrono::nanoseconds mSamplingPeriod;
+ // debug.sf.sampling_timer_timeout_ns
+ // This is the interval at which the luma sampling system will check that the luma clients
+ // have up to date information. It defaults to the mSamplingPeriod.
+ std::chrono::nanoseconds mSamplingTimerTimeout;
+ };
+ struct EnvironmentTimingTunables : TimingTunables {
+ EnvironmentTimingTunables();
+ };
+ explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler,
+ const TimingTunables& tunables);
+ explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler);
+
~RegionSamplingThread();
// Add a listener to receive luma notifications. The luma reported via listener will
@@ -44,8 +70,13 @@
const sp<IRegionSamplingListener>& listener);
// Remove the listener to stop receiving median luma notifications.
void removeListener(const sp<IRegionSamplingListener>& listener);
- // Instruct the thread to perform a median luma sampling on the layers.
- void sampleNow();
+
+ // Notifies sampling engine that new content is available. This will trigger a sampling
+ // pass at some point in the future.
+ void notifyNewContent();
+
+ // Notifies the sampling engine that it has a good timing window in which to sample.
+ void notifySamplingOffset();
private:
struct Descriptor {
@@ -63,12 +94,19 @@
const sp<GraphicBuffer>& buffer, const Point& leftTop,
const std::vector<RegionSamplingThread::Descriptor>& descriptors);
+ void doSample();
void binderDied(const wp<IBinder>& who) override;
+ void checkForStaleLuma();
void captureSample() REQUIRES(mMutex);
void threadMain();
SurfaceFlinger& mFlinger;
+ Scheduler& mScheduler;
+ const TimingTunables mTunables;
+ scheduler::IdleTimer mIdleTimer;
+
+ std::unique_ptr<SamplingOffsetCallback> const mPhaseCallback;
std::mutex mThreadMutex;
std::thread mThread GUARDED_BY(mThreadMutex);
@@ -79,6 +117,8 @@
bool mSampleRequested GUARDED_BY(mMutex) = false;
std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex);
+ std::chrono::nanoseconds lastSampleTime GUARDED_BY(mMutex);
+ bool mDiscardedFrames GUARDED_BY(mMutex) = false;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 665179e..5178836 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 {
@@ -75,9 +76,18 @@
void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
if (mTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
- mPeriod = period;
+
mPhase = phase;
mReferenceTime = referenceTime;
+ if (mPeriod != period && mReferenceTime != 0) {
+ // Inflate the reference time to be the most recent predicted
+ // vsync before the current time.
+ const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t baseTime = now - mReferenceTime;
+ const nsecs_t numOldPeriods = baseTime / mPeriod;
+ mReferenceTime = mReferenceTime + (numOldPeriods)*mPeriod;
+ }
+ mPeriod = period;
if (mTraceDetailedInfo) {
ATRACE_INT64("DispSync:Period", mPeriod);
ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
@@ -428,8 +438,16 @@
void DispSync::resetLocked() {
mPhase = 0;
- mReferenceTime = 0;
+ const size_t lastSampleIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES;
+ // Keep the most recent sample, when we resync to hardware we'll overwrite this
+ // with a more accurate signal
+ if (mResyncSamples[lastSampleIdx] != 0) {
+ mReferenceTime = mResyncSamples[lastSampleIdx];
+ }
mModelUpdated = false;
+ for (size_t i = 0; i < MAX_RESYNC_SAMPLES; i++) {
+ mResyncSamples[i] = 0;
+ }
mNumResyncSamples = 0;
mFirstResyncSample = 0;
mNumResyncSamplesSincePresent = 0;
@@ -529,7 +547,6 @@
Mutex::Autolock lock(mMutex);
mPeriod = period;
mPhase = 0;
- mReferenceTime = 0;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 4a90f10..6f3bd00 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 {
@@ -204,7 +213,7 @@
// These member variables are the state used during the resynchronization
// process to store information about the hardware vsync event times used
// to compute the model.
- nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES];
+ nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES] = {0};
size_t mFirstResyncSample;
size_t mNumResyncSamples;
int mNumResyncSamplesSincePresent;
@@ -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..0063c8a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -28,6 +28,7 @@
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
+#include <system/window.h>
#include <ui/DisplayStatInfo.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -67,9 +68,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 =
@@ -291,31 +297,39 @@
mPrimaryDispSync->dump(result);
}
-void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
- const std::string layerName) {
- // This is V1 logic. It calculates the average FPS based on the timestamp frequency
- // regardless of which layer the timestamp came from.
- // For now, the averages and FPS are recorded in the systrace.
- determineTimestampAverage(isAutoTimestamp, framePresentTime);
-
- // This is V2 logic. It calculates the average and median timestamp difference based on the
- // individual layer history. The results are recorded in the systrace.
- determineLayerTimestampStats(layerName, framePresentTime);
+void Scheduler::addNativeWindowApi(int apiId) {
+ std::lock_guard<std::mutex> lock(mWindowApiHistoryLock);
+ mWindowApiHistory[mApiHistoryCounter] = apiId;
+ mApiHistoryCounter++;
+ mApiHistoryCounter = mApiHistoryCounter % scheduler::ARRAY_SIZE;
}
-void Scheduler::incrementFrameCounter() {
- std::lock_guard<std::mutex> lock(mLayerHistoryLock);
- mLayerHistory.incrementCounter();
+void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
+ fn(*mPrimaryDispSync);
}
-void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) {
+void Scheduler::updateFpsBasedOnNativeWindowApi() {
+ int mode;
+ {
+ std::lock_guard<std::mutex> lock(mWindowApiHistoryLock);
+ mode = scheduler::calculate_mode(mWindowApiHistory);
+ }
+ ATRACE_INT("NativeWindowApiMode", mode);
+
+ if (mode == NATIVE_WINDOW_API_MEDIA) {
+ // TODO(b/127365162): These callback names are not accurate anymore. Update.
+ mediaChangeRefreshRate(MediaFeatureState::MEDIA_PLAYING);
+ ATRACE_INT("DetectedVideo", 1);
+ } else {
+ mediaChangeRefreshRate(MediaFeatureState::MEDIA_OFF);
+ ATRACE_INT("DetectedVideo", 0);
+ }
+}
+
+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) {
@@ -327,85 +341,6 @@
}
}
-void Scheduler::determineLayerTimestampStats(const std::string layerName,
- const nsecs_t framePresentTime) {
- std::vector<int64_t> differencesMs;
- std::string differencesText = "";
- {
- std::lock_guard<std::mutex> lock(mLayerHistoryLock);
- mLayerHistory.insert(layerName, framePresentTime);
-
- // Traverse through the layer history, and determine the differences in present times.
- nsecs_t newestPresentTime = framePresentTime;
- for (int i = 1; i < mLayerHistory.getSize(); i++) {
- std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
- for (auto layer : layers) {
- if (layer.first != layerName) {
- continue;
- }
- int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
- // Dismiss noise.
- if (differenceMs > 10 && differenceMs < 60) {
- differencesMs.push_back(differenceMs);
- }
- IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
- newestPresentTime = layer.second;
- }
- }
- }
- ALOGV("Layer %s timestamp intervals: %s", layerName.c_str(), differencesText.c_str());
-
- if (!differencesMs.empty()) {
- // Mean/Average is a good indicator for when 24fps videos are playing, because the frames
- // come in 33, and 49 ms intervals with occasional 41ms.
- const int64_t meanMs = scheduler::calculate_mean(differencesMs);
- const auto tagMean = "TimestampMean_" + layerName;
- ATRACE_INT(tagMean.c_str(), meanMs);
-
- // Mode and median are good indicators for 30 and 60 fps videos, because the majority of
- // frames come in 16, or 33 ms intervals.
- const auto tagMedian = "TimestampMedian_" + layerName;
- ATRACE_INT(tagMedian.c_str(), scheduler::calculate_median(&differencesMs));
-
- const auto tagMode = "TimestampMode_" + layerName;
- ATRACE_INT(tagMode.c_str(), scheduler::calculate_mode(differencesMs));
- }
-}
-
-void Scheduler::determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime) {
- ATRACE_INT("AutoTimestamp", isAutoTimestamp);
-
- // Video does not have timestamp automatically set, so we discard timestamps that are
- // coming in from other sources for now.
- if (isAutoTimestamp) {
- return;
- }
- int64_t differenceMs = (framePresentTime - mPreviousFrameTimestamp) / 1000000;
- mPreviousFrameTimestamp = framePresentTime;
-
- if (differenceMs < 10 || differenceMs > 100) {
- // Dismiss noise.
- return;
- }
- ATRACE_INT("TimestampDiff", differenceMs);
-
- mTimeDifferences[mCounter % scheduler::ARRAY_SIZE] = differenceMs;
- mCounter++;
- int64_t mean = scheduler::calculate_mean(mTimeDifferences);
- ATRACE_INT("AutoTimestampMean", mean);
-
- // TODO(b/113612090): This are current numbers from trial and error while running videos
- // from YouTube at 24, 30, and 60 fps.
- if (mean > 14 && mean < 18) {
- ATRACE_INT("MediaFPS", 60);
- } else if (mean > 31 && mean < 34) {
- ATRACE_INT("MediaFPS", 30);
- return;
- } else if (mean > 39 && mean < 42) {
- ATRACE_INT("MediaFPS", 24);
- }
-}
-
void Scheduler::resetIdleTimer() {
if (mIdleTimer) {
mIdleTimer->reset();
@@ -413,19 +348,15 @@
}
void Scheduler::resetTimerCallback() {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mResetTimerCallback) {
- mResetTimerCallback();
- ATRACE_INT("ExpiredIdleTimer", 0);
- }
+ // We do not notify the applications about config changes when idle timer is reset.
+ timerChangeRefreshRate(IdleTimerState::RESET);
+ ATRACE_INT("ExpiredIdleTimer", 0);
}
void Scheduler::expiredTimerCallback() {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mExpiredTimerCallback) {
- mExpiredTimerCallback();
- ATRACE_INT("ExpiredIdleTimer", 1);
- }
+ // We do not notify the applications about config changes when idle timer expires.
+ timerChangeRefreshRate(IdleTimerState::EXPIRED);
+ ATRACE_INT("ExpiredIdleTimer", 1);
}
std::string Scheduler::doDump() {
@@ -434,4 +365,46 @@
return stream.str();
}
+void Scheduler::mediaChangeRefreshRate(MediaFeatureState mediaFeatureState) {
+ // Default playback for media is DEFAULT when media is on.
+ RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
+ ConfigEvent configEvent = ConfigEvent::None;
+
+ {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ mCurrentMediaFeatureState = mediaFeatureState;
+ // Only switch to PERFORMANCE if idle timer was reset, when turning
+ // media off. If the timer is IDLE, stay at DEFAULT.
+ if (mediaFeatureState == MediaFeatureState::MEDIA_OFF &&
+ mCurrentIdleTimerState == IdleTimerState::RESET) {
+ refreshRateType = RefreshRateType::PERFORMANCE;
+ }
+ }
+ changeRefreshRate(refreshRateType, configEvent);
+}
+
+void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) {
+ RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
+ ConfigEvent configEvent = ConfigEvent::None;
+
+ {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ mCurrentIdleTimerState = idleTimerState;
+ // Only switch to PERFOMANCE if the idle timer was reset, and media is
+ // not playing. Otherwise, stay at DEFAULT.
+ if (idleTimerState == IdleTimerState::RESET &&
+ mCurrentMediaFeatureState == MediaFeatureState::MEDIA_OFF) {
+ refreshRateType = RefreshRateType::PERFORMANCE;
+ }
+ }
+ changeRefreshRate(refreshRateType, configEvent);
+}
+
+void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mChangeRefreshRateCallback) {
+ mChangeRefreshRateCallback(refreshRateType, configEvent);
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 7f113e7..73896d5 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <functional>
#include <memory>
#include <ui/DisplayStatInfo.h>
@@ -28,6 +29,7 @@
#include "IdleTimer.h"
#include "InjectVSyncSource.h"
#include "LayerHistory.h"
+#include "RefreshRateConfigs.h"
#include "SchedulerUtils.h"
namespace android {
@@ -36,9 +38,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 };
@@ -93,6 +105,9 @@
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
+ // Provides access to the DispSync object for the primary display.
+ void withPrimaryDispSync(std::function<void(DispSync&)> const& fn);
+
sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle);
// Should be called when receiving a hotplug event.
@@ -130,15 +145,16 @@
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
nsecs_t expectedPresentTime();
- // Adds the present time for given layer to the history of present times.
- void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
- 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);
+ // apiId indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
+ // TODO(b/123956502): Remove this call with V1 go/content-fps-detection-in-scheduler.
+ void addNativeWindowApi(int apiId);
+ // Updates FPS based on the most occured request for Native Window API.
+ void updateFpsBasedOnNativeWindowApi();
+ // 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();
@@ -153,17 +169,16 @@
private:
friend class TestableScheduler;
+ // In order to make sure that the features don't override themselves, we need a state machine
+ // to keep track which feature requested the config change.
+ enum class MediaFeatureState { MEDIA_PLAYING, MEDIA_OFF };
+ enum class IdleTimerState { EXPIRED, RESET };
+
// Creates a connection on the given EventThread and forwards the given callbacks.
sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
- // Collects the statistical mean (average) and median between timestamp
- // intervals for each frame for each layer.
- void determineLayerTimestampStats(const std::string layerName, const nsecs_t framePresentTime);
- // Collects the average difference between timestamps for each frame regardless
- // of which layer the timestamp came from.
- void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
// Function that resets the idle timer.
void resetIdleTimer();
// Function that is called when the timer resets.
@@ -172,6 +187,12 @@
void expiredTimerCallback();
// Sets vsync period.
void setVsyncPeriod(const nsecs_t period);
+ // Media feature's function to change the refresh rate.
+ void mediaChangeRefreshRate(MediaFeatureState mediaFeatureState);
+ // Idle timer feature's function to change the refresh rate.
+ void timerChangeRefreshRate(IdleTimerState idleTimerState);
+ // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters.
+ void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent);
// If fences from sync Framework are supported.
const bool mHasSyncFramework;
@@ -205,10 +226,13 @@
std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
size_t mCounter = 0;
- // DetermineLayerTimestampStats is called from BufferQueueLayer::onFrameAvailable which
- // can run on any thread, and cause failure.
- std::mutex mLayerHistoryLock;
- LayerHistory mLayerHistory GUARDED_BY(mLayerHistoryLock);
+ // The following few fields follow native window api bits that come with buffers. If there are
+ // more buffers with NATIVE_WINDOW_API_MEDIA we render at 60Hz, otherwise we render at 90Hz.
+ // There is not dependency on timestamp for V0.
+ // TODO(b/123956502): Remove this when more robust logic for content fps detection is developed.
+ std::mutex mWindowApiHistoryLock;
+ std::array<int, scheduler::ARRAY_SIZE> mWindowApiHistory GUARDED_BY(mWindowApiHistoryLock);
+ int64_t mApiHistoryCounter = 0;
// Timer that records time between requests for next vsync. If the time is higher than a given
// interval, a callback is fired. Set this variable to >0 to use this feature.
@@ -216,8 +240,14 @@
std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
std::mutex mCallbackLock;
- ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
- ExpiredIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
+ ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
+
+ // In order to make sure that the features don't override themselves, we need a state machine
+ // to keep track which feature requested the config change.
+ std::mutex mFeatureStateLock;
+ MediaFeatureState mCurrentMediaFeatureState GUARDED_BY(mFeatureStateLock) =
+ MediaFeatureState::MEDIA_OFF;
+ IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
index 191022d..fb5414f 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
@@ -34,23 +34,5 @@
return v->at(n);
}
-int64_t calculate_mode(const std::vector<int64_t>& v) {
- if (v.empty()) {
- return 0;
- }
-
- // Create a map with all the counts for the indivicual values in the vector.
- std::unordered_map<int64_t, int64_t> counts;
- for (int64_t value : v) {
- counts[value]++;
- }
-
- // Sort the map, and return the number with the highest count. If two numbers have
- // the same count, first one is returned.
- using ValueType = const decltype(counts)::value_type&;
- const auto compareCounts = [](ValueType l, ValueType r) { return l.second <= r.second; };
- return std::max_element(counts.begin(), counts.end(), compareCounts)->first;
-}
-
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index edd23de..9e6e8c7 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -18,6 +18,7 @@
#include <cinttypes>
#include <numeric>
+#include <unordered_map>
#include <vector>
namespace android {
@@ -45,7 +46,24 @@
int64_t calculate_median(std::vector<int64_t>* v);
// Calculates the statistical mode in the vector. Return 0 if the vector is empty.
-int64_t calculate_mode(const std::vector<int64_t>& v);
+template <typename T>
+auto calculate_mode(const T& v) {
+ if (v.empty()) {
+ return 0;
+ }
+
+ // Create a map with all the counts for the indivicual values in the vector.
+ std::unordered_map<int64_t, int> counts;
+ for (int64_t value : v) {
+ counts[value]++;
+ }
+
+ // Sort the map, and return the number with the highest count. If two numbers have
+ // the same count, first one is returned.
+ using ValueType = const decltype(counts)::value_type&;
+ const auto compareCounts = [](ValueType l, ValueType r) { return l.second <= r.second; };
+ return static_cast<int>(std::max_element(counts.begin(), counts.end(), compareCounts)->first);
+}
} // namespace scheduler
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2017f46..c7c0867 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -370,11 +370,13 @@
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);
-
+ mUseSmart90ForVideo = use_smart_90_for_video(false);
property_get("debug.sf.use_smart_90_for_video", value, "0");
- mUseSmart90ForVideo = atoi(value);
+
+ int int_value = atoi(value);
+ if (int_value) {
+ mUseSmart90ForVideo = true;
+ }
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
@@ -563,19 +565,17 @@
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) {
- mPhaseOffsets->setRefreshRateType(
- scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
- setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
+ const auto performanceRefreshRate =
+ mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
+
+ if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
} else {
- mPhaseOffsets->setRefreshRateType(
- scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
- setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
+ setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
}
}));
}
@@ -633,6 +633,10 @@
mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
mSfConnectionHandle.get());
+ mRegionSamplingThread =
+ new RegionSamplingThread(*this, *mScheduler,
+ RegionSamplingThread::EnvironmentTimingTunables());
+
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
renderEngineFeature |= (useColorManagement ?
@@ -699,15 +703,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 +918,7 @@
}
void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
- ConfigEvent event) {
+ Scheduler::ConfigEvent event) {
ATRACE_CALL();
// Lock is acquired by setRefreshRateTo.
@@ -941,7 +942,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) {
@@ -974,8 +975,10 @@
display->setActiveConfig(mUpcomingActiveConfig.configId);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
- if (mUpcomingActiveConfig.event != ConfigEvent::None) {
+ if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
mUpcomingActiveConfig.configId);
}
@@ -983,15 +986,6 @@
bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
- // we may be in the process of changing the active state
- if (mWaitForNextInvalidate) {
- mWaitForNextInvalidate = false;
-
- repaintEverythingForHWC();
- // We do not want to give another frame to HWC while we are transitioning.
- return true;
- }
-
if (mCheckPendingFence) {
if (mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled)) {
@@ -1043,7 +1037,6 @@
getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId);
// we need to submit an empty frame to HWC to start the process
- mWaitForNextInvalidate = true;
mCheckPendingFence = true;
return false;
@@ -1416,17 +1409,11 @@
return mAllowedConfigs[displayId]->isConfigAllowed(config);
}
-void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, ConfigEvent event) {
- ATRACE_CALL();
-
- mPhaseOffsets->setRefreshRateType(refreshRate);
-
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
-
+void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) {
if (mBootStage != BootStage::FINISHED) {
return;
}
+ ATRACE_CALL();
// Don't do any updating if the current fps is the same as the new one.
const auto displayId = getInternalDisplayIdLocked();
@@ -1444,6 +1431,7 @@
return;
}
+ mPhaseOffsets->setRefreshRateType(refreshRate);
setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
}
@@ -1588,23 +1576,28 @@
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
+ bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE &&
+ (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
+ bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
+ bool gpuFrameMissed = mHadClientComposition && frameMissed;
+ ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ ATRACE_INT("HwcFrameMissed", static_cast<int>(hwcFrameMissed));
+ ATRACE_INT("GpuFrameMissed", static_cast<int>(gpuFrameMissed));
+ if (frameMissed) {
+ mFrameMissedCount++;
+ mTimeStats->incrementMissedFrames();
+ }
+
+ if (mUseSmart90ForVideo) {
+ // This call is made each time SF wakes up and creates a new frame. It is part
+ // of video detection feature.
+ mScheduler->updateFpsBasedOnNativeWindowApi();
+ }
+
if (performSetActiveConfig()) {
break;
}
- if (mUse90Hz && mUseSmart90ForVideo) {
- // This call is made each time SF wakes up and creates a new frame. It is part
- // of video detection feature.
- mScheduler->incrementFrameCounter();
- }
- bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE &&
- (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
- bool hwcFrameMissed = !mHadClientComposition && frameMissed;
- if (frameMissed) {
- ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
- mFrameMissedCount++;
- mTimeStats->incrementMissedFrames();
- }
// For now, only propagate backpressure when missing a hwc frame.
if (hwcFrameMissed) {
if (mPropagateBackpressure) {
@@ -1685,11 +1678,14 @@
postComposition();
mHadClientComposition = false;
+ mHadDeviceComposition = false;
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
mHadClientComposition =
mHadClientComposition || getHwComposer().hasClientComposition(displayId);
+ mHadDeviceComposition =
+ mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
}
mVsyncModulator.onRefreshed(mHadClientComposition);
@@ -1758,6 +1754,13 @@
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
}
+ Dataspace targetDataspace = Dataspace::UNKNOWN;
+ if (useColorManagement) {
+ ColorMode colorMode;
+ RenderIntent renderIntent;
+ pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
+ display->setColorMode(colorMode, targetDataspace, renderIntent);
+ }
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
layer->forceClientComposition(displayDevice);
@@ -1789,15 +1792,7 @@
const auto& displayState = display->getState();
layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
- displayDevice->getSupportedPerFrameMetadata());
- }
-
- if (useColorManagement) {
- ColorMode colorMode;
- Dataspace dataSpace;
- RenderIntent renderIntent;
- pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
- display->setColorMode(colorMode, dataSpace, renderIntent);
+ displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
}
}
@@ -2063,8 +2058,8 @@
mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
mTransactionCompletedThread.sendCallbacks();
- if (mLumaSampling) {
- mRegionSamplingThread->sampleNow();
+ if (mLumaSampling && mRegionSamplingThread) {
+ mRegionSamplingThread->notifyNewContent();
}
}
@@ -3888,6 +3883,11 @@
if (what & layer_state_t::eMetadataChanged) {
if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eColorSpaceAgnosticChanged) {
+ if (layer->setColorSpaceAgnostic(s.colorSpaceAgnostic)) {
+ flags |= eTraversalNeeded;
+ }
+ }
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
mTransactionCompletedThread.run();
@@ -4391,7 +4391,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);
@@ -4745,6 +4745,7 @@
*/
result.append("\nScheduler state:\n");
result.append(mScheduler->doDump() + "\n");
+ StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off");
result.append(mRefreshRateStats->doDump() + "\n");
}
@@ -5652,11 +5653,22 @@
// 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)) {
+ 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..1181886 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);
@@ -979,7 +970,12 @@
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
+ // True if in the previous frame at least one layer was composed via the GPU.
bool mHadClientComposition = false;
+ // True if in the previous frame at least one layer was composed via HW Composer.
+ // Note that it is possible for a frame to be composed via both client and device
+ // composition, for example in the case of overlays.
+ bool mHadDeviceComposition = false;
enum class BootStage {
BOOTLOADER,
@@ -1020,9 +1016,6 @@
TransactionCompletedThread mTransactionCompletedThread;
- bool mLumaSampling = true;
- sp<RegionSamplingThread> mRegionSamplingThread = new RegionSamplingThread(*this);
-
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
@@ -1109,7 +1102,6 @@
/* ------------------------------------------------------------------------
* Scheduler
*/
- bool mUse90Hz = false;
bool mUseSmart90ForVideo = false;
std::unique_ptr<Scheduler> mScheduler;
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
@@ -1126,7 +1118,7 @@
struct ActiveConfigInfo {
int configId;
sp<IBinder> displayToken;
- ConfigEvent event;
+ Scheduler::ConfigEvent event;
bool operator!=(const ActiveConfigInfo& other) const {
if (configId != other.configId) {
@@ -1145,10 +1137,12 @@
// below flags are set by main thread only
bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
- bool mWaitForNextInvalidate = false;
bool mCheckPendingFence = false;
/* ------------------------------------------------------------------------ */
+ bool mLumaSampling = true;
+ sp<RegionSamplingThread> mRegionSamplingThread;
+
sp<IInputFlinger> mInputFlinger;
InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index f2881f5..e130511 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -166,11 +166,15 @@
auto tmpuseColorManagement = SurfaceFlingerProperties::use_color_management();
auto tmpHasHDRDisplay = SurfaceFlingerProperties::has_HDR_display();
auto tmpHasWideColorDisplay = SurfaceFlingerProperties::has_wide_color_display();
- if (tmpuseColorManagement.has_value() && tmpHasHDRDisplay.has_value() &&
- tmpHasWideColorDisplay.has_value()) {
- return *tmpuseColorManagement || *tmpHasHDRDisplay || *tmpHasWideColorDisplay;
- }
- return defaultValue;
+
+ auto tmpuseColorManagementVal = tmpuseColorManagement.has_value() ? *tmpuseColorManagement :
+ defaultValue;
+ auto tmpHasHDRDisplayVal = tmpHasHDRDisplay.has_value() ? *tmpHasHDRDisplay :
+ defaultValue;
+ auto tmpHasWideColorDisplayVal = tmpHasWideColorDisplay.has_value() ? *tmpHasWideColorDisplay :
+ defaultValue;
+
+ return tmpuseColorManagementVal || tmpHasHDRDisplayVal || tmpHasWideColorDisplayVal;
}
int64_t default_composition_dataspace(Dataspace defaultValue) {
@@ -205,6 +209,22 @@
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;
+}
+
+bool use_smart_90_for_video(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::use_smart_90_for_video();
+ 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..6f90117 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -55,6 +55,10 @@
int32_t wcg_composition_pixel_format(
android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
+int32_t set_idle_timer_ms(int32_t defaultValue);
+
+bool use_smart_90_for_video(bool 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..fe6dc93 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -286,3 +286,24 @@
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"
+}
+
+# useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the
+# screen refresh rate based on that.
+prop {
+ api_name: "use_smart_90_for_video"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.use_smart_90_for_video"
+}
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
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 79b5ca0..13059e8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -341,6 +341,8 @@
// still be referenced by something despite our best efforts to destroy
// it after each test is done.
mutableDisplays().clear();
+ mutableCurrentState().displays.clear();
+ mutableDrawingState().displays.clear();
mutableEventQueue().reset();
mutableInterceptor().reset();
mutableScheduler().reset();